Dynamic Sidebar implemented, with appropriate icons and separately populated category pages
This commit is contained in:
parent
1ce7b31d8e
commit
6023073b3a
|
@ -74,5 +74,42 @@ namespace ShopOnline.Api.Controllers
|
|||
"Error retrieving data from the database.");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route(nameof(GetProductCategories))]
|
||||
public async Task<ActionResult<IEnumerable<ProductCategoryDto>>> GetProductCategories()
|
||||
{
|
||||
try
|
||||
{
|
||||
var productCategories = await productRepository.GetCategories();
|
||||
var productCategoryDtos = productCategories.ConvertToDto();
|
||||
|
||||
return Ok(productCategoryDtos);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return StatusCode(StatusCodes.Status500InternalServerError,
|
||||
"Error retrieving data from the database.");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("{categoryId}/GetItemsByCategory")]
|
||||
public async Task<ActionResult<IEnumerable<ProductDto>>> GetItemsByCategory(int categoryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var products = await productRepository.GetItemsByCategory(categoryId);
|
||||
var productCategories = await productRepository.GetCategories();
|
||||
var productDtos = products.ConvertToDto(productCategories);
|
||||
|
||||
return Ok(productDtos);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return StatusCode(StatusCodes.Status500InternalServerError,
|
||||
"Error retrieving data from the database.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,22 +292,27 @@ namespace ShopOnline.Api.Data
|
|||
modelBuilder.Entity<ProductCategory>().HasData(new ProductCategory
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Beauty"
|
||||
Name = "Beauty",
|
||||
IconCSS = "fas fa-spa"
|
||||
});
|
||||
modelBuilder.Entity<ProductCategory>().HasData(new ProductCategory
|
||||
{
|
||||
Id = 2,
|
||||
Name = "Furniture"
|
||||
Name = "Furniture",
|
||||
IconCSS = "fas fa-couch"
|
||||
});
|
||||
modelBuilder.Entity<ProductCategory>().HasData(new ProductCategory
|
||||
{
|
||||
Id = 3,
|
||||
Name = "Electronics"
|
||||
Name = "Electronics",
|
||||
IconCSS = "fas fa-headphones"
|
||||
|
||||
});
|
||||
modelBuilder.Entity<ProductCategory>().HasData(new ProductCategory
|
||||
{
|
||||
Id = 4,
|
||||
Name = "Shoes"
|
||||
Name = "Shoes",
|
||||
IconCSS = "fas fa-shoe-prints"
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string IconCSS { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,17 @@ namespace ShopOnline.Api.Extensions
|
|||
{
|
||||
public static class DtoConversions
|
||||
{
|
||||
public static IEnumerable<ProductCategoryDto> ConvertToDto(this IEnumerable<ProductCategory> productCategories)
|
||||
{
|
||||
return (from productCategory in productCategories
|
||||
select new ProductCategoryDto
|
||||
{
|
||||
Id = productCategory.Id,
|
||||
Name = productCategory.Name,
|
||||
IconCSS = productCategory.IconCSS
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<ProductDto> ConvertToDto(this IEnumerable<Product> products,
|
||||
IEnumerable<ProductCategory> productCategories)
|
||||
{
|
||||
|
|
420
ShopOnline.Api/Migrations/20220916171516_AddProductCategoryIcons.Designer.cs
generated
Normal file
420
ShopOnline.Api/Migrations/20220916171516_AddProductCategoryIcons.Designer.cs
generated
Normal file
|
@ -0,0 +1,420 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using ShopOnline.Api.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ShopOnline.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(ShopOnlineDbContext))]
|
||||
[Migration("20220916171516_AddProductCategoryIcons")]
|
||||
partial class AddProductCategoryIcons
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "6.0.8")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
|
||||
|
||||
modelBuilder.Entity("ShopOnline.Api.Entities.Cart", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Carts");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
UserId = 1
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
UserId = 2
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ShopOnline.Api.Entities.CartItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<int>("CartId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ProductId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CartItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ShopOnline.Api.Entities.Product", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<int>("CategoryId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ImageURL")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Products");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
CategoryId = 1,
|
||||
Description = "A kit provided by Glossier, containing skin care, hair care and makeup products",
|
||||
ImageURL = "/Images/Beauty/Beauty1.png",
|
||||
Name = "Glossier - Beauty Kit",
|
||||
Price = 100m,
|
||||
Quantity = 100
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
CategoryId = 1,
|
||||
Description = "A kit provided by Curology, containing skin care products",
|
||||
ImageURL = "/Images/Beauty/Beauty2.png",
|
||||
Name = "Curology - Skin Care Kit",
|
||||
Price = 50m,
|
||||
Quantity = 45
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 3,
|
||||
CategoryId = 1,
|
||||
Description = "A kit provided by Curology, containing skin care products",
|
||||
ImageURL = "/Images/Beauty/Beauty3.png",
|
||||
Name = "Cocooil - Organic Coconut Oil",
|
||||
Price = 20m,
|
||||
Quantity = 30
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 4,
|
||||
CategoryId = 1,
|
||||
Description = "A kit provided by Schwarzkopf, containing skin care and hair care products",
|
||||
ImageURL = "/Images/Beauty/Beauty4.png",
|
||||
Name = "Schwarzkopf - Hair Care and Skin Care Kit",
|
||||
Price = 50m,
|
||||
Quantity = 60
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 5,
|
||||
CategoryId = 1,
|
||||
Description = "Skin Care Kit, containing skin care and hair care products",
|
||||
ImageURL = "/Images/Beauty/Beauty5.png",
|
||||
Name = "Skin Care Kit",
|
||||
Price = 30m,
|
||||
Quantity = 85
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 6,
|
||||
CategoryId = 3,
|
||||
Description = "Air Pods - in-ear wireless headphones",
|
||||
ImageURL = "/Images/Electronic/Electronics1.png",
|
||||
Name = "Air Pods",
|
||||
Price = 100m,
|
||||
Quantity = 120
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 7,
|
||||
CategoryId = 3,
|
||||
Description = "On-ear Golden Headphones - these headphones are not wireless",
|
||||
ImageURL = "/Images/Electronic/Electronics2.png",
|
||||
Name = "On-ear Golden Headphones",
|
||||
Price = 40m,
|
||||
Quantity = 200
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 8,
|
||||
CategoryId = 3,
|
||||
Description = "On-ear Black Headphones - these headphones are not wireless",
|
||||
ImageURL = "/Images/Electronic/Electronics3.png",
|
||||
Name = "On-ear Black Headphones",
|
||||
Price = 40m,
|
||||
Quantity = 300
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 9,
|
||||
CategoryId = 3,
|
||||
Description = "Sennheiser Digital Camera - High quality digital camera provided by Sennheiser - includes tripod",
|
||||
ImageURL = "/Images/Electronic/Electronic4.png",
|
||||
Name = "Sennheiser Digital Camera with Tripod",
|
||||
Price = 600m,
|
||||
Quantity = 20
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 10,
|
||||
CategoryId = 3,
|
||||
Description = "Canon Digital Camera - High quality digital camera provided by Canon",
|
||||
ImageURL = "/Images/Electronic/Electronic5.png",
|
||||
Name = "Canon Digital Camera",
|
||||
Price = 500m,
|
||||
Quantity = 15
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 11,
|
||||
CategoryId = 3,
|
||||
Description = "Gameboy - Provided by Nintendo",
|
||||
ImageURL = "/Images/Electronic/technology6.png",
|
||||
Name = "Nintendo Gameboy",
|
||||
Price = 100m,
|
||||
Quantity = 60
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 12,
|
||||
CategoryId = 2,
|
||||
Description = "Very comfortable black leather office chair",
|
||||
ImageURL = "/Images/Furniture/Furniture1.png",
|
||||
Name = "Black Leather Office Chair",
|
||||
Price = 50m,
|
||||
Quantity = 212
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 13,
|
||||
CategoryId = 2,
|
||||
Description = "Very comfortable pink leather office chair",
|
||||
ImageURL = "/Images/Furniture/Furniture2.png",
|
||||
Name = "Pink Leather Office Chair",
|
||||
Price = 50m,
|
||||
Quantity = 112
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 14,
|
||||
CategoryId = 2,
|
||||
Description = "Very comfortable lounge chair",
|
||||
ImageURL = "/Images/Furniture/Furniture3.png",
|
||||
Name = "Lounge Chair",
|
||||
Price = 70m,
|
||||
Quantity = 90
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 15,
|
||||
CategoryId = 2,
|
||||
Description = "Very comfortable Silver lounge chair",
|
||||
ImageURL = "/Images/Furniture/Furniture4.png",
|
||||
Name = "Silver Lounge Chair",
|
||||
Price = 120m,
|
||||
Quantity = 95
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 16,
|
||||
CategoryId = 2,
|
||||
Description = "White and blue Porcelain Table Lamp",
|
||||
ImageURL = "/Images/Furniture/Furniture6.png",
|
||||
Name = "Porcelain Table Lamp",
|
||||
Price = 15m,
|
||||
Quantity = 100
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 17,
|
||||
CategoryId = 2,
|
||||
Description = "Office Table Lamp",
|
||||
ImageURL = "/Images/Furniture/Furniture7.png",
|
||||
Name = "Office Table Lamp",
|
||||
Price = 20m,
|
||||
Quantity = 73
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 18,
|
||||
CategoryId = 4,
|
||||
Description = "Comfortable Puma Sneakers in most sizes",
|
||||
ImageURL = "/Images/Shoes/Shoes1.png",
|
||||
Name = "Puma Sneakers",
|
||||
Price = 100m,
|
||||
Quantity = 50
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 19,
|
||||
CategoryId = 4,
|
||||
Description = "Colorful trainsers - available in most sizes",
|
||||
ImageURL = "/Images/Shoes/Shoes2.png",
|
||||
Name = "Colorful Trainers",
|
||||
Price = 150m,
|
||||
Quantity = 60
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 20,
|
||||
CategoryId = 4,
|
||||
Description = "Blue Nike Trainers - available in most sizes",
|
||||
ImageURL = "/Images/Shoes/Shoes3.png",
|
||||
Name = "Blue Nike Trainers",
|
||||
Price = 200m,
|
||||
Quantity = 70
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 21,
|
||||
CategoryId = 4,
|
||||
Description = "Colorful Hummel Trainers - available in most sizes",
|
||||
ImageURL = "/Images/Shoes/Shoes4.png",
|
||||
Name = "Colorful Hummel Trainers",
|
||||
Price = 120m,
|
||||
Quantity = 120
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 22,
|
||||
CategoryId = 4,
|
||||
Description = "Red Nike Trainers - available in most sizes",
|
||||
ImageURL = "/Images/Shoes/Shoes5.png",
|
||||
Name = "Red Nike Trainers",
|
||||
Price = 200m,
|
||||
Quantity = 100
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 23,
|
||||
CategoryId = 4,
|
||||
Description = "Birkenstock Sandles - available in most sizes",
|
||||
ImageURL = "/Images/Shoes/Shoes6.png",
|
||||
Name = "Birkenstock Sandles",
|
||||
Price = 50m,
|
||||
Quantity = 150
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ShopOnline.Api.Entities.ProductCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<string>("IconCSS")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ProductCategories");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
IconCSS = "fas fa-spa",
|
||||
Name = "Beauty"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
IconCSS = "fas fa-couch",
|
||||
Name = "Furniture"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 3,
|
||||
IconCSS = "fas fa-headphones",
|
||||
Name = "Electronics"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 4,
|
||||
IconCSS = "fas fa-shoe-prints",
|
||||
Name = "Shoes"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ShopOnline.Api.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
UserName = "Bob"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
UserName = "Sarah"
|
||||
});
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ShopOnline.Api.Migrations
|
||||
{
|
||||
public partial class AddProductCategoryIcons : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "IconCSS",
|
||||
table: "ProductCategories",
|
||||
type: "nvarchar(max)",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ProductCategories",
|
||||
keyColumn: "Id",
|
||||
keyValue: 1,
|
||||
column: "IconCSS",
|
||||
value: "fas fa-spa");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ProductCategories",
|
||||
keyColumn: "Id",
|
||||
keyValue: 2,
|
||||
column: "IconCSS",
|
||||
value: "fas fa-couch");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ProductCategories",
|
||||
keyColumn: "Id",
|
||||
keyValue: 3,
|
||||
column: "IconCSS",
|
||||
value: "fas fa-headphones");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ProductCategories",
|
||||
keyColumn: "Id",
|
||||
keyValue: 4,
|
||||
column: "IconCSS",
|
||||
value: "fas fa-shoe-prints");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IconCSS",
|
||||
table: "ProductCategories");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -345,6 +345,10 @@ namespace ShopOnline.Api.Migrations
|
|||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"), 1L, 1);
|
||||
|
||||
b.Property<string>("IconCSS")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
@ -357,21 +361,25 @@ namespace ShopOnline.Api.Migrations
|
|||
new
|
||||
{
|
||||
Id = 1,
|
||||
IconCSS = "fas fa-spa",
|
||||
Name = "Beauty"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
IconCSS = "fas fa-couch",
|
||||
Name = "Furniture"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 3,
|
||||
IconCSS = "fas fa-headphones",
|
||||
Name = "Electronics"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 4,
|
||||
IconCSS = "fas fa-shoe-prints",
|
||||
Name = "Shoes"
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace ShopOnline.Api.Repositories.Contracts
|
|||
Task<Product> GetItem(int id);
|
||||
|
||||
Task<IEnumerable<ProductCategory>> GetCategories();
|
||||
|
||||
Task<ProductCategory> GetCategory(int id);
|
||||
Task<IEnumerable<Product>> GetItemsByCategory(int id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,5 +36,14 @@ namespace ShopOnline.Api.Repositories
|
|||
|
||||
return products;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Product>> GetItemsByCategory(int id)
|
||||
{
|
||||
var products = await (from product in shopOnlineDbContext.Products
|
||||
where product.CategoryId == id
|
||||
select product).ToListAsync();
|
||||
|
||||
return products;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ShopOnline.Models.Dtos
|
||||
{
|
||||
public class ProductCategoryDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string IconCSS { get; set; }
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
<div class="lds-spin"><i class="custom fa-regular fa-heart fa-10x" style="background: transparent;"></i></div>
|
||||
<div class="lds-spin"><i class="custom fa-regular fa-heart fa-9x" style="background: transparent;"></i></div>
|
|
@ -22,7 +22,7 @@ else
|
|||
@foreach (var prodGroup in GetGroupedProductsByCategory())
|
||||
{
|
||||
<div class="row mt-3">
|
||||
<h4>@prodGroup.FirstOrDefault(pg=>pg.CategoryId == prodGroup.Key).CategoryName</h4>
|
||||
<h3>@prodGroup.FirstOrDefault(pg=>pg.CategoryId == prodGroup.Key).CategoryName</h3>
|
||||
<DisplayProducts Products="@prodGroup.Take(4)"></DisplayProducts>
|
||||
</div>
|
||||
<hr class="mb-3" />
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
@page "/ProductsByCategory/{CategoryId:int}"
|
||||
@inherits ProductsByCategoryBase
|
||||
|
||||
@if (Products == null && ErrorMessage == null)
|
||||
{
|
||||
<div class="row d-flex justify-content-center">
|
||||
<div class="col-md-1">
|
||||
<DisplayCustomSpinner />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (ErrorMessage != null)
|
||||
{
|
||||
<DisplayError ErrorMessage="@ErrorMessage" />
|
||||
}
|
||||
else {
|
||||
<h2>@CategoryName</h2>
|
||||
@if(Products.Count() > 0)
|
||||
{
|
||||
<div class="row mt-3">
|
||||
<DisplayProducts Products="@Products"></DisplayProducts>
|
||||
</div>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using ShopOnline.Models.Dtos;
|
||||
using ShopOnline.Web.Services.Contracts;
|
||||
|
||||
namespace ShopOnline.Web.Pages
|
||||
{
|
||||
public class ProductsByCategoryBase:ComponentBase
|
||||
{
|
||||
[Parameter]
|
||||
public int CategoryId { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IProductService ProductService { get; set; }
|
||||
|
||||
public IEnumerable<ProductDto> Products { get; set; }
|
||||
public string CategoryName { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Products = await ProductService.GetItemsByCategory(CategoryId);
|
||||
if(Products != null && Products.Count() > 0)
|
||||
{
|
||||
var productDto = Products.FirstOrDefault(p => p.CategoryId == CategoryId);
|
||||
if(productDto != null)
|
||||
{
|
||||
CategoryName = productDto.CategoryName;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ namespace ShopOnline.Web.Services.Contracts
|
|||
{
|
||||
Task<IEnumerable<ProductDto>> GetItems();
|
||||
Task<ProductDto> GetItem(int id);
|
||||
|
||||
Task<IEnumerable<ProductCategoryDto>> GetProductCategories();
|
||||
Task<IEnumerable<ProductDto>> GetItemsByCategory(int categoryId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,5 +65,59 @@ namespace ShopOnline.Web.Services
|
|||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProductDto>> GetItemsByCategory(int categoryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await httpClient.GetAsync($"api/Product/{categoryId}/GetItemsByCategory");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
|
||||
{
|
||||
return Enumerable.Empty<ProductDto>();
|
||||
}
|
||||
return await response.Content.ReadFromJsonAsync<IEnumerable<ProductDto>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = await response.Content.ReadAsStringAsync();
|
||||
throw new Exception($"Http Status Code - {response.StatusCode} Message - {message}");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProductCategoryDto>> GetProductCategories()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await httpClient.GetAsync("api/Product/GetProductCategories");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
if(response.StatusCode == System.Net.HttpStatusCode.NoContent)
|
||||
{
|
||||
return Enumerable.Empty<ProductCategoryDto>();
|
||||
}
|
||||
return await response.Content.ReadFromJsonAsync<IEnumerable<ProductCategoryDto>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = await response.Content.ReadAsStringAsync();
|
||||
throw new Exception($"Http Status Code - {response.StatusCode} Message - {message}");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">ShopOnline.Web</a>
|
||||
<a class="navbar-brand" href=""><span class="fas fa-shopping-cart" aria-hidden="true"></span> ShopOnline</a>
|
||||
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
@ -14,22 +14,15 @@
|
|||
<nav class="flex-column">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="oi oi-home" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="counter">
|
||||
<span class="oi oi-plus" aria-hidden="true"></span> Counter
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="fetchdata">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
|
||||
<span class="fas fa-home" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<ProductCategoriesNavMenu />
|
||||
|
||||
<div class="nav-item px-3 d-sm-none">
|
||||
<NavLink class="nav-link" href="ShoppingCart">
|
||||
<span class="fas fa-shopping-cart" aria-hidden="true"></span> Shopping Cart (<b>@shoppingCartItemsCount</b>)
|
||||
<span class="fas fa-shopping-cart" aria-hidden="true"></span> Shopping Cart (<b>@shoppingCartItemsCount</b>)
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
@inherits ProductCategoriesNavMenuBase
|
||||
|
||||
@if(ProductCategoryDtos == null && ErrorMessage == null)
|
||||
{
|
||||
<DisplaySpinner />
|
||||
}
|
||||
else if(ErrorMessage != null)
|
||||
{
|
||||
<DisplayError ErrorMessage="@ErrorMessage" />
|
||||
}
|
||||
else {
|
||||
@foreach(var productCategory in ProductCategoryDtos)
|
||||
{
|
||||
var link = "/ProductsByCategory/" + productCategory.Id;
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="@link">
|
||||
<span class="@productCategory.IconCSS"></span> @productCategory.Name
|
||||
</NavLink>
|
||||
</div>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
.navbar-toggler {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.oi {
|
||||
width: 2rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using ShopOnline.Models.Dtos;
|
||||
using ShopOnline.Web.Services.Contracts;
|
||||
|
||||
namespace ShopOnline.Web.Shared
|
||||
{
|
||||
public class ProductCategoriesNavMenuBase:ComponentBase
|
||||
{
|
||||
[Inject]
|
||||
public IProductService ProductService { get; set; }
|
||||
|
||||
public IEnumerable<ProductCategoryDto> ProductCategoryDtos { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
ProductCategoryDtos = await ProductService.GetProductCategories();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
ErrorMessage = ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,3 +10,4 @@
|
|||
@using ShopOnline.Web.Shared
|
||||
@using ShopOnline.Models.Dtos
|
||||
@using ShopOnline.Web.Services.Contracts
|
||||
@using ShopOnline.Web.Pages
|
||||
|
|
Loading…
Reference in New Issue