public async Task <IActionResult> Update(BasketDetailsViewModel bvm)
        {
            if (!ModelState.IsValid)
            {
                return(RedirectToAction("Index", "Shop"));
            }

            foreach ((long itemId, int quantity) in bvm.Quantities)
            {
                BasketItem item = await _productDbContext.BasketItems.FindAsync(itemId);

                if (item is null)
                {
                    continue;
                }

                // If the new quantity is greater than 0, then update; otherwise, delete
                if (quantity > 0)
                {
                    item.Quantity = quantity;
                    _productDbContext.BasketItems.Update(item);
                }
                else
                {
                    _productDbContext.Remove(item);
                }
            }

            await _productDbContext.SaveChangesAsync();

            return(RedirectToLocal(bvm.ReturnUrl));
        }
        public async Task <IViewComponentResult> InvokeAsync(
            bool quantityInputs = true, bool checkoutButton = true)
        {
            // Always create a view model to avoid the view component view trying
            // to take the current action's model (possible MVC bug?)
            BasketDetailsViewModel bvm = new BasketDetailsViewModel()
            {
                QuantityInputs = quantityInputs,
                CheckoutButton = checkoutButton,
            };

            long?currentBasketId =
                (await _userManager.GetUserAsync(HttpContext.User))?.CurrentBasketId;

            // If the user is logged in and has a basket, fill in the view model;
            // otherwise, the default values will suffice
            if (currentBasketId.HasValue)
            {
                // Retrieve all of the items in the current basket, making sure
                // to include the Product navigational property
                bvm.Items = await _productDbContext.Baskets.Where(b => b.Id == currentBasketId)
                            .Include(b => b.Items)
                            .SelectMany(b => b.Items)
                            .Include(bi => bi.Product)
                            .ToListAsync();

                if (bvm.QuantityInputs)
                {
                    bvm.Quantities = new Dictionary <long, int>();
                    foreach (BasketItem item in bvm.Items)
                    {
                        bvm.Quantities[item.Id] = item.Quantity;
                    }
                }

                // Find the total quantity in the basket by summing each line item's quantity
                bvm.TotalQuantity = bvm.Items.Select(bi => bi.Quantity)
                                    .Sum();

                // Find the grand total price in the basket by summing the products of each
                // line item's quantity by its product's price. The Product navigational
                // property was already included in the Items LINQ expression seen above.
                bvm.TotalPrice = bvm.Items.Select(bi => bi.Quantity * bi.Product.Price)
                                 .Sum();
            }

            return(View(bvm));
        }