From 6cff3aaf503860838932fc8ec78659f1ef3d9871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ca=C3=B1izares=20Est=C3=A9vez?= Date: Wed, 16 Nov 2016 10:19:00 +0100 Subject: [PATCH] Basket microservice integration in MVC web, remove session from MVC Site, docker-compose to include Basket.api and Redis image. --- build-images.ps1 | 4 +- docker-compose.yml | 20 +- global.json | 3 +- .../eShopOnContainers.Droid.csproj | 2 +- .../eShopOnContainers.Droid.csproj.bak | 322 ++++++++++++++++++ .../eShopOnContainers.iOS.csproj | 2 +- .../eShopOnContainers.iOS.csproj.bak | 253 ++++++++++++++ .../Controllers/BasketController.cs | 8 +- .../Basket/Basket.API/Model/Basket.cs | 9 +- .../Basket/Basket.API/Model/BasketItem.cs | 9 +- .../Basket.API/Model/IBasketRepository.cs | 4 +- .../Basket.API/Model/RedisBasketRepository.cs | 6 +- .../Basket/Basket.API/docker-compose.yml | 1 + .../Properties/launchSettings.json | 1 - src/Web/WebMVC/AppSettings.cs | 1 + src/Web/WebMVC/Controllers/CartController.cs | 8 +- src/Web/WebMVC/Controllers/OrderController.cs | 23 +- src/Web/WebMVC/Models/Basket.cs | 2 - src/Web/WebMVC/Services/BasketService.cs | 71 ++-- src/Web/WebMVC/Services/CatalogService.cs | 1 - src/Web/WebMVC/Services/IBasketService.cs | 11 +- src/Web/WebMVC/Services/OrderingService.cs | 2 - src/Web/WebMVC/Startup.cs | 15 +- src/Web/WebMVC/ViewComponents/Cart.cs | 6 +- src/Web/WebMVC/ViewComponents/CartList.cs | 4 +- src/Web/WebMVC/Views/Order/Create.cshtml | 2 +- src/Web/WebMVC/appsettings.json | 5 +- src/Web/WebMVC/docker-compose.yml | 19 +- src/Web/WebMVC/wwwroot/css/site.min.css | 2 +- 29 files changed, 726 insertions(+), 90 deletions(-) create mode 100644 src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj.bak create mode 100644 src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj.bak diff --git a/build-images.ps1 b/build-images.ps1 index c11713e1d..a4404c4ed 100644 --- a/build-images.ps1 +++ b/build-images.ps1 @@ -42,13 +42,13 @@ dotnet publish $orderingPathToJson -o $orderingPathToPub #*** Basket service image *** $basketPathToJson = $scriptPath + "\src\Services\Basket\Basket.API\project.json" -Write-Host "basketPathToJson is $orderingPathToJson" -ForegroundColor Yellow +Write-Host "basketPathToJson is $basketPathToJson" -ForegroundColor Yellow $basketPathToPub = $scriptPath + "\pub\basket" Write-Host "basketPathToPub is $basketPathToPub" -ForegroundColor Yellow Write-Host "Restore Dependencies just in case as it is needed to run dotnet publish" -ForegroundColor Blue dotnet restore $basketPathToJson -dotnet build $basketPathToPub +dotnet build $basketPathToJson dotnet publish $basketPathToJson -o $basketPathToPub docker build -t eshop/web $webPathToPub diff --git a/docker-compose.yml b/docker-compose.yml index fd5f51b89..a29fdafb7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,7 @@ services: depends_on: - catalog.api - identity.data + - basket.api catalog.api: image: eshop/catalog.api @@ -39,7 +40,7 @@ services: environment: - ConnectionString=Server=ordering.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word ports: - - "81:80" + - "5102:80" # (Go to Production): For secured/final deployment, remove Ports mapping and # leave just the internal expose section # expose: @@ -60,4 +61,19 @@ services: - SA_PASSWORD=Pass@word - ACCEPT_EULA=Y ports: - - "5433:1433" \ No newline at end of file + - "5433:1433" + + basket.api: + image: eshop/basket.api + environment: + - ConnectionString=basket.data + build: + context: . + dockerfile: Dockerfile + ports: + - "5103:80" + depends_on: + - basket.data + + basket.data: + image: redis \ No newline at end of file diff --git a/global.json b/global.json index c4b6d22ad..bf6ec0487 100644 --- a/global.json +++ b/global.json @@ -2,7 +2,8 @@ "projects": [ "src", "test", - "src/Services/Ordering" + "src/Services/Ordering", + "src/Web" ], "sdk": { diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj index cf581a2b4..39bea90f5 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj @@ -17,7 +17,7 @@ Off Properties\AndroidManifest.xml true - v7.0 + v6.0 armeabi,armeabi-v7a,x86 diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj.bak b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj.bak new file mode 100644 index 000000000..cf581a2b4 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj.bak @@ -0,0 +1,322 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {62DBB163-9CA9-4818-B48B-13233DF37C24} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + eShopOnContainers.Droid + eShopOnContainers.Droid + 512 + true + Resources\Resource.Designer.cs + Off + Properties\AndroidManifest.xml + true + v7.0 + armeabi,armeabi-v7a,x86 + + + + + + + + + True + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + True + None + False + False + False + 1G + Xamarin + False + False + False + False + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + False + SdkOnly + + + + ..\..\packages\Acr.Support.2.1.0\lib\MonoAndroid10\Acr.Support.Android.dll + True + + + ..\..\packages\Acr.UserDialogs.6.3.1\lib\MonoAndroid10\Acr.UserDialogs.dll + True + + + ..\..\packages\Acr.UserDialogs.6.3.1\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll + True + + + ..\..\packages\AndHUD.1.2.0\lib\MonoAndroid\AndHUD.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.2.2.6-pre-232\lib\MonoAndroid10\FFImageLoading.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.Forms.2.2.6-pre-232\lib\MonoAndroid10\FFImageLoading.Forms.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.Forms.2.2.6-pre-232\lib\MonoAndroid10\FFImageLoading.Forms.Droid.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.2.2.6-pre-232\lib\MonoAndroid10\FFImageLoading.Platform.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\FormsViewGroup.dll + True + + + ..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + True + + + ..\..\packages\Unity.4.0.1\lib\portable-net45+wp80+win8+wpa81+MonoAndroid10+MonoTouch10\Microsoft.Practices.Unity.dll + True + + + ..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\ModernHttpClient.dll + True + + + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll + True + + + ..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll + True + + + ..\..\packages\SlideOverKit.2.1.4\lib\MonoAndroid10\SlideOverKit.dll + True + + + ..\..\packages\SlideOverKit.2.1.4\lib\MonoAndroid10\SlideOverKit.Droid.dll + True + + + ..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll + True + + + + + + + + ..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll + True + + + ..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll + True + + + ..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll + True + + + ..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll + True + + + ..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll + True + + + ..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll + True + + + ..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll + True + + + ..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Core.dll + True + + + ..\..\packages\Xamarin.Forms.Pages.2.3.2.118-pre1\lib\MonoAndroid10\Xamarin.Forms.Pages.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Platform.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll + True + + + ..\..\packages\Xamarin.Forms.Theme.Base.1.0.0.43-pre1\lib\MonoAndroid10\Xamarin.Forms.Theme.Android.dll + True + + + ..\..\packages\Xamarin.Forms.Theme.Base.1.0.0.43-pre1\lib\MonoAndroid10\Xamarin.Forms.Theme.Base.dll + True + + + ..\..\packages\Xamarin.Forms.Theme.Light.1.0.0.43-pre1\lib\MonoAndroid10\Xamarin.Forms.Theme.Light.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll + True + + + + + + + + + + + + + + + + Assets\Montserrat-Bold.ttf + + + Assets\Montserrat-Regular.ttf + + + Assets\SourceSansPro-Regular.ttf + + + + + + + Designer + + + Designer + + + Designer + + + + + + + + + + + + + + + + + {65116d1c-145b-4693-abda-f0fb6f425191} + eShopOnContainers.Core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Este proyecto hace referencia a los paquetes NuGet que faltan en este equipo. Use la restauración de paquetes NuGet para descargarlos. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=322105. El archivo que falta es {0}. + + + + + + + + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj index e0c7a17c1..c159b57bc 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj @@ -10,7 +10,7 @@ Exe eShopOnContainers.iOS Resources - eShopOnContainers.iOS + eShopOnContainersiOS diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj.bak b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj.bak new file mode 100644 index 000000000..e0c7a17c1 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.iOS/eShopOnContainers.iOS.csproj.bak @@ -0,0 +1,253 @@ + + + + Debug + iPhoneSimulator + 8.0.30703 + 2.0 + {6EEB23DC-7063-4444-9AF8-90DF24F549C0} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + eShopOnContainers.iOS + Resources + eShopOnContainers.iOS + + + + + true + full + false + bin\iPhoneSimulator\Debug + DEBUG + prompt + 4 + false + i386, x86_64 + None + true + + + none + true + bin\iPhoneSimulator\Release + prompt + 4 + None + i386, x86_64 + false + + + true + full + false + bin\iPhone\Debug + DEBUG + prompt + 4 + false + ARMv7, ARM64 + iPhone Developer + true + Entitlements.plist + + + none + true + bin\iPhone\Release + prompt + 4 + ARMv7, ARM64 + false + iPhone Developer + Entitlements.plist + + + none + True + bin\iPhone\Ad-Hoc + prompt + 4 + False + ARMv7, ARM64 + True + Automatic:AdHoc + iPhone Distribution + Entitlements.plist + + + none + True + bin\iPhone\AppStore + prompt + 4 + False + ARMv7, ARM64 + Automatic:AppStore + iPhone Distribution + Entitlements.plist + + + + + + + Resources\fonts\Montserrat-Bold.ttf + + + Resources\fonts\Montserrat-Regular.ttf + + + Resources\fonts\SourceSansPro-Regular.ttf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\packages\Acr.Support.2.1.0\lib\Xamarin.iOS10\Acr.Support.iOS.dll + True + + + ..\..\packages\Acr.UserDialogs.6.3.1\lib\Xamarin.iOS10\Acr.UserDialogs.dll + True + + + ..\..\packages\Acr.UserDialogs.6.3.1\lib\Xamarin.iOS10\Acr.UserDialogs.Interface.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.2.2.6-pre-232\lib\Xamarin.iOS10\FFImageLoading.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.Forms.2.2.6-pre-232\lib\Xamarin.iOS10\FFImageLoading.Forms.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.Forms.2.2.6-pre-232\lib\Xamarin.iOS10\FFImageLoading.Forms.Touch.dll + True + + + ..\..\packages\Xamarin.FFImageLoading.2.2.6-pre-232\lib\Xamarin.iOS10\FFImageLoading.Platform.dll + True + + + ..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + True + + + ..\..\packages\Unity.4.0.1\lib\portable-net45+wp80+win8+wpa81+MonoAndroid10+MonoTouch10\Microsoft.Practices.Unity.dll + True + + + ..\..\packages\modernhttpclient.2.4.2\lib\Xamarin.iOS10\ModernHttpClient.dll + True + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll + True + + + ..\..\packages\SlideOverKit.2.1.4\lib\Xamarin.iOS10\SlideOverKit.dll + True + + + ..\..\packages\SlideOverKit.2.1.4\lib\Xamarin.iOS10\SlideOverKit.iOS.dll + True + + + ..\..\packages\Splat.1.6.2\lib\Xamarin.iOS10\Splat.dll + True + + + + + + ..\..\packages\WebP.Touch.1.0.2\lib\Xamarin.iOS10\WebP.Touch.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll + True + + + ..\..\packages\Xamarin.Forms.Pages.2.3.2.118-pre1\lib\Xamarin.iOS10\Xamarin.Forms.Pages.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll + True + + + ..\..\packages\Xamarin.Forms.Theme.Base.1.0.0.43-pre1\lib\Xamarin.iOS10\Xamarin.Forms.Theme.Base.dll + True + + + ..\..\packages\Xamarin.Forms.Theme.Base.1.0.0.43-pre1\lib\Xamarin.iOS10\Xamarin.Forms.Theme.iOS.dll + True + + + ..\..\packages\Xamarin.Forms.Theme.Light.1.0.0.43-pre1\lib\Xamarin.iOS10\Xamarin.Forms.Theme.Light.dll + True + + + ..\..\packages\Xamarin.Forms.2.3.2.127\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll + True + + + + + + {65116D1C-145B-4693-ABDA-F0FB6F425191} + eShopOnContainers.Core + + + + + + + + + + + + + + + Este proyecto hace referencia a los paquetes NuGet que faltan en este equipo. Use la restauración de paquetes NuGet para descargarlos. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=322105. El archivo que falta es {0}. + + + + + + + \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs index 456000658..9cd4c017d 100644 --- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs +++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs @@ -22,9 +22,11 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers } // GET api/values/5 [HttpGet("{id}")] - public async Task Get(Guid id) + public async Task Get(string id) { - return await _repository.GetBasket(id); + var basket = await _repository.GetBasket(id); + + return Ok(basket); } // POST api/values @@ -36,7 +38,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers // DELETE api/values/5 [HttpDelete("{id}")] - public void Delete(Guid id) + public void Delete(string id) { _repository.DeleteBasket(id); } diff --git a/src/Services/Basket/Basket.API/Model/Basket.cs b/src/Services/Basket/Basket.API/Model/Basket.cs index 32c10b5b2..d07c710e7 100644 --- a/src/Services/Basket/Basket.API/Model/Basket.cs +++ b/src/Services/Basket/Basket.API/Model/Basket.cs @@ -7,12 +7,13 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { public class CustomerBasket { - public Guid CustomerId { get; private set; } - public IList BasketItems => new List(); + public string BuyerId { get; set; } + public List Items { get; set; } - public CustomerBasket(Guid customerId) + public CustomerBasket(string customerId) { - CustomerId = customerId; + BuyerId = customerId; + Items = new List(); } } } diff --git a/src/Services/Basket/Basket.API/Model/BasketItem.cs b/src/Services/Basket/Basket.API/Model/BasketItem.cs index 75e53a25e..c3f9b6212 100644 --- a/src/Services/Basket/Basket.API/Model/BasketItem.cs +++ b/src/Services/Basket/Basket.API/Model/BasketItem.cs @@ -7,8 +7,11 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { public class BasketItem { - public Guid Id { get; set; } - public decimal Price { get; set; } - public int Count { get; set; } + 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/Services/Basket/Basket.API/Model/IBasketRepository.cs b/src/Services/Basket/Basket.API/Model/IBasketRepository.cs index 4f422cf4d..31f46d1d2 100644 --- a/src/Services/Basket/Basket.API/Model/IBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/IBasketRepository.cs @@ -7,8 +7,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { public interface IBasketRepository { - Task GetBasket(Guid customerId); + Task GetBasket(string customerId); Task UpdateBasket(CustomerBasket basket); - Task DeleteBasket(Guid id); + Task DeleteBasket(string id); } } diff --git a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs index 65a104511..d1ddab1cd 100644 --- a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs @@ -25,13 +25,13 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model } - public async Task DeleteBasket(Guid id) + public async Task DeleteBasket(string id) { var database = await GetDatabase(); return await database.KeyDeleteAsync(id.ToString()); } - public async Task GetBasket(Guid customerId) + public async Task GetBasket(string customerId) { var database = await GetDatabase(); @@ -47,7 +47,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model public async Task UpdateBasket(CustomerBasket basket) { var database = await GetDatabase(); - return await database.StringSetAsync(basket.CustomerId.ToString(), JsonConvert.SerializeObject(basket)); + return await database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket)); } private async Task GetDatabase() diff --git a/src/Services/Basket/Basket.API/docker-compose.yml b/src/Services/Basket/Basket.API/docker-compose.yml index 71a8bd170..b52ae7631 100644 --- a/src/Services/Basket/Basket.API/docker-compose.yml +++ b/src/Services/Basket/Basket.API/docker-compose.yml @@ -12,5 +12,6 @@ services: - "32783:80" depends_on: - basket.data + basket.data: image: redis diff --git a/src/Services/Catalog/Catalog.API/Properties/launchSettings.json b/src/Services/Catalog/Catalog.API/Properties/launchSettings.json index b123021c8..9c71e8a45 100644 --- a/src/Services/Catalog/Catalog.API/Properties/launchSettings.json +++ b/src/Services/Catalog/Catalog.API/Properties/launchSettings.json @@ -17,7 +17,6 @@ "Microsoft.eShopOnContainers.Services.Catalog.API": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:5000/api/values", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/Web/WebMVC/AppSettings.cs b/src/Web/WebMVC/AppSettings.cs index 572a6e5b0..84d5c43b7 100644 --- a/src/Web/WebMVC/AppSettings.cs +++ b/src/Web/WebMVC/AppSettings.cs @@ -10,6 +10,7 @@ namespace Microsoft.eShopOnContainers.WebMVC public Connectionstrings ConnectionStrings { get; set; } public string CatalogUrl { get; set; } public string OrderingUrl { get; set; } + public string BasketUrl { get; set; } public Logging Logging { get; set; } } diff --git a/src/Web/WebMVC/Controllers/CartController.cs b/src/Web/WebMVC/Controllers/CartController.cs index 49d96d8a4..1ed24b398 100644 --- a/src/Web/WebMVC/Controllers/CartController.cs +++ b/src/Web/WebMVC/Controllers/CartController.cs @@ -27,7 +27,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers public async Task Index() { var user = await _userManager.GetUserAsync(HttpContext.User); - var vm = _basketSvc.GetBasket(user); + var vm = await _basketSvc.GetBasket(user); return View(vm); } @@ -37,8 +37,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers public async Task Index(Dictionary quantities, string action) { var user = await _userManager.GetUserAsync(HttpContext.User); - var basket = _basketSvc.SetQuantities(user, quantities); - var vm = _basketSvc.UpdateBasket(basket); + var basket = await _basketSvc.SetQuantities(user, quantities); + var vm = await _basketSvc.UpdateBasket(basket); if (action == "[ Checkout ]") { @@ -62,7 +62,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers UnitPrice = productDetails.Price, ProductId = productDetails.Id }; - _basketSvc.AddItemToBasket(user, product); + await _basketSvc.AddItemToBasket(user, product); return RedirectToAction("Index", "Catalog"); } } diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs index 6ab853368..ca1bc5781 100644 --- a/src/Web/WebMVC/Controllers/OrderController.cs +++ b/src/Web/WebMVC/Controllers/OrderController.cs @@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers { var vm = new CreateOrderViewModel(); var user = await _userManager.GetUserAsync(HttpContext.User); - var basket = _basketSvc.GetBasket(user); + var basket = await _basketSvc.GetBasket(user); var order = _basketSvc.MapBasketToOrder(basket); vm.Order = _orderSvc.MapUserInfoIntoOrder(user, order); @@ -36,21 +36,28 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers } [HttpPost] - public async Task Create(CreateOrderViewModel model) + public async Task Create(CreateOrderViewModel model, Dictionary quantities, string action) { var user = await _userManager.GetUserAsync(HttpContext.User); - var basket = _basketSvc.GetBasket(user); + var basket = await _basketSvc.SetQuantities(user, quantities); + basket = await _basketSvc.UpdateBasket(basket); var order = _basketSvc.MapBasketToOrder(basket); // override if user has changed some shipping address or payment info data. _orderSvc.OverrideUserInfoIntoOrder(model.Order, order); - _orderSvc.CreateOrder(user, order); - //Empty basket for current user. - _basketSvc.CleanBasket(user); + if (action == "[ Place Order ]") + { + _orderSvc.CreateOrder(user, order); - //Redirect to historic list. - return RedirectToAction("Index"); + //Empty basket for current user. + await _basketSvc.CleanBasket(user); + + //Redirect to historic list. + return RedirectToAction("Index"); + } + + return View(model); } public async Task Detail(string orderId) diff --git a/src/Web/WebMVC/Models/Basket.cs b/src/Web/WebMVC/Models/Basket.cs index 09acf1471..62ac09d17 100644 --- a/src/Web/WebMVC/Models/Basket.cs +++ b/src/Web/WebMVC/Models/Basket.cs @@ -11,8 +11,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models { Items = new List(); } - - public string Id; public List Items { get; set; } public string BuyerId { get; set; } diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs index 263f7df11..1b988d2b2 100644 --- a/src/Web/WebMVC/Services/BasketService.cs +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -4,39 +4,54 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.AspNetCore.Http; +using System.Net.Http; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; namespace Microsoft.eShopOnContainers.WebMVC.Services { public class BasketService : IBasketService { - private int _itemsInCart; - private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IOptions _settings; + private HttpClient _apiClient; + private readonly string _remoteServiceBaseUrl; - public BasketService(IHttpContextAccessor httpContextAccessor) + public BasketService(IOptions settings) { - _httpContextAccessor = httpContextAccessor; + _settings = settings; + _remoteServiceBaseUrl = _settings.Value.BasketUrl; } - public int ItemsInCart { get { return _itemsInCart; }} - - public Basket GetBasket(ApplicationUser user) + public async Task GetBasket(ApplicationUser user) { - Basket activeOrder; - activeOrder = _httpContextAccessor.HttpContext.Session.GetObject("MyActiveOrder"); - _itemsInCart = (activeOrder != null) ? activeOrder.Items.Count() : 0; + _apiClient = new HttpClient(); + var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id.ToString()}"; + var dataString = await _apiClient.GetStringAsync(basketUrl); + var response = JsonConvert.DeserializeObject(dataString); + if (response == null) + { + response = new Basket() + { + BuyerId = user.Id + }; + } - return activeOrder; + return response; } - public Basket UpdateBasket(Basket basket) + public async Task UpdateBasket(Basket basket) { - _httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", basket); - return _httpContextAccessor.HttpContext.Session.GetObject("MyActiveOrder"); + _apiClient = new HttpClient(); + var basketUrl = _remoteServiceBaseUrl; + StringContent content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); + var response = await _apiClient.PostAsync(basketUrl, content); + + return basket; } - public Basket SetQuantities(ApplicationUser user, Dictionary quantities) + public async Task SetQuantities(ApplicationUser user, Dictionary quantities) { - var basket = GetBasket(user); + var basket = await GetBasket(user); basket.Items.ForEach(x => { @@ -72,27 +87,31 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services return order; } - public void AddItemToBasket(ApplicationUser user, BasketItem product) + public async Task AddItemToBasket(ApplicationUser user, BasketItem product) { - Basket activeOrder = GetBasket(user); - if (activeOrder == null) + Basket basket = await GetBasket(user); + if (basket == null) { - activeOrder = new Basket() + basket = new Basket() { BuyerId = user.Id, - Id = Guid.NewGuid().ToString(), + //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); + basket.Items.Add(product); + await UpdateBasket(basket); } - public void CleanBasket(ApplicationUser user) + public async Task CleanBasket(ApplicationUser user) { - _httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", new Basket()); + _apiClient = new HttpClient(); + var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id.ToString()}"; + var response = await _apiClient.DeleteAsync(basketUrl); + + //CCE: response status code... + } } } diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs index 7da54f84f..aa7240400 100644 --- a/src/Web/WebMVC/Services/CatalogService.cs +++ b/src/Web/WebMVC/Services/CatalogService.cs @@ -14,7 +14,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { public class CatalogService : ICatalogService { - private readonly List _items; //Fake data while services are ready. private readonly IOptions _settings; private HttpClient _apiClient; private readonly string _remoteServiceBaseUrl; diff --git a/src/Web/WebMVC/Services/IBasketService.cs b/src/Web/WebMVC/Services/IBasketService.cs index 8db9a6171..f022c9f33 100644 --- a/src/Web/WebMVC/Services/IBasketService.cs +++ b/src/Web/WebMVC/Services/IBasketService.cs @@ -8,12 +8,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { public interface IBasketService { - Basket GetBasket(ApplicationUser user); - int ItemsInCart { get; } - void AddItemToBasket(ApplicationUser user, BasketItem product); - Basket UpdateBasket(Basket basket); - Basket SetQuantities(ApplicationUser user, Dictionary quantities); + Task GetBasket(ApplicationUser user); + Task AddItemToBasket(ApplicationUser user, BasketItem product); + Task UpdateBasket(Basket basket); + Task SetQuantities(ApplicationUser user, Dictionary quantities); Order MapBasketToOrder(Basket basket); - void CleanBasket(ApplicationUser user); + Task CleanBasket(ApplicationUser user); } } diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index 276668af3..4940ca97e 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -10,9 +10,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public class OrderingService : IOrderingService { private List _orders; - private int _itemsInCart; - public int ItemsInCart { get { return _itemsInCart; } } //var ordersUrl = _settings.OrderingUrl + "/api/ordering/orders"; //var dataString = await _http.GetStringAsync(ordersUrl); //var items = JsonConvert.DeserializeObject>(dataString); diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 130ea8872..3de0bb928 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -49,10 +49,6 @@ namespace Microsoft.eShopOnContainers.WebMVC 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.AddSingleton(); //CCE: Once services are integrated, a singleton is not needed we can left transient. @@ -82,15 +78,20 @@ namespace Microsoft.eShopOnContainers.WebMVC app.UseIdentity(); - //CCE: Remember to remove this line once Basket mservice is ready. - app.UseSession(); - app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Catalog}/{action=Index}/{id?}"); }); + + var context = (ApplicationDbContext)app + .ApplicationServices.GetService(typeof(ApplicationDbContext)); + + using (context) + { + context.Database.Migrate(); + } } } } diff --git a/src/Web/WebMVC/ViewComponents/Cart.cs b/src/Web/WebMVC/ViewComponents/Cart.cs index 24e551706..70e96e208 100644 --- a/src/Web/WebMVC/ViewComponents/Cart.cs +++ b/src/Web/WebMVC/ViewComponents/Cart.cs @@ -27,10 +27,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents }; return View(vm); } - private Task ItemsInCartAsync(ApplicationUser user) + private async Task ItemsInCartAsync(ApplicationUser user) { - _cartSvc.GetBasket(user); - return Task.Run ( ()=> { return _cartSvc.ItemsInCart; }); + var basket = await _cartSvc.GetBasket(user); + return basket.Items.Count; } } } diff --git a/src/Web/WebMVC/ViewComponents/CartList.cs b/src/Web/WebMVC/ViewComponents/CartList.cs index d0eb4d7d1..6cb29bd6b 100644 --- a/src/Web/WebMVC/ViewComponents/CartList.cs +++ b/src/Web/WebMVC/ViewComponents/CartList.cs @@ -22,9 +22,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents var item = await GetItemsAsync(user); return View(item); } - private Task GetItemsAsync(ApplicationUser user) + private async Task GetItemsAsync(ApplicationUser user) { - return Task.Run(()=> { return _cartSvc.GetBasket(user); }); + return await _cartSvc.GetBasket(user); } } } diff --git a/src/Web/WebMVC/Views/Order/Create.cshtml b/src/Web/WebMVC/Views/Order/Create.cshtml index c85ca5c03..61881f8de 100644 --- a/src/Web/WebMVC/Views/Order/Create.cshtml +++ b/src/Web/WebMVC/Views/Order/Create.cshtml @@ -70,7 +70,7 @@
- +
diff --git a/src/Web/WebMVC/appsettings.json b/src/Web/WebMVC/appsettings.json index a42639356..99a218dfc 100644 --- a/src/Web/WebMVC/appsettings.json +++ b/src/Web/WebMVC/appsettings.json @@ -3,8 +3,9 @@ //"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word" "DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word" }, - "CatalogUrl": "http://localhost:5001", - "OrderingUrl": "http://localhost:2446/", + "CatalogUrl": "http://localhost:5101", + "OrderingUrl": "http://localhost:5102/", + "BasketUrl": "http://localhost:5103", "Logging": { "IncludeScopes": false, "LogLevel": { diff --git a/src/Web/WebMVC/docker-compose.yml b/src/Web/WebMVC/docker-compose.yml index fd5f51b89..22bf093ea 100644 --- a/src/Web/WebMVC/docker-compose.yml +++ b/src/Web/WebMVC/docker-compose.yml @@ -39,7 +39,7 @@ services: environment: - ConnectionString=Server=ordering.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word ports: - - "81:80" + - "5102:80" # (Go to Production): For secured/final deployment, remove Ports mapping and # leave just the internal expose section # expose: @@ -60,4 +60,19 @@ services: - SA_PASSWORD=Pass@word - ACCEPT_EULA=Y ports: - - "5433:1433" \ No newline at end of file + - "5433:1433" + + basket.api: + image: eshop/basket.api + environment: + - ConnectionString=basket.data + build: + context: . + dockerfile: Dockerfile + ports: + - "5103:80" + depends_on: + - basket.data + + basket.data: + image: redis \ No newline at end of file diff --git a/src/Web/WebMVC/wwwroot/css/site.min.css b/src/Web/WebMVC/wwwroot/css/site.min.css index 4fcdc3092..35d022759 100644 --- a/src/Web/WebMVC/wwwroot/css/site.min.css +++ b/src/Web/WebMVC/wwwroot/css/site.min.css @@ -1 +1 @@ -@font-face{font-family:Montserrat;font-weight:400;src:url("/fonts/Montserrat-Regular.eot?") format("eot"),url("/fonts/Montserrat-Regular.woff") format("woff"),url("/fonts/Montserrat-Regular.ttf") format("truetype"),url("/fonts/Montserrat-Regular.svg#Montserrat") format("svg")}@font-face{font-family:Montserrat;font-weight:700;src:url("/fonts/Montserrat-Bold.eot?") format("eot"),url("/fonts/Montserrat-Bold.woff") format("woff"),url("/fonts/Montserrat-Bold.ttf") format("truetype"),url("/fonts/Montserrat-Bold.svg#Montserrat") format("svg")}body{padding-top:80px;font-family:Montserrat,sans-serif}.mt-15{margin-top:15px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.select-filter{background-color:transparent;padding:10px;margin:10px;margin-right:20px;color:#fff;padding-top:20px;padding-bottom:3px;min-width:140px;border-color:#37c7ca;max-height:43px;-webkit-appearance:none}.select-filter option{background-color:#00a69c}select::-ms-expand{display:none}.select-filter-wrapper{z-index:0;display:inline-block;margin-left:-10px}.select-filter-wrapper::before{content:attr(data-name);opacity:.5;z-index:1;text-transform:uppercase;position:absolute;font-size:10px;margin-top:15px;margin-left:21px;color:#fff}.select-filter-arrow{position:absolute;margin-left:130px;margin-top:40px}.btn-brand-small-filter{margin-top:10px;position:absolute;margin-left:15px}.carousel-caption p{font-size:20px;line-height:1.4}.layout-cart-image{height:36px;margin-top:5px}.layout-cart-badge{position:absolute;margin-top:2px;margin-left:14px;background-color:#83d01b;padding:1px;color:#fff;border-radius:50%;width:18px;height:18px;font-size:12px;cursor:pointer}.btn-bracketed:hover:before{display:inline-block;content:"[";padding-right:.5em;color:#7fff00}.btn-bracketed:hover:after{display:inline-block;content:"]";padding-left:.5em;color:#7fff00}.btn-brand{background-color:#83d01b;color:#fff;padding:10px 20px 10px 20px;border-radius:0;border:none;width:255px;display:inline-block;text-align:center;text-transform:uppercase;height:45px;font-size:16px;font-weight:normal}.btn-brand::before{content:'['}.btn-brand::after{content:']'}.btn-brand:hover:before{padding-right:5px}.btn-brand:hover:after{padding-left:5px}.btn-brand-big{width:360px;margin-top:20px}.btn-brand-small{width:120px;font-size:14px}.btn-brand-small::before{content:''}.btn-brand-small::after{content:''}.btn-brand-small:hover:before{content:'';padding:0}.btn-brand-small:hover:after{content:'';padding:0}.btn-brand-dark{background-color:#00a69c}.btn-brand:hover{color:#fff;background-color:#83d01b;text-decoration:none}.btn-brand-dark:hover{background-color:#00a69c}.btn-cart{float:right;margin-top:40px;margin-bottom:40px}.btn-catalog-apply{padding-left:10px;padding-top:13px}.form-label{text-transform:uppercase;font-weight:normal!important;text-align:left;margin-bottom:10px !important;color:#404040}.form-input{border-radius:0;padding:10px;height:45px;width:360px;max-width:360px}.form-input-small{max-width:100px}.form-select{border-radius:0;padding:10px;height:45px;width:150px}.carousel-inner .item img[src$=".svg"]{width:100%}.navbar-inverse{background-color:#fff;border-color:#fff}.navbar-inverse li{margin-top:10px}.btn-login{border:1px solid #00a69c;height:36px!important;margin-right:10px;margin-top:10px;background-color:#fff;color:#00a69c;text-transform:uppercase;max-width:140px;width:140px;padding-top:8px!important}.btn-login{font-weight:normal!important}.btn-login::before{content:'['}.btn-login::after{content:']'}.btn-login:hover:before{content:'[ '}.btn-login:hover:after{content:' ]'}.navbar-inverse li a{height:30px;padding:5px 20px;color:#00a69c !important}.navbar-brand{margin-top:20px;background-image:url(../images/brand.PNG);width:201px;height:44px;margin-left:0 !important}.nav>li>a{color:#fff}.nav>li>a:hover,.nav>li>a:focus{background-color:#00a69c;font-weight:bolder}.container-fluid{padding-left:0;padding-right:0}.home-banner{width:100%;margin-right:0;margin-left:0;background-image:url(../images/main_banner.png);background-size:cover;height:258px;background-position:center}.home-banner-text{margin-top:70px}.home-catalog-container{min-height:400px;margin-bottom:20px}.home-catalog-filter-container{background-color:#00a69c;height:63px}.home-catalog-filter-container li a{padding-top:5px !important}.home-catalog-filter-brands::before{content:'BRAND';color:#fff;font-size:x-small;opacity:.5;margin:10px 0 0 15px}.home-catalog-filter-types::before{content:'TYPES';color:#fff;font-size:x-small;opacity:.5;margin:10px 0 0 15px}.home-catalog-item{margin-top:10px;margin-bottom:10px}.home-catalog-item-image{width:100%;object-fit:cover;text-align:center}.home-catalog-item-image-addCart{background-color:#83d01b;color:#fff;display:inline-block;height:43px;padding:10px 20px 10px 20px;font-weight:bold;text-align:center;margin-top:10px;margin-left:60px;margin-right:60px;font-size:16px;font-weight:normal}.home-catalog-item-image-addCart:hover{color:#fff;text-decoration:none}.home-catalog-item-image:hover:after{cursor:pointer}.home-catalog-item-title{text-align:center;text-transform:uppercase;font-weight:300;font-size:16px;margin-top:20px}.home-catalog-item-price{text-align:center;font-weight:900;font-size:28px}.home-catalog-item-price::before{content:'$'}.home-catalog-noResults{text-align:center;margin-top:100px}.container .nav .navbar-nav .col-sm-6 ::before{content:'BRAND'}.validation-summary-errors li{list-style:none}footer{background-color:#000;height:150px;vertical-align:middle}footer .brand{margin-top:25px;background-image:url(../images/brand_dark.PNG);max-width:231px;height:52px;margin-left:0 !important}footer .text{text-align:right;width:100%;height:100%;color:#83d01b;margin-top:10px}.text{color:#83d01b}.text:hover{color:#83d01b}form .col-md-4{text-align:right}.brand-header-block{background-color:#00a69c;height:63px}.brand-header-block li{list-style:none;display:inline;opacity:.5;margin-top:25px;margin-left:10px;float:right;cursor:pointer;color:#fff}.brand-header-block li a{color:#fff}.brand-header-block li a:hover{text-decoration:none}.brand-header-block .active{opacity:1}.brand-header-block .active::before{content:'[ ';color:#adff2f}.brand-header-block .active::after{content:' ]';color:#adff2f}.brand-header-back{float:left!important;margin-top:20px!important;text-transform:uppercase}.account-login-container{min-height:70vh;text-align:center}.account-register-container{min-height:70vh;text-align:center !important;align-content:center}.cart-index-container{min-height:70vh;padding-top:40px;margin-bottom:30px}.order-create-container{min-height:70vh;padding-top:40px;margin-bottom:30px;padding-left: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;text-align:left}.cart-product-image{max-width:210px}.cart-section-total{margin-bottom:5px;margin-left:175px;text-align:left}.cart-product-column input{width:70px;text-align:center}.cart-refresh-button{margin-top:0;background-image:url('../images/refresh.svg');color:#fff;font-size:8px;width:40px;margin-top:10px;height:40px;background-color:transparent;border:none}.cart-refresh-button:hover{background-color:transparent}.input-validation-error{border:1px solid #fb0d0d}.text-danger{color:#fb0d0d;font-size:12px}.cart{border:none !important}.form-horizontal h4{margin-top:30px}.form-control:focus{border-color:#83d01b}.form-input-center{margin:auto}.order-index-container{min-height:70vh;padding-top:40px;margin-bottom:30px}.order-index-container .table tbody tr{border-bottom:none}.order-index-container .table tbody tr td{border-top:none;padding-top:10px;padding-bottom:10px}.order-index-container .table tbody tr:nth-child(even){background-color:#f5f5f5}.order-create-section-title{margin-left:-15px;text-transform:uppercase}.order-create-section-items{margin-left:-45px;width:102%}.order-detail-button a{color:#83d01b}.order-detail-container{min-height:70vh;padding-top:40px;margin-bottom:30px}.order-detail-container .table tbody tr:first-child td{border-top:none}.order-detail-container .table tr{border-bottom:none}.order-detail-section{margin-top:50px}.order-detail-container .table{margin-left:-7px}.order-section-total{margin-bottom:5px;margin-left:40px;text-align:left}.fr{float:right!important}.down-arrow{background-image:url('../images/arrow-down.png');height:7px;width:10px;display:inline-block;margin-left:20px}.logout-icon{background-image:url('../images/logout.PNG');display:inline-block;height:19px;width:19px;margin-left:15px}.myorders-icon{background-image:url('../images/my_orders.PNG');display:inline-block;height:20px;width:20px;margin-left:15px}.login-user{position:absolute!important;top:30px;right:65px;cursor:pointer}.login-user-dropdown{position:relative;display:inline-block}.login-user-dropdown-content{display:none;position:absolute;background-color:#fff;min-width:160px;box-shadow:0 8px 16px 0 rgba(0,0,0,.2);left:100px}.login-user-dropdown-content a{color:#000;padding:12px 16px;text-decoration:none;display:block;text-align:right;text-transform:uppercase}.login-user:hover .login-user-dropdown-content{display:block}.login-user-dropdown-content a:hover{color:#83d01b}.es-header{min-height:80px!important}.es-pager-bottom{margin-top:40px}.es-pager-top{margin-bottom:20px;margin-top:20px}.es-pager-top ul{list-style:none}.es-pager-bottom ul{list-style:none}.page-item{cursor:pointer}.next{position:absolute;right:0;top:0}.previous{position:absolute;left:0;top:0}.is-disabled{cursor:not-allowed;opacity:.5;pointer-events:none}.table tr{border-bottom:1px solid #ddd}.table th{text-transform:uppercase}@media screen and (max-width:767px){.carousel-caption{display:none}footer .text{text-align:left;margin-top:-15px}}@media screen and (max-width:415px){.btn-brand-small-filter{width:40px;padding:10px 10px 10px 10px;font-size:10px}.btn-brand-small-filter::before{content:'->';color:#fff}} \ No newline at end of file +@font-face{font-family:Montserrat;font-weight:400;src:url("/fonts/Montserrat-Regular.eot?") format("eot"),url("/fonts/Montserrat-Regular.woff") format("woff"),url("/fonts/Montserrat-Regular.ttf") format("truetype"),url("/fonts/Montserrat-Regular.svg#Montserrat") format("svg")}@font-face{font-family:Montserrat;font-weight:700;src:url("/fonts/Montserrat-Bold.eot?") format("eot"),url("/fonts/Montserrat-Bold.woff") format("woff"),url("/fonts/Montserrat-Bold.ttf") format("truetype"),url("/fonts/Montserrat-Bold.svg#Montserrat") format("svg")}body{padding-top:80px;font-family:Montserrat,sans-serif;min-width:480px}.mt-15{margin-top:15px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.select-filter{background-color:transparent;padding:10px;margin:10px;margin-right:20px;color:#fff;padding-top:20px;padding-bottom:3px;min-width:140px;border-color:#37c7ca;max-height:43px;-webkit-appearance:none}.select-filter option{background-color:#00a69c}select::-ms-expand{display:none}.select-filter-wrapper{z-index:0;display:inline-block;margin-left:-10px}.select-filter-wrapper::before{content:attr(data-name);opacity:.5;z-index:1;text-transform:uppercase;position:absolute;font-size:10px;margin-top:15px;margin-left:21px;color:#fff}.select-filter-arrow{position:absolute;margin-left:130px;margin-top:40px}.btn-brand-small-filter{margin-top:10px;position:absolute;margin-left:15px}.carousel-caption p{font-size:20px;line-height:1.4}.layout-cart-image{height:36px;margin-top:5px}.layout-cart-badge{position:absolute;margin-top:2px;margin-left:14px;background-color:#83d01b;padding:1px;color:#fff;border-radius:50%;width:18px;height:18px;font-size:12px;cursor:pointer}.btn-bracketed:hover:before{display:inline-block;content:"[";padding-right:.5em;color:#7fff00}.btn-bracketed:hover:after{display:inline-block;content:"]";padding-left:.5em;color:#7fff00}.btn-brand{background-color:#83d01b;color:#fff;padding:10px 20px 10px 20px;border-radius:0;border:none;width:255px;display:inline-block;text-align:center;text-transform:uppercase;height:45px;font-size:16px;font-weight:normal}.btn-brand::before{content:'['}.btn-brand::after{content:']'}.btn-brand:hover:before{padding-right:5px}.btn-brand:hover:after{padding-left:5px}.btn-brand-big{width:360px;margin-top:20px}.btn-brand-small{width:45px}.btn-brand-small::before{content:''}.btn-brand-small::after{content:''}.btn-brand-small:hover:before{content:'';padding:0}.btn-brand-small:hover:after{content:'';padding:0}.btn-brand-dark{background-color:#00a69c}.btn-brand:hover{color:#fff;background-color:#83d01b;text-decoration:none}.btn-brand-dark:hover{background-color:#00a69c}.btn-cart{float:right;margin-top:40px;margin-bottom:40px}.btn-catalog-apply{padding:0}.form-label{text-transform:uppercase;font-weight:normal!important;text-align:left;margin-bottom:10px !important;color:#404040}.form-input{border-radius:0;padding:10px;height:45px}.form-input-small{max-width:100px!important}.form-select{border-radius:0;padding:10px;height:45px;width:150px}.carousel-inner .item img[src$=".svg"]{width:100%}.navbar-inverse{background-color:#fff;border-color:#fff}.btn-login{border:1px solid #00a69c;height:36px!important;margin-right:10px;margin-top:10px;background-color:#fff;color:#00a69c;text-transform:uppercase;max-width:140px;width:140px;padding-top:8px!important}.btn-login{font-weight:normal!important}.btn-login::before{content:'['}.btn-login::after{content:']'}.btn-login:hover:before{content:'[ '}.btn-login:hover:after{content:' ]'}.navbar-inverse li a{height:30px;padding:5px 20px;color:#00a69c !important}.navbar-brand{margin-top:20px;background-image:url(../images/brand.PNG);width:201px;height:44px;margin-left:0 !important}.nav>li>a{color:#fff}.nav>li>a:hover,.nav>li>a:focus{background-color:#00a69c;font-weight:bolder}.container-fluid{padding-left:0;padding-right:0}.home-banner{width:100%;margin-right:0;margin-left:0;background-image:url(../images/main_banner.png);background-size:cover;height:258px;background-position:center}.home-banner-text{margin-top:70px}.home-catalog-container{min-height:400px;margin-bottom:20px}.home-catalog-filter-container{background-color:#00a69c;height:63px}.home-catalog-filter-container li a{padding-top:5px !important}.home-catalog-filter-brands::before{content:'BRAND';color:#fff;font-size:x-small;opacity:.5;margin:10px 0 0 15px}.home-catalog-filter-types::before{content:'TYPES';color:#fff;font-size:x-small;opacity:.5;margin:10px 0 0 15px}.home-catalog-item{margin-top:10px;margin-bottom:10px}.home-catalog-item-image{width:100%;object-fit:cover;text-align:center}.home-catalog-item-image-addCart{background-color:#83d01b;color:#fff;display:inline-block;height:43px;padding:10px 20px 10px 20px;font-weight:bold;text-align:center;margin-top:10px;margin-left:60px;margin-right:60px;font-size:16px;font-weight:normal}.home-catalog-item-image-addCart:hover{color:#fff;text-decoration:none}.home-catalog-item-image:hover:after{cursor:pointer}.home-catalog-item-title{text-align:center;text-transform:uppercase;font-weight:300;font-size:16px;margin-top:20px}.home-catalog-item-price{text-align:center;font-weight:900;font-size:28px}.home-catalog-item-price::before{content:'$'}.home-catalog-noResults{text-align:center;margin-top:100px}.container .nav .navbar-nav .col-sm-6 ::before{content:'BRAND'}.validation-summary-errors li{list-style:none}footer{background-color:#000;height:150px;vertical-align:middle}footer .brand{margin-top:25px;background-image:url(../images/brand_dark.PNG);max-width:231px;height:52px;margin-left:0 !important}footer .text{text-align:right;width:100%;height:100%;color:#83d01b;margin-top:10px}.text{color:#83d01b}.text:hover{color:#83d01b}form .col-md-4{text-align:right}.brand-header-block{background-color:#00a69c;height:63px}.brand-header-block li{list-style:none;display:inline;opacity:.5;margin-top:25px;margin-left:10px;float:right;cursor:pointer;color:#fff}.brand-header-block li a{color:#fff}.brand-header-block li a:hover{text-decoration:none}.brand-header-block .active{opacity:1}.brand-header-block .active::before{content:'[ ';color:#adff2f}.brand-header-block .active::after{content:' ]';color:#adff2f}.brand-header-back{float:left!important;margin-top:20px!important;text-transform:uppercase}.account-login-container{min-height:70vh;text-align:center;padding-top:40px}.account-register-container{min-height:70vh;text-align:center !important;align-content:center}.cart-index-container{min-height:70vh;padding-top:40px;margin-bottom:30px;min-width:992px}.register-container{min-height:70vh;padding-top:40px;margin-bottom:30px;padding-left:30px}.order-create-container{min-height:70vh;padding-top:40px;margin-bottom:30px;padding-left:30px;min-width:995px}.cart-product-column{max-width:120px;text-transform:uppercase;vertical-align:middle!important}.order-create-container .cart-product-column{max-width:130px}.cart-product-column-name{width:220px}.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;text-align:left}.cart-product-image{max-width:210px}.cart-section-total{margin-bottom:5px;margin-left:175px;text-align:left}.cart-product-column input{width:70px;text-align:center}.cart-refresh-button{margin-top:0;background-image:url('../images/refresh.svg');color:#fff;font-size:8px;width:40px;height:40px;background-color:transparent;border:none;margin-top:25px;margin-left:15px}.cart-refresh-button:hover{background-color:transparent}.cart-totals{border-bottom:none!important}.input-validation-error{border:1px solid #fb0d0d}.text-danger{color:#fb0d0d;font-size:12px}.cart{border:none !important}.form-horizontal h4{margin-top:30px}.form-horizontal .form-group{margin-right:0!important}.form-control:focus{border-color:#83d01b}.form-input-center{margin:auto}.order-index-container{min-height:70vh;padding-top:40px;margin-bottom:30px}.order-index-container .table tbody tr{border-bottom:none}.order-index-container .table tbody tr td{border-top:none;padding-top:10px;padding-bottom:10px}.order-index-container .table tbody tr:nth-child(even){background-color:#f5f5f5}.order-create-section-title{margin-left:-15px;text-transform:uppercase}.order-create-section-items{margin-left:-45px;width:102%}.order-detail-button a{color:#83d01b}.order-detail-container{min-height:70vh;padding-top:40px;margin-bottom:30px}.order-detail-container .table tbody tr:first-child td{border-top:none}.order-detail-container .table tr{border-bottom:none}.order-detail-section{margin-top:50px}.order-detail-container .table{margin-left:-7px}.order-section-total{margin-bottom:5px;margin-left:40px;text-align:left}.fr{float:right!important}.down-arrow{background-image:url('../images/arrow-down.png');height:7px;width:10px;display:inline-block;margin-left:20px}.logout-icon{background-image:url('../images/logout.PNG');display:inline-block;height:19px;width:19px;margin-left:15px}.myorders-icon{background-image:url('../images/my_orders.PNG');display:inline-block;height:20px;width:20px;margin-left:15px}.login-user{position:absolute!important;top:30px;right:65px;cursor:pointer}.login-user-dropdown{position:relative;display:inline-block}.login-user-dropdown-content{display:none;position:absolute;background-color:#fff;min-width:160px;box-shadow:0 8px 16px 0 rgba(0,0,0,.2);right:0}.login-user-dropdown-content a{color:#000;padding:12px 16px;text-decoration:none;display:block;text-align:right;text-transform:uppercase}.login-user:hover .login-user-dropdown-content{display:block}.down-arrow:hover>.login-user-dropdown-content{display:block}.login-user-dropdown-content a:hover{color:#83d01b}.es-header{min-height:80px!important}.es-pager-bottom{margin-top:40px}.es-pager-top{margin-bottom:20px;margin-top:20px}.es-pager-top ul{list-style:none}.es-pager-bottom ul{list-style:none}.page-item{cursor:pointer}.next{position:absolute;right:15px;top:0}.previous{position:absolute;left:0;top:0}.is-disabled{cursor:not-allowed;opacity:.5;pointer-events:none}.table tr{border-bottom:1px solid #ddd}.table th{text-transform:uppercase}.navbar-nav{margin-top:10px;margin-bottom:7.5px;margin-right:-10px;float:right}@media screen and (max-width:1195px){.cart-product-column-name{display:none}}@media screen and (max-width:767px){.carousel-caption{display:none}footer .text{text-align:left;margin-top:-15px}.cart-product-column-brand{display:none}}@media screen and (min-width:992px){.form-input{width:360px;max-width:360px}} \ No newline at end of file