@ -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<ApplicationUser> _userManager; | |||
private readonly IBasketService _basketSvc; | |||
private readonly ICatalogService _catalogSvc; | |||
public CartController(IBasketService basketSvc, ICatalogService catalogSvc, UserManager<ApplicationUser> userManager) | |||
{ | |||
_userManager = userManager; | |||
_basketSvc = basketSvc; | |||
_catalogSvc = catalogSvc; | |||
} | |||
public async Task<IActionResult> Index() | |||
{ | |||
var user = await _userManager.GetUserAsync(HttpContext.User); | |||
var vm = _basketSvc.GetBasket(user); | |||
return View(vm); | |||
} | |||
[HttpPost] | |||
public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action) | |||
{ | |||
var user = await _userManager.GetUserAsync(HttpContext.User); | |||
var basket = _basketSvc.SetQuantities(user, quantities); | |||
var vm = _basketSvc.UpdateBasket(basket); | |||
if (action == "[ Checkout ]") | |||
{ | |||
var order = _basketSvc.MapBasketToOrder(basket); | |||
return RedirectToAction("Create", "Order"); | |||
} | |||
return View(vm); | |||
} | |||
public async Task<IActionResult> 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.AddItemToBasket(user, product); | |||
return RedirectToAction("Index", "Catalog"); | |||
} | |||
} | |||
} |
@ -0,0 +1,55 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using System.Net.Http; | |||
using Microsoft.AspNetCore.Mvc; | |||
using Microsoft.eShopOnContainers.WebMVC.Models; | |||
using Microsoft.Extensions.Options; | |||
using Newtonsoft.Json; | |||
using Microsoft.eShopOnContainers.WebMVC.Services; | |||
using Microsoft.eShopOnContainers.WebMVC.Models.CatalogViewModels; | |||
using BikeSharing_Private_Web_Site.Services.Pagination; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Controllers | |||
{ | |||
public class CatalogController : Controller | |||
{ | |||
private ICatalogService _catalogSvc; | |||
public CatalogController(ICatalogService catalogSvc) | |||
{ | |||
_catalogSvc = catalogSvc; | |||
} | |||
public async Task<IActionResult> Index(int? BrandFilterApplied, int? TypesFilterApplied, int? page) | |||
{ | |||
var vm = new IndexViewModel() | |||
{ | |||
CatalogItems = await _catalogSvc.GetCatalogItems(6 * (page ?? 0), 6), | |||
Brands = _catalogSvc.GetBrands(), | |||
Types = _catalogSvc.GetTypes(), | |||
BrandFilterApplied = BrandFilterApplied ?? 0, | |||
TypesFilterApplied = TypesFilterApplied ?? 0, | |||
PaginationInfo = new PaginationInfo() | |||
{ | |||
ActualPage = page ?? 0, | |||
ItemsPerPage = 6, | |||
TotalItems = _catalogSvc.TotalItems, | |||
TotalPages = int.Parse(Math.Round(((decimal)_catalogSvc.TotalItems / 6), MidpointRounding.AwayFromZero).ToString()) | |||
} | |||
}; | |||
vm.PaginationInfo.Next = (vm.PaginationInfo.ActualPage == vm.PaginationInfo.TotalPages - 1) ? "is-disabled" : ""; | |||
vm.PaginationInfo.Previous = (vm.PaginationInfo.ActualPage == 0) ? "is-disabled" : ""; | |||
return View(vm); | |||
} | |||
public IActionResult Error() | |||
{ | |||
return View(); | |||
} | |||
} | |||
} | |||
@ -1,55 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using System.Net.Http; | |||
using Microsoft.AspNetCore.Mvc; | |||
using Microsoft.eShopOnContainers.WebMVC.Models; | |||
using Microsoft.Extensions.Options; | |||
using Newtonsoft.Json; | |||
using Microsoft.eShopOnContainers.WebMVC.Services; | |||
using Microsoft.eShopOnContainers.WebMVC.Models.HomeViewModels; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Controllers | |||
{ | |||
public class HomeController : Controller | |||
{ | |||
private HttpClient _http; | |||
private AppSettings _settings; | |||
private ICatalogService _catalogSvc; | |||
public HomeController(IOptions<AppSettings> options, ICatalogService catalogSvc) | |||
{ | |||
_http = new HttpClient(); | |||
_settings = options.Value; | |||
_catalogSvc = catalogSvc; | |||
} | |||
public async Task<IActionResult> Index() | |||
{ | |||
//var dataString = await _http.GetStringAsync(_settings.CatalogUrl); | |||
//var items = JsonConvert.DeserializeObject<List<CatalogItem>>(dataString); | |||
//items.AddRange(items); | |||
var items = await _catalogSvc.GetCatalogItems(); | |||
var vm = new IndexViewModel() | |||
{ | |||
CatalogItems = items | |||
}; | |||
return View(vm); | |||
} | |||
public async Task<IActionResult> Orders() | |||
{ | |||
ViewData["Message"] = "Orders page."; | |||
var ordersUrl = _settings.OrderingUrl + "/api/ordering/orders"; | |||
var dataString = await _http.GetStringAsync(ordersUrl); | |||
var items = JsonConvert.DeserializeObject<List<Order>>(dataString); | |||
return View(items); | |||
} | |||
public IActionResult Error() | |||
{ | |||
return View(); | |||
} | |||
} | |||
} |
@ -1,395 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.AspNetCore.Authorization; | |||
using Microsoft.AspNetCore.Identity; | |||
using Microsoft.AspNetCore.Mvc; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.eShopOnContainers.WebMVC.Models; | |||
using Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels; | |||
using Microsoft.eShopOnContainers.WebMVC.Services; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Controllers | |||
{ | |||
[Authorize] | |||
public class ManageController : Controller | |||
{ | |||
private readonly UserManager<ApplicationUser> _userManager; | |||
private readonly SignInManager<ApplicationUser> _signInManager; | |||
private readonly IEmailSender _emailSender; | |||
private readonly ISmsSender _smsSender; | |||
private readonly ILogger _logger; | |||
public ManageController( | |||
UserManager<ApplicationUser> userManager, | |||
SignInManager<ApplicationUser> signInManager, | |||
IEmailSender emailSender, | |||
ISmsSender smsSender, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
_userManager = userManager; | |||
_signInManager = signInManager; | |||
_emailSender = emailSender; | |||
_smsSender = smsSender; | |||
_logger = loggerFactory.CreateLogger<ManageController>(); | |||
} | |||
// | |||
// GET: /Manage/Index | |||
[HttpGet] | |||
public async Task<IActionResult> Index(ManageMessageId? message = null) | |||
{ | |||
ViewData["StatusMessage"] = | |||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." | |||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." | |||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." | |||
: message == ManageMessageId.Error ? "An error has occurred." | |||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." | |||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." | |||
: ""; | |||
var user = await GetCurrentUserAsync(); | |||
if (user == null) | |||
{ | |||
return View("Error"); | |||
} | |||
var model = new IndexViewModel | |||
{ | |||
HasPassword = await _userManager.HasPasswordAsync(user), | |||
PhoneNumber = await _userManager.GetPhoneNumberAsync(user), | |||
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), | |||
Logins = await _userManager.GetLoginsAsync(user), | |||
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user), | |||
User = user | |||
}; | |||
return View(model); | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> Index(IndexViewModel model) | |||
{ | |||
if (!ModelState.IsValid) | |||
{ | |||
return View(model); | |||
} | |||
var user = await _userManager.GetUserAsync(HttpContext.User); | |||
user.CardHolderName = model.User.CardHolderName; | |||
user.CardNumber = model.User.CardNumber; | |||
//user.CardType = model.User.CardType; | |||
user.City = model.User.City; | |||
user.Country = model.User.Country; | |||
user.Expiration = model.User.Expiration; | |||
user.State = model.User.State; | |||
user.Street = model.User.Street; | |||
user.ZipCode = model.User.ZipCode; | |||
var result = await _userManager.UpdateAsync(user); | |||
if (result.Succeeded) | |||
{ | |||
_logger.LogInformation(99, "User changed his address and payment method information."); | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ProfileUpdated }); | |||
} | |||
AddErrors(result); | |||
return View(model); | |||
} | |||
// | |||
// POST: /Manage/RemoveLogin | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account) | |||
{ | |||
ManageMessageId? message = ManageMessageId.Error; | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); | |||
if (result.Succeeded) | |||
{ | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
message = ManageMessageId.RemoveLoginSuccess; | |||
} | |||
} | |||
return RedirectToAction(nameof(ManageLogins), new { Message = message }); | |||
} | |||
// | |||
// GET: /Manage/AddPhoneNumber | |||
public IActionResult AddPhoneNumber() | |||
{ | |||
return View(); | |||
} | |||
// | |||
// POST: /Manage/AddPhoneNumber | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model) | |||
{ | |||
if (!ModelState.IsValid) | |||
{ | |||
return View(model); | |||
} | |||
// Generate the token and send it | |||
var user = await GetCurrentUserAsync(); | |||
if (user == null) | |||
{ | |||
return View("Error"); | |||
} | |||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); | |||
await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code); | |||
return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber }); | |||
} | |||
// | |||
// POST: /Manage/EnableTwoFactorAuthentication | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> EnableTwoFactorAuthentication() | |||
{ | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
await _userManager.SetTwoFactorEnabledAsync(user, true); | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
_logger.LogInformation(1, "User enabled two-factor authentication."); | |||
} | |||
return RedirectToAction(nameof(Index), "Manage"); | |||
} | |||
// | |||
// POST: /Manage/DisableTwoFactorAuthentication | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> DisableTwoFactorAuthentication() | |||
{ | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
await _userManager.SetTwoFactorEnabledAsync(user, false); | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
_logger.LogInformation(2, "User disabled two-factor authentication."); | |||
} | |||
return RedirectToAction(nameof(Index), "Manage"); | |||
} | |||
// | |||
// GET: /Manage/VerifyPhoneNumber | |||
[HttpGet] | |||
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber) | |||
{ | |||
var user = await GetCurrentUserAsync(); | |||
if (user == null) | |||
{ | |||
return View("Error"); | |||
} | |||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber); | |||
// Send an SMS to verify the phone number | |||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); | |||
} | |||
// | |||
// POST: /Manage/VerifyPhoneNumber | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model) | |||
{ | |||
if (!ModelState.IsValid) | |||
{ | |||
return View(model); | |||
} | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); | |||
if (result.Succeeded) | |||
{ | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); | |||
} | |||
} | |||
// If we got this far, something failed, redisplay the form | |||
ModelState.AddModelError(string.Empty, "Failed to verify phone number"); | |||
return View(model); | |||
} | |||
// | |||
// POST: /Manage/RemovePhoneNumber | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> RemovePhoneNumber() | |||
{ | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
var result = await _userManager.SetPhoneNumberAsync(user, null); | |||
if (result.Succeeded) | |||
{ | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); | |||
} | |||
} | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); | |||
} | |||
// | |||
// GET: /Manage/ChangePassword | |||
[HttpGet] | |||
public IActionResult ChangePassword() | |||
{ | |||
return View(); | |||
} | |||
// | |||
// POST: /Manage/ChangePassword | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model) | |||
{ | |||
if (!ModelState.IsValid) | |||
{ | |||
return View(model); | |||
} | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); | |||
if (result.Succeeded) | |||
{ | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
_logger.LogInformation(3, "User changed their password successfully."); | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); | |||
} | |||
AddErrors(result); | |||
return View(model); | |||
} | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); | |||
} | |||
// | |||
// GET: /Manage/SetPassword | |||
[HttpGet] | |||
public IActionResult SetPassword() | |||
{ | |||
return View(); | |||
} | |||
// | |||
// POST: /Manage/SetPassword | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public async Task<IActionResult> SetPassword(SetPasswordViewModel model) | |||
{ | |||
if (!ModelState.IsValid) | |||
{ | |||
return View(model); | |||
} | |||
var user = await GetCurrentUserAsync(); | |||
if (user != null) | |||
{ | |||
var result = await _userManager.AddPasswordAsync(user, model.NewPassword); | |||
if (result.Succeeded) | |||
{ | |||
await _signInManager.SignInAsync(user, isPersistent: false); | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); | |||
} | |||
AddErrors(result); | |||
return View(model); | |||
} | |||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); | |||
} | |||
//GET: /Manage/ManageLogins | |||
[HttpGet] | |||
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null) | |||
{ | |||
ViewData["StatusMessage"] = | |||
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." | |||
: message == ManageMessageId.AddLoginSuccess ? "The external login was added." | |||
: message == ManageMessageId.Error ? "An error has occurred." | |||
: ""; | |||
var user = await GetCurrentUserAsync(); | |||
if (user == null) | |||
{ | |||
return View("Error"); | |||
} | |||
var userLogins = await _userManager.GetLoginsAsync(user); | |||
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); | |||
ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; | |||
return View(new ManageLoginsViewModel | |||
{ | |||
CurrentLogins = userLogins, | |||
OtherLogins = otherLogins | |||
}); | |||
} | |||
// | |||
// POST: /Manage/LinkLogin | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public IActionResult LinkLogin(string provider) | |||
{ | |||
// Request a redirect to the external login provider to link a login for the current user | |||
var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); | |||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); | |||
return Challenge(properties, provider); | |||
} | |||
// | |||
// GET: /Manage/LinkLoginCallback | |||
[HttpGet] | |||
public async Task<ActionResult> LinkLoginCallback() | |||
{ | |||
var user = await GetCurrentUserAsync(); | |||
if (user == null) | |||
{ | |||
return View("Error"); | |||
} | |||
var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); | |||
if (info == null) | |||
{ | |||
return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); | |||
} | |||
var result = await _userManager.AddLoginAsync(user, info); | |||
var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; | |||
return RedirectToAction(nameof(ManageLogins), new { Message = message }); | |||
} | |||
#region Helpers | |||
private void AddErrors(IdentityResult result) | |||
{ | |||
foreach (var error in result.Errors) | |||
{ | |||
ModelState.AddModelError(string.Empty, error.Description); | |||
} | |||
} | |||
public enum ManageMessageId | |||
{ | |||
AddPhoneSuccess, | |||
AddLoginSuccess, | |||
ChangePasswordSuccess, | |||
SetTwoFactorSuccess, | |||
SetPasswordSuccess, | |||
RemoveLoginSuccess, | |||
RemovePhoneSuccess, | |||
Error, | |||
ProfileUpdated | |||
} | |||
private Task<ApplicationUser> GetCurrentUserAsync() | |||
{ | |||
return _userManager.GetUserAsync(HttpContext.User); | |||
} | |||
#endregion | |||
} | |||
} |
@ -0,0 +1,23 @@ | |||
using Microsoft.AspNetCore.Http; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
public static class SessionExtensions | |||
{ | |||
public static void SetObject(this ISession session, string key, object value) | |||
{ | |||
session.SetString(key, JsonConvert.SerializeObject(value)); | |||
} | |||
public static T GetObject<T>(this ISession session, string key) | |||
{ | |||
var value = session.GetString(key); | |||
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value); | |||
} | |||
} | |||
@ -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<BasketItem>(); | |||
} | |||
public string Id; | |||
public List<BasketItem> Items { get; set; } | |||
public string BuyerId { get; set; } | |||
public decimal Total() | |||
{ | |||
return Items.Sum(x => x.UnitPrice * x.Quantity); | |||
} | |||
} | |||
} |
@ -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; } | |||
} | |||
} |
@ -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; } | |||
} | |||
} |
@ -0,0 +1,17 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
namespace BikeSharing_Private_Web_Site.Services.Pagination | |||
{ | |||
public class PaginationInfo | |||
{ | |||
public int TotalItems { get; set; } | |||
public int ItemsPerPage { get; set; } | |||
public int ActualPage { get; set; } | |||
public int TotalPages { get; set; } | |||
public string Previous { get; set; } | |||
public string Next { get; set; } | |||
} | |||
} |
@ -0,0 +1,98 @@ | |||
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 Basket GetBasket(ApplicationUser user) | |||
{ | |||
Basket activeOrder; | |||
activeOrder = _httpContextAccessor.HttpContext.Session.GetObject<Basket>("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<Basket>("MyActiveOrder"); | |||
} | |||
public Basket SetQuantities(ApplicationUser user, Dictionary<string, int> 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; | |||
} | |||
public void AddItemToBasket(ApplicationUser user, BasketItem product) | |||
{ | |||
Basket activeOrder = GetBasket(user); | |||
if (activeOrder == null) | |||
{ | |||
activeOrder = new Basket() | |||
{ | |||
BuyerId = user.Id, | |||
Id = Guid.NewGuid().ToString(), | |||
Items = new List<Models.BasketItem>() | |||
}; | |||
} | |||
activeOrder.Items.Add(product); | |||
//CCE: lacks and httpcall to persist in the real back.end service. | |||
_httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", activeOrder); | |||
} | |||
public void CleanBasket(ApplicationUser user) | |||
{ | |||
_httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", new Basket()); | |||
} | |||
} | |||
} |
@ -1,41 +0,0 @@ | |||
using System; | |||
using System.Threading.Tasks; | |||
using Microsoft.eShopOnContainers.WebMVC.Models; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Services | |||
{ | |||
public class CartService : ICartService | |||
{ | |||
Order _order; | |||
public CartService() | |||
{ | |||
_order = new Order(); | |||
_order.OrderItems = new System.Collections.Generic.List<OrderItem>(); | |||
_order.OrderItems.Add(new OrderItem() | |||
{ | |||
ProductName = "Cart product" | |||
}); | |||
} | |||
public void AddItemToOrder(CatalogItem item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public int GetItemCountFromOrderInProgress() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public Task<Order> GetOrderInProgress() | |||
{ | |||
return Task.Run(() => { return _order; }); | |||
} | |||
public void RemoveItemFromOrder(Guid itemIdentifier) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
} | |||
} |
@ -0,0 +1,19 @@ | |||
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 AddItemToBasket(ApplicationUser user, BasketItem product); | |||
Basket UpdateBasket(Basket basket); | |||
Basket SetQuantities(ApplicationUser user, Dictionary<string, int> quantities); | |||
Order MapBasketToOrder(Basket basket); | |||
void CleanBasket(ApplicationUser user); | |||
} | |||
} |
@ -1,16 +0,0 @@ | |||
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 ICartService | |||
{ | |||
void AddItemToOrder(CatalogItem item); | |||
void RemoveItemFromOrder(Guid itemIdentifier); | |||
int GetItemCountFromOrderInProgress(); | |||
Task<Order> GetOrderInProgress(); | |||
} | |||
} |
@ -1,12 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Services | |||
{ | |||
public interface IEmailSender | |||
{ | |||
Task SendEmailAsync(string email, string subject, string message); | |||
} | |||
} |
@ -1,12 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Services | |||
{ | |||
public interface ISmsSender | |||
{ | |||
Task SendSmsAsync(string number, string message); | |||
} | |||
} |
@ -1,25 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
namespace Microsoft.eShopOnContainers.WebMVC.Services | |||
{ | |||
// This class is used by the application to send Email and SMS | |||
// when you turn on two-factor authentication in ASP.NET Identity. | |||
// For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713 | |||
public class AuthMessageSender : IEmailSender, ISmsSender | |||
{ | |||
public Task SendEmailAsync(string email, string subject, string message) | |||
{ | |||
// Plug in your email service here to send an email. | |||
return Task.FromResult(0); | |||
} | |||
public Task SendSmsAsync(string number, string message) | |||
{ | |||
// Plug in your SMS service here to send a text message. | |||
return Task.FromResult(0); | |||
} | |||
} | |||
} |
@ -0,0 +1,30 @@ | |||
using Microsoft.AspNetCore.Mvc; | |||
using Microsoft.eShopOnContainers.WebMVC.Models; | |||
using Microsoft.eShopOnContainers.WebMVC.Services; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents | |||
{ | |||
public class CartList : ViewComponent | |||
{ | |||
private readonly IBasketService _cartSvc; | |||
public CartList(IBasketService cartSvc) | |||
{ | |||
_cartSvc = cartSvc; | |||
} | |||
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user) | |||
{ | |||
var item = await GetItemsAsync(user); | |||
return View(item); | |||
} | |||
private Task<Basket> GetItemsAsync(ApplicationUser user) | |||
{ | |||
return Task.Run(()=> { return _cartSvc.GetBasket(user); }); | |||
} | |||
} | |||
} |
@ -1,10 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Confirm Email"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<div> | |||
<p> | |||
Thank you for confirming your email. Please <a asp-controller="Account" asp-action="Login">Click here to Log in</a>. | |||
</p> | |||
</div> |
@ -1,35 +0,0 @@ | |||
@model ExternalLoginConfirmationViewModel | |||
@{ | |||
ViewData["Title"] = "Register"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<h3>Associate your @ViewData["LoginProvider"] account.</h3> | |||
<form asp-controller="Account" asp-action="ExternalLoginConfirmation" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal"> | |||
<h4>Association Form</h4> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<p class="text-info"> | |||
You've successfully authenticated with <strong>@ViewData["LoginProvider"]</strong>. | |||
Please enter an email address for this site below and click the Register button to finish | |||
logging in. | |||
</p> | |||
<div class="form-group"> | |||
<label asp-for="Email" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="Email" class="form-control" /> | |||
<span asp-validation-for="Email" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Register</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,8 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Login Failure"; | |||
} | |||
<header> | |||
<h2>@ViewData["Title"].</h2> | |||
<p class="text-danger">Unsuccessful login with service.</p> | |||
</header> |
@ -1,31 +0,0 @@ | |||
@model ForgotPasswordViewModel | |||
@{ | |||
ViewData["Title"] = "Forgot your password?"; | |||
} | |||
<h2>@ViewData["Title"]</h2> | |||
<p> | |||
For more information on how to enable reset password please see this <a href="http://go.microsoft.com/fwlink/?LinkID=532713">article</a>. | |||
</p> | |||
@*<form asp-controller="Account" asp-action="ForgotPassword" method="post" class="form-horizontal"> | |||
<h4>Enter your email.</h4> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<div class="form-group"> | |||
<label asp-for="Email" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="Email" class="form-control" /> | |||
<span asp-validation-for="Email" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Submit</button> | |||
</div> | |||
</div> | |||
</form>*@ | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,8 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Forgot Password Confirmation"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<p> | |||
Please check your email to reset your password. | |||
</p> |
@ -1,8 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Locked out"; | |||
} | |||
<header> | |||
<h1 class="text-danger">Locked out.</h1> | |||
<p class="text-danger">This account has been locked out, please try again later.</p> | |||
</header> |
@ -1,43 +0,0 @@ | |||
@model ResetPasswordViewModel | |||
@{ | |||
ViewData["Title"] = "Reset password"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<form asp-controller="Account" asp-action="ResetPassword" method="post" class="form-horizontal"> | |||
<h4>Reset your password.</h4> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<input asp-for="Code" type="hidden" /> | |||
<div class="form-group"> | |||
<label asp-for="Email" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="Email" class="form-control" /> | |||
<span asp-validation-for="Email" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label asp-for="Password" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="Password" class="form-control" /> | |||
<span asp-validation-for="Password" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="ConfirmPassword" class="form-control" /> | |||
<span asp-validation-for="ConfirmPassword" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Reset</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,8 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Reset password confirmation"; | |||
} | |||
<h1>@ViewData["Title"].</h1> | |||
<p> | |||
Your password has been reset. Please <a asp-controller="Account" asp-action="Login">Click here to log in</a>. | |||
</p> |
@ -1,21 +0,0 @@ | |||
@model SendCodeViewModel | |||
@{ | |||
ViewData["Title"] = "Send Verification Code"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<form asp-controller="Account" asp-action="SendCode" asp-route-returnurl="@Model.ReturnUrl" method="post" class="form-horizontal"> | |||
<input asp-for="RememberMe" type="hidden" /> | |||
<div class="row"> | |||
<div class="col-md-8"> | |||
Select Two-Factor Authentication Provider: | |||
<select asp-for="SelectedProvider" asp-items="Model.Providers"></select> | |||
<button type="submit" class="btn btn-default">Submit</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,38 +0,0 @@ | |||
@model VerifyCodeViewModel | |||
@{ | |||
ViewData["Title"] = "Verify"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<form asp-controller="Account" asp-action="VerifyCode" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal"> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<input asp-for="Provider" type="hidden" /> | |||
<input asp-for="RememberMe" type="hidden" /> | |||
<h4>@ViewData["Status"]</h4> | |||
<hr /> | |||
<div class="form-group"> | |||
<label asp-for="Code" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="Code" class="form-control" /> | |||
<span asp-validation-for="Code" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<div class="checkbox"> | |||
<input asp-for="RememberBrowser" /> | |||
<label asp-for="RememberBrowser"></label> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Submit</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -0,0 +1,25 @@ | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.Basket | |||
@inject UserManager<ApplicationUser> UserManager | |||
@{ | |||
ViewData["Title"] = "My Cart"; | |||
} | |||
<div class="brand-header-block"> | |||
<ul class="container"> | |||
<li class="brand-header-back"><a asp-area="" asp-controller="Catalog" asp-action="Index">Back to list</a></li> | |||
</ul> | |||
</div> | |||
<form method="post" id="cartForm"> | |||
<div class="container cart-index-container"> | |||
<div class="row"> | |||
@await Component.InvokeAsync("CartList", new { user = await UserManager.GetUserAsync(User) }) | |||
<div class="col-md-offset-8 col-md-4"> | |||
<input type="submit" | |||
class="btn btn-default btn-brand btn-cart" | |||
value="[ Checkout ]" name="action" /> | |||
</div> | |||
</div> | |||
</div> | |||
</form> |
@ -0,0 +1,110 @@ | |||
@{ | |||
ViewData["Title"] = "Catalog"; | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.CatalogViewModels.IndexViewModel | |||
} | |||
<div class="container-fluid"> | |||
<div class="row home-banner"> | |||
<div class="container home-banner-text"><img src="~/images/main_banner_text.png" /></div> | |||
</div> | |||
<div class="home-catalog-filter-container"> | |||
<div class="container"> | |||
<form asp-action="Index" asp-controller="Catalog" method="post"> | |||
<div data-name="brand" class="select-filter-wrapper"> | |||
<img src="~/images/arrow-down.png" class="select-filter-arrow" /> | |||
<select asp-for="@Model.BrandFilterApplied" asp-items="@Model.Brands" class="select-filter"></select> | |||
</div> | |||
<div data-name="type" class="select-filter-wrapper"> | |||
<img src="~/images/arrow-down.png" class="select-filter-arrow" /> | |||
<select asp-for="@Model.TypesFilterApplied" asp-items="@Model.Types" class="select-filter"></select> | |||
</div> | |||
<input type="submit" class="btn-brand btn-brand-small btn-brand-small-filter btn-catalog-apply" value="APPLY" /> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="container home-catalog-container"> | |||
<div class="container es-pager-top"> | |||
<div class="row"> | |||
<div class="col-xs-4"> | |||
<nav> | |||
<ul> | |||
<li class="page-item"> | |||
<a class="text previous @Model.PaginationInfo.Previous" id="Previous" | |||
href="@Url.Action("Index","Catalog", new { page = Model.PaginationInfo.ActualPage -1 })" | |||
aria-label="Previous"> | |||
<span>Previous</span> | |||
</a> | |||
</li> | |||
</ul> | |||
</nav> | |||
</div> | |||
<div class="col-xs-4 u-align-center"><span>Showing @Html.DisplayFor(modelItem => modelItem.PaginationInfo.ItemsPerPage) of @Html.DisplayFor(modelItem => modelItem.PaginationInfo.TotalItems) products - Page @(Model.PaginationInfo.ActualPage + 1) of @Html.DisplayFor(x => x.PaginationInfo.TotalPages)</span></div> | |||
<div class="col-xs-4"> | |||
<nav> | |||
<ul> | |||
<li class="page-item"> | |||
<a class="text next @Model.PaginationInfo.Next" id="Next" | |||
href="@Url.Action("Index","Catalog", new { page = Model.PaginationInfo.ActualPage + 1 })" | |||
aria-label="Next"> | |||
<span>Next</span> | |||
</a> | |||
</li> | |||
</ul> | |||
</nav> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
@foreach (var catalogItem in Model.CatalogItems) | |||
{ | |||
<div class="col-sm-4 home-catalog-item"> | |||
<form asp-controller="Cart" asp-action="AddToCart" asp-route-productId="@catalogItem.Id"> | |||
<div class="home-catalog-item-image"> | |||
<img src="@catalogItem.PictureUrl" /> | |||
<input type="submit" value="[ ADD TO CART ]" class="btn-brand home-catalog-item-image-addCart" /> | |||
</div> | |||
<div class="home-catalog-item-title"> | |||
<span>@catalogItem.Name</span> | |||
</div> | |||
<div class="home-catalog-item-price"> | |||
<span>@catalogItem.Price.ToString("N2")</span> | |||
</div> | |||
</form> | |||
</div> | |||
} | |||
</div> | |||
<div class="container es-pager-bottom"> | |||
<div class="row"> | |||
<div class="col-xs-4"> | |||
<nav> | |||
<ul> | |||
<li class="page-item"> | |||
<a class="text previous @Model.PaginationInfo.Previous" id="Previous" | |||
href="@Url.Action("Index","Catalog", new { page = Model.PaginationInfo.ActualPage + -1 })" | |||
aria-label="Previous"> | |||
<span>Previous</span> | |||
</a> | |||
</li> | |||
</ul> | |||
</nav> | |||
</div> | |||
<div class="col-xs-4 u-align-center"><span>Showing @Html.DisplayFor(modelItem => modelItem.PaginationInfo.ItemsPerPage) of @Html.DisplayFor(modelItem => modelItem.PaginationInfo.TotalItems) products - Page @(Model.PaginationInfo.ActualPage + 1) of @Html.DisplayFor(x => x.PaginationInfo.TotalPages)</span></div> | |||
<div class="col-xs-4"> | |||
<nav> | |||
<ul> | |||
<li class="page-item"> | |||
<a class="text next @Model.PaginationInfo.Next" id="Next" | |||
href="@Url.Action("Index","Catalog", new { page = Model.PaginationInfo.ActualPage + 1 })" | |||
aria-label="Next"> | |||
<span>Next</span> | |||
</a> | |||
</li> | |||
</ul> | |||
</nav> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@ -1,67 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Home Page"; | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.HomeViewModels.IndexViewModel | |||
} | |||
<div class="container-fluid"> | |||
<div class="row home-banner"> | |||
<div class="container home-banner-text"><img src="~/images/main_banner_text.png" /></div> | |||
</div> | |||
<div class="home-catalog-filter-container"> | |||
<div class="container"> | |||
@*<ul class="nav navbar-nav col-sm-6 home-catalog-filter-brands"> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Index" class="btn-bracketed">ALL</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="About" class="btn-bracketed">AZURE</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Contact" class="btn-bracketed">.NET</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Orders" class="btn-bracketed">LOREM</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Orders" class="btn-bracketed">IPSUM</a></li> | |||
</ul> | |||
<ul class="nav navbar-nav col-sm-6 home-catalog-filter-types"> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Index" class="btn-bracketed">ALL</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="About" class="btn-bracketed">T-SHIRT</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Contact" class="btn-bracketed">STICKER</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Orders" class="btn-bracketed">MUGS</a></li> | |||
<li><a asp-area="" asp-controller="Home" asp-action="Orders" class="btn-bracketed">SWEATSHIRT</a></li> | |||
</ul>*@ | |||
<div data-name="brand" class="select-filter-wrapper"> | |||
<img src="~/images/arrow-down.png" class="select-filter-arrow" /> | |||
<select asp-for="BrandFilterApplied" asp-items="Model.Brands" class="select-filter" > | |||
<option>ALL</option> | |||
</select> | |||
</div> | |||
<div data-name="type" class="select-filter-wrapper"> | |||
<img src="~/images/arrow-down.png" class="select-filter-arrow" /> | |||
<select asp-for="TypesFilterApplied" asp-items="Model.Types" class="select-filter"> | |||
<option>ALL</option> | |||
</select> | |||
</div> | |||
<a asp-area="" asp-controller="Home" asp-action="About" class="btn-brand btn-brand-small btn-brand-small-filter"> | |||
APPLY | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="container home-catalog-container"> | |||
<div class="row"> | |||
@foreach (var catalogItem in Model.CatalogItems) | |||
{ | |||
<div class="col-sm-4 home-catalog-item"> | |||
<div class="home-catalog-item-image" > | |||
<img src="~/images/product_temp.PNG" /> | |||
<a asp-area="" asp-controller="Home" asp-action="About" class="btn-brand home-catalog-item-image-addCart"> | |||
ADD TO CART | |||
</a> | |||
</div> | |||
<div class="home-catalog-item-title"> | |||
<span>@catalogItem.Name</span> | |||
</div> | |||
<div class="home-catalog-item-price"> | |||
<span>@catalogItem.Price.ToString("N2")</span> | |||
</div> | |||
</div> | |||
} | |||
</div> | |||
</div> | |||
@ -1,50 +0,0 @@ | |||
@{ | |||
ViewData["Title"] = "Orders"; | |||
@model IEnumerable<Order> | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<h3>@ViewData["Message"]</h3> | |||
@foreach (var order in Model) | |||
{ | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
<h3 class="panel-title"> | |||
<strong>Order Number:</strong> @order.OrderNumber | |||
</h3> | |||
</div> | |||
<div class="panel-body"> | |||
<strong>BuyerId: </strong> @order.BuyerId <br /> | |||
<strong>OrderDate: </strong> @order.OrderDate <br /> | |||
<strong>SequenceNumber: </strong> @order.SequenceNumber <br /> | |||
</div> | |||
<div class="panel-body"> | |||
<address> | |||
<strong>Street: </strong> @order.ShippingAddress.Street <br /> | |||
<strong>City: </strong> @order.ShippingAddress.City <br /> | |||
<strong>State: </strong> @order.ShippingAddress.State <br /> | |||
<strong>StateCode: </strong> @order.ShippingAddress.StateCode <br /> | |||
<strong>Country: </strong> @order.ShippingAddress.Country <br /> | |||
<strong>CountryCode: </strong> @order.ShippingAddress.CountryCode <br /> | |||
<strong>ZipCode: </strong> @order.ShippingAddress.ZipCode <br /> | |||
<strong>Latitude: </strong> @order.ShippingAddress.Latitude <br /> | |||
<strong>Longitude: </strong> @order.ShippingAddress.Longitude <br /> | |||
</address> | |||
</div> | |||
<div class="panel-body"> | |||
@foreach (var orderItem in order.OrderItems) | |||
{ | |||
<address> | |||
<strong>ProductId: </strong> @orderItem.ProductId <br /> | |||
<strong>ProductName: </strong> @orderItem.ProductName <br /> | |||
<strong>Price: </strong> @orderItem.UnitPrice <br /> | |||
<strong>Quantity: </strong> @orderItem.Quantity <br /> | |||
<strong>Discount: </strong> @orderItem.Discount <br /> | |||
</address> | |||
} | |||
</div> | |||
</div> | |||
} | |||
@ -1,27 +0,0 @@ | |||
@model AddPhoneNumberViewModel | |||
@{ | |||
ViewData["Title"] = "Add Phone Number"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<form asp-controller="Manage" asp-action="AddPhoneNumber" method="post" class="form-horizontal"> | |||
<h4>Add a phone number.</h4> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<div class="form-group"> | |||
<label asp-for="PhoneNumber" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="PhoneNumber" class="form-control" /> | |||
<span asp-validation-for="PhoneNumber" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Send verification code</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,42 +0,0 @@ | |||
@model ChangePasswordViewModel | |||
@{ | |||
ViewData["Title"] = "Change Password"; | |||
} | |||
<form asp-controller="Manage" asp-action="ChangePassword" method="post" class="form-horizontal"> | |||
<h4>Change Password Form</h4> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<div class="form-group"> | |||
<label asp-for="OldPassword" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="OldPassword" class="form-control" /> | |||
<span asp-validation-for="OldPassword" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label asp-for="NewPassword" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="NewPassword" class="form-control" /> | |||
<span asp-validation-for="NewPassword" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="ConfirmPassword" class="form-control" /> | |||
<span asp-validation-for="ConfirmPassword" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Change password</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,100 +0,0 @@ | |||
@model IndexViewModel | |||
@{ | |||
ViewData["Title"] = "Manage your account"; | |||
} | |||
@*<h2>@ViewData["Title"].</h2>*@ | |||
<p class="text-success">@ViewData["StatusMessage"]</p> | |||
<div class="brand-header-block"> | |||
<ul class="container"> | |||
<li class="brand-header-back"><a asp-area="" asp-controller="Home" asp-action="Index">Back to list</a></li> | |||
</ul> | |||
</div> | |||
<div class="container cart-index-container"> | |||
<form asp-controller="Manage" asp-action="Index" method="post" class="form-horizontal"> | |||
<div class="form-group"> | |||
<div class="col-md-offset-8 col-md-4"> | |||
<button type="submit" class="btn btn-default btn-brand">[ Save ]</button> | |||
</div> | |||
</div> | |||
<h4 class="order-create-section-title">SHIPPING ADDRESS</h4> | |||
<div class="form-horizontal row"> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.Street" class="control-label form-label">ADDRESS</label> | |||
<input asp-for="User.Street" class="form-control form-input" /> | |||
<span asp-validation-for="User.Street" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.City" class="control-label form-label"></label> | |||
<input asp-for="User.City" class="form-control form-input" /> | |||
<span asp-validation-for="User.City" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.State" class="control-label form-label"></label> | |||
<input asp-for="User.State" class="form-control form-input" /> | |||
<span asp-validation-for="User.State" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.Country" class="control-label form-label"></label> | |||
<input asp-for="User.Country" class="form-control form-input" /> | |||
<span asp-validation-for="User.Country" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.ZipCode" class="control-label form-label"></label> | |||
<input asp-for="User.ZipCode" class="form-control form-input form-input-small" /> | |||
<span asp-validation-for="User.ZipCode" class="text-danger" /> | |||
</div> | |||
</div> | |||
<br /><br /> | |||
<div class="order-create-section-payment"> | |||
<h4 class="order-create-section-title">PAYMENT METHOD</h4> | |||
<div class="form-horizontal row"> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.CardNumber" class="control-label form-label">Card Number</label> | |||
<input asp-for="User.CardNumber" class="form-control form-input" /> | |||
<span asp-validation-for="User.CardNumber" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.CardHolderName" class="control-label form-label">Cardholder Name</label> | |||
<input asp-for="User.CardHolderName" class="form-control form-input" /> | |||
<span asp-validation-for="User.CardHolderName" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-3"> | |||
<label asp-for="User.Expiration" class="control-label form-label">Expiration Date</label> | |||
<input asp-for="User.Expiration" placeholder="MM/YY" class="form-control form-input form-input-small" /> | |||
<span asp-validation-for="User.Expiration" class="text-danger" /> | |||
</div> | |||
<div class="form-group col-sm-3"> | |||
<label asp-for="User.SecurityNumber" class="control-label form-label">Security Code</label> | |||
<input asp-for="User.SecurityNumber" class="form-control form-input form-input-small" /> | |||
<span asp-validation-for="User.SecurityNumber" class="text-danger" /> | |||
</div> | |||
</div> | |||
</div> | |||
<br /><br /> | |||
<h4 class="order-create-section-title">Change your account settings</h4> | |||
<div class="form-horizontal row"> | |||
<div class="form-group col-sm-6"> | |||
<label asp-for="User.Street" class="control-label form-label">PASSWORD</label> | |||
<br /> | |||
@if (Model.HasPassword) | |||
{ | |||
<a asp-controller="Manage" asp-action="ChangePassword" class="text">Change</a> | |||
} | |||
else | |||
{ | |||
<a asp-controller="Manage" asp-action="SetPassword" class="text">Create</a> | |||
} | |||
</div> | |||
</div> | |||
<br /><br /> | |||
<div class="form-group"> | |||
<div class="col-md-offset-8 col-md-4"> | |||
<button type="submit" class="btn btn-default btn-brand">[ Save ]</button> | |||
</div> | |||
</div> | |||
<br /><br /> | |||
</form> | |||
</div> | |||
@ -1,54 +0,0 @@ | |||
@model ManageLoginsViewModel | |||
@using Microsoft.AspNetCore.Http.Authentication | |||
@{ | |||
ViewData["Title"] = "Manage your external logins"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<p class="text-success">@ViewData["StatusMessage"]</p> | |||
@if (Model.CurrentLogins.Count > 0) | |||
{ | |||
<h4>Registered Logins</h4> | |||
<table class="table"> | |||
<tbody> | |||
@for (var index = 0; index < Model.CurrentLogins.Count; index++) | |||
{ | |||
<tr> | |||
<td>@Model.CurrentLogins[index].LoginProvider</td> | |||
<td> | |||
@if ((bool)ViewData["ShowRemoveButton"]) | |||
{ | |||
<form asp-controller="Manage" asp-action="RemoveLogin" method="post" class="form-horizontal"> | |||
<div> | |||
<input asp-for="@Model.CurrentLogins[index].LoginProvider" name="LoginProvider" type="hidden" /> | |||
<input asp-for="@Model.CurrentLogins[index].ProviderKey" name="ProviderKey" type="hidden" /> | |||
<input type="submit" class="btn btn-default" value="Remove" title="Remove this @Model.CurrentLogins[index].LoginProvider login from your account" /> | |||
</div> | |||
</form> | |||
} | |||
else | |||
{ | |||
@: | |||
} | |||
</td> | |||
</tr> | |||
} | |||
</tbody> | |||
</table> | |||
} | |||
@if (Model.OtherLogins.Count > 0) | |||
{ | |||
<h4>Add another service to log in.</h4> | |||
<hr /> | |||
<form asp-controller="Manage" asp-action="LinkLogin" method="post" class="form-horizontal"> | |||
<div id="socialLoginList"> | |||
<p> | |||
@foreach (var provider in Model.OtherLogins) | |||
{ | |||
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button> | |||
} | |||
</p> | |||
</div> | |||
</form> | |||
} |
@ -1,38 +0,0 @@ | |||
@model SetPasswordViewModel | |||
@{ | |||
ViewData["Title"] = "Set Password"; | |||
} | |||
<p class="text-info"> | |||
You do not have a local username/password for this site. Add a local | |||
account so you can log in without an external login. | |||
</p> | |||
<form asp-controller="Manage" asp-action="SetPassword" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal"> | |||
<h4>Set your password</h4> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<div class="form-group"> | |||
<label asp-for="NewPassword" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="NewPassword" class="form-control" /> | |||
<span asp-validation-for="NewPassword" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="ConfirmPassword" class="form-control" /> | |||
<span asp-validation-for="ConfirmPassword" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Set password</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,30 +0,0 @@ | |||
@model VerifyPhoneNumberViewModel | |||
@{ | |||
ViewData["Title"] = "Verify Phone Number"; | |||
} | |||
<h2>@ViewData["Title"].</h2> | |||
<form asp-controller="Manage" asp-action="VerifyPhoneNumber" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal"> | |||
<input asp-for="PhoneNumber" type="hidden" /> | |||
<h4>Add a phone number.</h4> | |||
<h5>@ViewData["Status"]</h5> | |||
<hr /> | |||
<div asp-validation-summary="All" class="text-danger"></div> | |||
<div class="form-group"> | |||
<label asp-for="Code" class="col-md-2 control-label"></label> | |||
<div class="col-md-10"> | |||
<input asp-for="Code" class="form-control" /> | |||
<span asp-validation-for="Code" class="text-danger"></span> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-10"> | |||
<button type="submit" class="btn btn-default">Submit</button> | |||
</div> | |||
</div> | |||
</form> | |||
@section Scripts { | |||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } | |||
} |
@ -1,54 +0,0 @@ | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.Order | |||
@{ | |||
ViewData["Title"] = "My Cart"; | |||
} | |||
<div class="brand-header-block"> | |||
<ul class="container"> | |||
<li class="brand-header-back"><a asp-area="" asp-controller="Home" asp-action="Index">Back to list</a></li> | |||
</ul> | |||
</div> | |||
<div class="container cart-index-container"> | |||
<div class="row"> | |||
<div class="col-md-offset-8 col-md-4"> | |||
<a asp-controller="Home" asp-action="Index" class="btn btn-default btn-brand btn-brand-dark btn-cart"> Continue Shopping </a> | |||
</div> | |||
<br /><br /><br /><br /> | |||
<div class="col-md-12"> | |||
<section> | |||
<table class="table"> | |||
<thead> | |||
<tr> | |||
<th> | |||
PRODUCT | |||
</th> | |||
<th> | |||
</th> | |||
<th> | |||
BRAND | |||
</th> | |||
<th> | |||
PRICE | |||
</th> | |||
<th> | |||
QUANTITY | |||
</th> | |||
<th> | |||
FINAL PRICE | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
@await Component.InvokeAsync("Cart") | |||
</tbody> | |||
</table> | |||
</section> | |||
</div> | |||
<br /><br /><br /><br /><br /><br /> | |||
<div class="col-md-offset-8 col-md-4"> | |||
<a asp-controller="Order" asp-action="Create" class="btn btn-default btn-brand btn-cart"> CheckOut </a> | |||
</div> | |||
</div> | |||
</div> |
@ -0,0 +1,84 @@ | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.Order | |||
@inject UserManager<ApplicationUser> UserManager | |||
@{ | |||
ViewData["Title"] = "Order Detail"; | |||
} | |||
<div class="brand-header-block"> | |||
<ul class="container"> | |||
<li class="brand-header-back"><a asp-area="" asp-controller="Catalog" asp-action="Index">Back to list</a></li> | |||
</ul> | |||
</div> | |||
<div class="container order-detail-container"> | |||
<div class="row"> | |||
<div class="col-sm-3"> | |||
<span>ORDER NUMBER</span><br /> | |||
<span>@Model.OrderNumber</span> | |||
</div> | |||
<div class="col-sm-3"> | |||
<span>DATE</span><br /> | |||
<span>@Model.OrderDate</span> | |||
</div> | |||
<div class="col-sm-3"> | |||
<span>TOTAL</span><br /> | |||
<span>$ @Model.Total()</span> | |||
</div> | |||
<div class="col-sm-3"> | |||
<span>STATUS</span><br /> | |||
<span>@Model.State</span> | |||
</div> | |||
</div> | |||
<div class="row order-detail-section"> | |||
<div class="col-sm-3"> | |||
<span>SHIPING ADDRESS</span><br /> | |||
<span>@Model.ShippingAddress.Street</span><br /> | |||
<span>@Model.ShippingAddress.City</span><br /> | |||
@*<span>@Model.ShippingAddress.ZipCode</span><br />*@ | |||
<span>@Model.ShippingAddress.Country</span><br /> | |||
</div> | |||
</div> | |||
<div> | |||
<div class="row order-detail-section"><div class="col-sm-3">ORDER DETAILS</div></div> | |||
<section> | |||
<table class="table"> | |||
<tbody> | |||
@for (int i = 0; i < Model.OrderItems.Count; i++) | |||
{ | |||
var item = Model.OrderItems[i]; | |||
<tr> | |||
<td class="cart-product-column"><img class="cart-product-image" src="@item.PictureUrl" /></td> | |||
<td class="cart-product-column">@item.ProductName</td> | |||
<td class="cart-product-column">ROSLYN</td> | |||
<td class="cart-product-column">$ @item.UnitPrice</td> | |||
<td class="cart-product-column">@item.Quantity</td> | |||
<td class="cart-product-column cart-total-value">$ @(item.Quantity * item.UnitPrice)</td> | |||
</tr> | |||
} | |||
</tbody> | |||
</table> | |||
<div class="row"> | |||
<div class="col-sm-6"> | |||
</div> | |||
</div> | |||
</section> | |||
</div> | |||
<div class="col-md-offset-9 col-md-3"> | |||
@*<input type="submit" | |||
class="btn btn-default cart-refresh-button" | |||
value="" | |||
name="action" />*@ | |||
<div class="order-section-total"> | |||
@*<div class="cart-subtotal-label"><span>SUBTOTAL</span></div> | |||
<div class="cart-subtotal-value"><span>$ @Model.Total()</span></div> | |||
<div class="cart-subtotal-label"><span>TAX</span></div> | |||
<div class="cart-subtotal-value"><span>$ 4.20</span></div>*@ | |||
<div class="cart-total-label"><span>TOTAL</span></div> | |||
<div class="cart-total-value"><span>$ @Model.Total()</span></div> | |||
</div> | |||
</div> | |||
</div> |
@ -1,20 +1,17 @@ | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.Order | |||
@model System.Int32 | |||
@{ | |||
ViewData["Title"] = "My Cart"; | |||
} | |||
@foreach (var item in Model.OrderItems) | |||
{ | |||
<tr> | |||
<td>@*image*@</td> | |||
<td>@item.ProductName</td> | |||
<td>ROSLYN</td> | |||
<td>$ @item.UnitPrice</td> | |||
<td>@item.Quantity</td> | |||
<td>$ @item.Quantity * @item.UnitPrice</td> | |||
</tr> | |||
} | |||
<div> | |||
<a asp-area="" asp-controller="Cart" asp-action="Index"><img src="~/images/cart.PNG" class="fr layout-cart-image hidden-xs" /> | |||
</a> | |||
<div class="layout-cart-badge"> | |||
@Model | |||
</div> | |||
</div> | |||
@ -0,0 +1,68 @@ | |||
@model Microsoft.eShopOnContainers.WebMVC.Models.Basket | |||
@{ | |||
ViewData["Title"] = "My Cart"; | |||
} | |||
<div class="col-md-12"> | |||
<section> | |||
<table class="table"> | |||
<thead> | |||
<tr> | |||
<th class="cart-product-column"> | |||
PRODUCT | |||
</th> | |||
<th> | |||
</th> | |||
<th> | |||
BRAND | |||
</th> | |||
<th> | |||
PRICE | |||
</th> | |||
<th> | |||
QUANTITY | |||
</th> | |||
<th> | |||
COST | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
@for (int i = 0; i < Model.Items.Count; i++) | |||
{ | |||
var item = Model.Items[i]; | |||
<tr> | |||
<td class="cart-product-column"><img class="cart-product-image" src="@item.PictureUrl" /></td> | |||
<td class="cart-product-column">@item.ProductName</td> | |||
<td class="cart-product-column">ROSLYN</td> | |||
<td class="cart-product-column">$ @item.UnitPrice</td> | |||
<td class="cart-product-column"> | |||
<input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" /> | |||
<input type="number" name="@("quantities[" + i +"].Value")" value="@item.Quantity" /> | |||
</td> | |||
<td class="cart-product-column cart-total-value">$ @(item.Quantity * item.UnitPrice)</td> | |||
</tr> | |||
} | |||
</tbody> | |||
</table> | |||
</section> | |||
</div> | |||
<div class="col-md-offset-8 col-md-4"> | |||
<input type="submit" | |||
class="btn btn-default cart-refresh-button" | |||
value="" | |||
name="action" /> | |||
<div class="cart-section-total"> | |||
@*<div class="cart-subtotal-label"><span>SUBTOTAL</span></div> | |||
<div class="cart-subtotal-value"><span>$ @Model.Total()</span></div> | |||
<div class="cart-subtotal-label"><span>TAX</span></div> | |||
<div class="cart-subtotal-value"><span>$ 4.20</span></div>*@ | |||
<div class="cart-total-label"><span>TOTAL</span></div> | |||
<div class="cart-total-value"><span>$ @Model.Total()</span></div> | |||
</div> | |||
</div> | |||
@ -0,0 +1,44 @@ | |||
<?xml version="1.0" encoding="iso-8859-1"?> | |||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | |||
viewBox="0 0 259.244 259.244" style="enable-background:new 0 0 259.244 259.244;" xml:space="preserve"> | |||
<g> | |||
<path style="fill:#3DB39E;" d="M248.348,129.3h-15.849C232.41,65.277,180.831,13.394,117.202,13.394 | |||
c-31.841,0-60.661,12.998-81.534,33.996C14.017,68.549,0.25,97.092,0.036,129.3H0l0.018,0.331L0,130.033h0.036 | |||
c0.393,63.853,51.758,115.816,115.19,115.816c31.841,0,60.661-13.007,81.534-34.049l-25.852-24.931 | |||
c-14.178,14.303-34.058,23.027-55.682,23.135c-44.401,0.206-79.201-36.49-79.201-80.122c-0.107-22.893,10.092-42.908,25.486-57.595 | |||
c14.186-14.285,34.058-23.001,55.691-23.108c44.41-0.206,79.201,36.445,79.201,79.997v0.125h-15.661 | |||
c-9.708,0-13.668,6.499-8.814,14.41l33.799,33.433c7.732,7.732,9.967,7.661,17.646,0l33.799-33.433 | |||
C262.025,135.781,258.056,129.3,248.348,129.3z"/> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
<g> | |||
</g> | |||
</svg> |
@ -1 +1 @@ | |||
// Write your Javascript code. | |||
// Write your Javascript code. |