From bbe546b60dffecf9ff5f12d0ab66a2fd3c86217f Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Sat, 22 Jun 2024 21:40:01 +0500
Subject: [PATCH 1/7] lesson 6

---
 .../Constants/ApiResourceConstants.cs         |  7 ++
 .../Controllers/CategoriesController.cs       | 18 +++-
 .../Controllers/ProductsController.cs         | 43 ++++++++
 .../WMS.WebUI/Exceptions/ApiException.cs      |  8 ++
 .../ApiResponse/PaginatedApiResponse.cs       | 17 ++++
 WMS.WebUI/WMS.WebUI/Program.cs                |  4 +-
 .../QueryParams/ProductQueryParameters.cs     | 12 +++
 WMS.WebUI/WMS.WebUI/Services/ApiClient.cs     | 66 +++++++++++++
 WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs   | 67 +++----------
 WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs  | 19 +---
 .../Stores/Interfaces/ICategoryStore.cs       |  5 +-
 .../Stores/Interfaces/IProductsStore.cs       | 14 +--
 .../WMS.WebUI/Stores/Mocks/CategoryDto.cs     | 16 +++
 .../Stores/Mocks/MockProductsStore.cs         | 56 -----------
 WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs    | 97 +++++++++++++++++++
 .../WMS.WebUI/ViewModels/CategoryViewModel.cs | 15 ++-
 .../WMS.WebUI/Views/Categories/Index.cshtml   | 40 ++++++++
 .../WMS.WebUI/Views/Products/Index.cshtml     | 80 +++++++++++++++
 WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj          |  1 +
 WMS.WebUI/WMS.WebUI/wwwroot/css/site.css      |  6 +-
 20 files changed, 451 insertions(+), 140 deletions(-)
 create mode 100644 WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Services/ApiClient.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs
 delete mode 100644 WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml

diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
new file mode 100644
index 0000000..6da50ba
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
@@ -0,0 +1,7 @@
+namespace WMS.WebUI.Constants;
+
+public static class ApiResourceConstants
+{
+    public const string Products = nameof(Products);
+    public const string Categories = nameof(Categories);
+}
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs b/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs
index 0736e03..24d57cc 100644
--- a/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs
+++ b/WMS.WebUI/WMS.WebUI/Controllers/CategoriesController.cs
@@ -14,12 +14,20 @@ public CategoriesController(ICategoryStore categoryStore)
     }
 
     // GET: Categories
-    public async Task<ActionResult> Index(string? searchString)
+    public async Task<ActionResult> Index(string? searchString,int? pageNumber)
     {
-        var categories = await _categoryStore.GetCategoriesAsync(searchString);
-        ViewBag.SearchString = searchString;
-
-        return View(categories);
+        var categories = await _categoryStore.GetCategoriesAsync(searchString, pageNumber);
+       
+        ViewBag.SearchString = searchString ;
+        ViewBag.PageSize = categories.PageSize;
+        ViewBag.TotalPages = categories.PagesCount;
+        ViewBag.TotalItems = categories.TotalCount;
+        ViewBag.CurrentPage = categories.CurrentPage;
+        ViewBag.HasPreviousPage = categories.HasPreviousPage;
+        ViewBag.HasNextPage = categories.HasNextPage;
+
+
+        return View(categories.Data);
     }
 
     // GET: Categories/Details/5
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs
new file mode 100644
index 0000000..0afd51d
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs
@@ -0,0 +1,43 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels;
+
+namespace WMS.WebUI.Controllers;
+
+public class ProductsController(IProductsStore store,ICategoryStore categoryStore) : Controller
+{
+    private readonly ICategoryStore _categoryStore = categoryStore;
+    private readonly IProductsStore _productsStore = store ?? throw new ArgumentNullException(nameof(store));
+
+    public async Task<IActionResult> Index(
+        string? search,
+        int? pageNumber,
+        int? categoryId,
+        decimal? maxPrice,
+        decimal? minPrice,
+        bool? lowQuantityInStock)
+    {
+        var products = await _productsStore.GetProducts(new ProductQueryParameters());
+        var categories = await _categoryStore.GetCategoriesAsync();
+
+        PopulateViewBag(products, search);
+
+        return View(products.Data);
+    }
+
+    private void PopulateViewBag(
+        PaginatedApiResponse<ProductViewModel> products,
+        string? searchString)
+    {
+        ViewBag.SearchString = searchString;
+        ViewBag.PageSize = products.PageSize;
+        ViewBag.TotalPages = products.PagesCount;
+        ViewBag.TotalItems = products.TotalCount;
+        ViewBag.CurrentPage = products.CurrentPage;
+        ViewBag.HasPreviousPage = products.HasPreviousPage;
+        ViewBag.HasNextPage = products.HasNextPage;
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs b/WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs
new file mode 100644
index 0000000..d7b9a6b
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Exceptions/ApiException.cs
@@ -0,0 +1,8 @@
+namespace WMS.WebUI.Exceptions;
+
+public class ApiException : Exception
+{
+    public ApiException() : base() { }
+    public ApiException(string message) : base(message) { }
+    public ApiException(string message, Exception inner) : base(message, inner) { }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs b/WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs
new file mode 100644
index 0000000..f95ff3a
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Models/ApiResponse/PaginatedApiResponse.cs
@@ -0,0 +1,17 @@
+namespace WMS.WebUI.Models.PaginatedResponse;
+
+public class PaginatedApiResponse<T>
+{
+    public List<T> Data { get; set; }
+    public int CurrentPage { get; set; }
+    public int PageSize { get; set; }
+    public int PagesCount { get; set; }
+    public int TotalCount { get; set; }
+    public bool HasNextPage { get; set; }
+    public bool HasPreviousPage { get; set; }
+
+    public PaginatedApiResponse()
+    {
+        Data = [];
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs
index 32f893d..57d4167 100644
--- a/WMS.WebUI/WMS.WebUI/Program.cs
+++ b/WMS.WebUI/WMS.WebUI/Program.cs
@@ -1,3 +1,4 @@
+using WMS.WebUI.Services;
 using WMS.WebUI.Stores;
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.Stores.Mocks;
@@ -8,7 +9,8 @@
 builder.Services.AddControllersWithViews();
 builder.Services.AddScoped<IDashboardStore, DashboardStore>();
 builder.Services.AddScoped<ICategoryStore, CategoryStore>();
-builder.Services.AddScoped<IProductsStore, MockProductsStore>();
+builder.Services.AddScoped<IProductsStore, ProductStore>();
+builder.Services.AddSingleton<ApiClient>();
 
 Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ;
 
diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs
new file mode 100644
index 0000000..43afcf7
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs
@@ -0,0 +1,12 @@
+namespace WMS.WebUI.QueryParams;
+
+public class ProductQueryParameters
+{
+    public string? Search { get; set; }
+    public int? CategoryId { get; set; }
+    public int? PageNumber { get; set; }
+    public int? PageSize { get; set; } = 10;
+    public decimal? MaxPrice { get; set; }
+    public decimal? MinPrice { get; set; }
+    public bool? LowQuantityInStock { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs
new file mode 100644
index 0000000..aae3a41
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs
@@ -0,0 +1,66 @@
+using Newtonsoft.Json;
+using System.Text;
+using WMS.WebUI.Exceptions;
+
+namespace WMS.WebUI.Services;
+
+public class ApiClient
+{
+    private readonly HttpClient _client;
+
+    public ApiClient()
+    {
+        _client = new()
+        {
+            BaseAddress = new Uri("https://localhost:7097/api/")
+        };
+    }
+
+    public async Task<T> GetAsync<T>(string resource)
+    {
+        var response = await _client.GetAsync(resource);
+        response.EnsureSuccessStatusCode();
+
+        response.EnsureSuccessStatusCode();
+
+        var json = await response.Content.ReadAsStringAsync();
+        var result = JsonConvert.DeserializeObject<T>(json)
+            ?? throw new ApiException($"Could not deserialize get response for resource {resource}.");
+
+        return result;
+    }
+
+    public async Task<T> PostAsync<T>(string resource, T body)
+    {
+        var content = GetStringContent(body);
+        var response = await _client.PostAsync(resource, content);
+        response.EnsureSuccessStatusCode();
+
+        var responseJson = await response.Content.ReadAsStringAsync();
+        var result = JsonConvert.DeserializeObject<T>(responseJson)
+            ?? throw new ApiException($"Could not deserialize post response for resource {resource}.");
+
+        return result;
+    }
+
+    public async Task PutAsync<TBody>(string resource, TBody body)
+    {
+        var content = GetStringContent(body);
+        var response = await _client.PutAsync(resource, content);
+        response.EnsureSuccessStatusCode();
+    }
+
+    public async Task DeleteAsync(string resource, int id)
+    {
+        var response = await _client.DeleteAsync(resource + "/" + id);
+        response.EnsureSuccessStatusCode();
+    }
+
+    private static StringContent GetStringContent<T>(T value)
+    {
+        var bodyJson = JsonConvert.SerializeObject(value);
+        var content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
+
+        return content;
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs
index 2db82cc..04ca545 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs
@@ -1,5 +1,5 @@
-using Newtonsoft.Json;
-using System.Text;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.Services;
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.ViewModels;
 
@@ -7,80 +7,45 @@ namespace WMS.WebUI.Stores;
 
 public class CategoryStore : ICategoryStore
 {
-    private readonly HttpClient _client;
+    private readonly ApiClient _client;
+    private const string RESOURCE = "categories";
 
-    public CategoryStore()
+    public CategoryStore(ApiClient client)
     {
-        _client = new HttpClient();
-        _client.BaseAddress = new Uri("https://localhost:7097/api/");
+        _client = client;
     }
 
     public async Task<CategoryViewModel> CreateCategoryAsync(CategoryViewModel category)
     {
-        var json = JsonConvert.SerializeObject(category);
-        var request = new StringContent(json, Encoding.UTF8, "application/json");
-        var response = await _client.PostAsync("categories", request);
-
-        response.EnsureSuccessStatusCode();
-        
-        var responseJson = await response.Content.ReadAsStringAsync();
-        var createdCategory = JsonConvert.DeserializeObject<CategoryViewModel>(responseJson);
-
-        if (createdCategory is null)
-        {
-            throw new JsonSerializationException("Error serializing Category response from API.");
-        }
+        var result = await _client.PostAsync(RESOURCE, category);
         
-        return createdCategory;
+        return result;
     }
 
     public async Task DeleteCategoryAsync(int id)
     {
-        var response = await _client.DeleteAsync($"categories/{id}");
-
-        response.EnsureSuccessStatusCode();
+        await _client.DeleteAsync(RESOURCE, id);
     }
 
-    public async Task<List<CategoryViewModel>> GetCategoriesAsync(string? search = null)
+    public async Task<PaginatedApiResponse<CategoryViewModel>> GetCategoriesAsync(string? search = null, int? pageNumber = 1)
     {
-        var response = await _client.GetAsync($"categories?search={search}");
-
-        response.EnsureSuccessStatusCode();
+        pageNumber ??= 1;
 
-        var json = await response.Content.ReadAsStringAsync();
-        var categories = JsonConvert.DeserializeObject<List<CategoryViewModel>>(json);
+        var queryParams = $"?search={search}&pageNumber={pageNumber}";
+        var result = await _client.GetAsync<PaginatedApiResponse<CategoryViewModel>>(RESOURCE + queryParams);
 
-        if (categories is null)
-        {
-            throw new JsonSerializationException("Error serializing Category response from API.");
-        }
-
-        return categories;
+        return result;
     }
 
     public async Task<CategoryViewModel> GetCategoryByIdAsync(int id)
     {
-        var response = await _client.GetAsync($"categories/{id}");
+        var category = await _client.GetAsync<CategoryViewModel>($"categories/{id}");
         
-        response.EnsureSuccessStatusCode();
-
-        var json = await response.Content.ReadAsStringAsync();
-        var category = JsonConvert.DeserializeObject<CategoryViewModel>(json);
-
-        if (category is null)
-        {
-            throw new JsonSerializationException("Error serializing Category response from API.");
-        }
-
         return category;
     }
 
     public async Task UpdateCategoryAsync(CategoryViewModel category)
     {
-        var json = JsonConvert.SerializeObject(category);
-        var request = new StringContent(json, Encoding.UTF8, "application/json");
-        var response = await _client.PutAsync($"categories/{category.Id}", request);
-
-        response.EnsureSuccessStatusCode();
+        await _client.PutAsync($"categories/{category.Id}", category);
     }
 }
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs
index 9a4a232..5f73dd9 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs
@@ -1,4 +1,5 @@
 using Newtonsoft.Json;
+using WMS.WebUI.Services;
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.ViewModels;
 
@@ -6,26 +7,16 @@ namespace WMS.WebUI.Stores;
 
 public class DashboardStore : IDashboardStore
 {
-    private readonly HttpClient _client;
+    private readonly ApiClient _client;
 
-    public DashboardStore()
+    public DashboardStore(ApiClient client)
     {
-        _client = new HttpClient();
-        _client.BaseAddress = new Uri("https://localhost:7097/api/");
+        _client = client;
     }
 
     public async Task<DashboardViewModel> Get()
     {
-        var response = await _client.GetAsync("dashboard");
-        response.EnsureSuccessStatusCode();
-
-        var json = await response.Content.ReadAsStringAsync();
-        var dashboard = JsonConvert.DeserializeObject<DashboardViewModel>(json);
-
-        if (dashboard is null)
-        {
-            throw new InvalidCastException("Could not convert json data to Dashboard format");
-        }
+        var dashboard = await _client.GetAsync<DashboardViewModel>("dashboard");
 
         return dashboard;
     }
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs
index f4c6469..54188d0 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICategoryStore.cs
@@ -1,10 +1,11 @@
-using WMS.WebUI.ViewModels;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.ViewModels;
 
 namespace WMS.WebUI.Stores.Interfaces;
 
 public interface ICategoryStore
 {
-    Task<List<CategoryViewModel>> GetCategoriesAsync(string? search = null);
+    Task<PaginatedApiResponse<CategoryViewModel>> GetCategoriesAsync(string? search = null,int? pageNumber = 1);
     Task<CategoryViewModel> GetCategoryByIdAsync(int id);
     Task<CategoryViewModel> CreateCategoryAsync(CategoryViewModel category);
     Task UpdateCategoryAsync(CategoryViewModel category);
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs
index 9de5f36..1ee92eb 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/IProductsStore.cs
@@ -1,12 +1,14 @@
-using WMS.WebUI.ViewModels;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.ViewModels;
 
 namespace WMS.WebUI.Stores.Interfaces;
 
 public interface IProductsStore
 {
-    List<ProductViewModel> GetProducts();
-    ProductViewModel? GetById(int id);
-    ProductViewModel Create(ProductViewModel product);
-    void Update(ProductViewModel product);
-    void Delete(int id);
+    Task<PaginatedApiResponse<ProductViewModel>> GetProducts(ProductQueryParameters queryParameters);
+    Task<ProductViewModel>? GetById(int id);
+    Task<ProductViewModel> Create(ProductViewModel product);
+    Task Update(ProductViewModel product);
+    Task Delete(int id);
 }
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs b/WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs
new file mode 100644
index 0000000..5a80327
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/Mocks/CategoryDto.cs
@@ -0,0 +1,16 @@
+namespace WMS.WebUI.Stores.Mocks
+{
+    public class CategoryDto
+    {
+        public int Id { get; set; }
+        public string Name { get; set; }
+        public string Description { get; set; }
+        public int? ParentId { get; set; }
+        public string? Parent { get; set; }
+        public virtual ICollection<CategoryDto> Children { get; set; }
+        public CategoryDto()
+        {
+            Children = new List<CategoryDto>();
+        }
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs
deleted file mode 100644
index d3fdabb..0000000
--- a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockProductsStore.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using WMS.WebUI.Stores.Interfaces;
-using WMS.WebUI.ViewModels;
-
-namespace WMS.WebUI.Stores.Mocks;
-
-public class MockProductsStore : IProductsStore
-{
-    private static int id = 1;
-    private static readonly List<ProductViewModel> _products = [];
-
-    public ProductViewModel Create(ProductViewModel product)
-    {
-        product.Id = id++;
-        _products.Add(product);
-
-        return product;
-    }
-
-    public void Delete(int id)
-    {
-        var product = _products.FirstOrDefault(x => x.Id == id);
-
-        if (product is null)
-        {
-            return;
-        }
-
-        var index = _products.IndexOf(product);
-
-        if(index > 0)
-        {
-            _products.RemoveAt(index);
-        }
-    }
-
-    public ProductViewModel? GetById(int id)
-    {
-        return _products.FirstOrDefault(x => x.Id == id);
-    }
-
-    public List<ProductViewModel> GetProducts()
-    {
-        return _products.ToList();
-    }
-
-    public void Update(ProductViewModel product)
-    {
-        var productToUpdate = _products.FirstOrDefault(x => x.Id == product.Id);
-        var index = _products.IndexOf(product);
-
-        if (index > 0)
-        {
-            _products[index] = product;
-        }
-    }
-}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs b/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs
new file mode 100644
index 0000000..b7cdae0
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs
@@ -0,0 +1,97 @@
+using System.Text;
+using WMS.WebUI.Constants;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Services;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels;
+
+namespace WMS.WebUI.Stores;
+
+public class ProductStore : IProductsStore
+{
+    private readonly ApiClient _client;
+
+    public ProductStore(ApiClient client)
+    {
+        _client = client;
+    }
+
+    public async Task<ProductViewModel> Create(ProductViewModel product)
+    {
+        var result = await _client.PostAsync(ApiResourceConstants.Products, product);
+        
+        return result;
+    }
+
+    public async Task Delete(int id)
+    {
+        await _client.DeleteAsync(ApiResourceConstants.Products, id);
+    }
+
+    public async Task<PaginatedApiResponse<ProductViewModel>> GetProducts(ProductQueryParameters queryParameters)
+    {
+        var queries = BuildQueryParameters(queryParameters);
+        var url = string.IsNullOrEmpty(queries) ?
+            ApiResourceConstants.Products :
+            ApiResourceConstants.Products + "?" + queries;
+
+        var result = await _client.GetAsync<PaginatedApiResponse<ProductViewModel>>(url);
+
+        return result;
+
+    }
+
+    public async Task<ProductViewModel> GetById(int id)
+    {
+        var result = await _client.GetAsync<ProductViewModel>(ApiResourceConstants.Products + "/" + id);
+
+        return result;
+    }
+
+    public async Task Update(ProductViewModel product)
+    {
+        await _client.PutAsync(ApiResourceConstants.Products, product);
+    }
+
+    private static string BuildQueryParameters(ProductQueryParameters queryParameters)
+    {
+        StringBuilder queryBuilder = new();
+
+        if (queryParameters.PageNumber.HasValue)
+        {
+            queryBuilder.Append($"pageNumber={queryParameters.PageNumber}&");
+        }
+        else
+        {
+            queryBuilder.Append($"pageNumber=1&");
+        }
+
+        if (!string.IsNullOrWhiteSpace(queryParameters.Search))
+        {
+            queryBuilder.Append($"Search={queryParameters.Search}&");
+        }
+
+        if (queryParameters.CategoryId.HasValue)
+        {
+            queryBuilder.Append($"CategoryId={queryParameters.CategoryId}&");
+        }
+
+        if (queryParameters.MinPrice.HasValue)
+        {
+            queryBuilder.Append($"MinPrice={queryParameters.MinPrice}&");
+        }
+
+        if (queryParameters.MaxPrice.HasValue)
+        {
+            queryBuilder.Append($"MaxPrice={queryParameters.MaxPrice}&");
+        }
+
+        if (queryParameters.LowQuantityInStock.HasValue && queryParameters.LowQuantityInStock == true)
+        {
+            queryBuilder = queryBuilder.Append($"LowQuantityInStock={queryParameters.LowQuantityInStock}");
+        }
+
+        return queryBuilder.ToString();
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs
index 68a1716..209b9f8 100644
--- a/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/CategoryViewModel.cs
@@ -1,10 +1,21 @@
-namespace WMS.WebUI.ViewModels;
+using WMS.WebUI.Stores.Mocks;
+
+namespace WMS.WebUI.ViewModels;
 
 public class CategoryViewModel
 {
     public int Id { get; set; }
     public string Name { get; set; }
-    public string? Description { get; set; }
+    public string Description { get; set; }
+    public int? ParentId { get; set; }
+    public string? Parent { get; set; }
+    public virtual ICollection<CategoryDto> Children { get; set; }
+    public virtual ICollection<object> Products { get; set; }
+    public CategoryViewModel()
+    {
+        Children = new List<CategoryDto>();
+        Products = new List<object>();
+    }
 }
 
 // read
diff --git a/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml
index 07762f6..e352236 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Categories/Index.cshtml
@@ -2,6 +2,7 @@
 @{
 }
 
+<br />
 <div class="mb-2">
     <form asp-action="Index">
         <div class="d-flex justfiy-content-between gap-4">
@@ -40,6 +41,45 @@
     </div>
 </div>
 
+<div class="d-flex justify-content-between">
+    <div class="p-2" style="font-size: 14px;">
+        <!-- First page button -->
+        <a class="btn btn-outline-primary rounded-left no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;&lt;</a>
+
+        <!-- Previous page button -->
+        <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;</a>
+
+        <!-- Previous page number -->
+        @if (ViewBag.CurrentPage > 1)
+        {
+            <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })">@(@ViewBag.CurrentPage - 1)</a>
+        }
+
+        <!-- Current page number -->
+        <button type="button" class="btn btn-primary rounded-right no-outline" disabled>@ViewBag.CurrentPage</button>
+
+        <!-- Next page number -->
+        @if (ViewBag.CurrentPage < ViewBag.TotalPages)
+        {
+            <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })">@(@ViewBag.CurrentPage + 1)</a>
+        }
+
+        <!-- Next page button -->
+        <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;</a>
+
+        <!-- Last page button -->
+        <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.TotalPages })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;&gt;</a>
+    </div>
+
+    <div class="p-2">
+        <p class="h6">@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)</p>
+    </div>
+</div>
+
+<br />
+<br />
+<br />
+
 <script id="idCellTemplate" type="text/template">
     <div>
         <a rel='nofollow' href="categories/details/${Id}">${Id}</a>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml
new file mode 100644
index 0000000..80dcf64
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml
@@ -0,0 +1,80 @@
+@model List<WMS.WebUI.ViewModels.ProductViewModel>
+
+<br />
+<div class="mb-4">
+    <form asp-action="Index">
+        <div class="row g-3">
+            <div class="col-md-3">
+                <div class="input-group">
+                    <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
+                    <button type="submit" class="btn btn-primary">
+                        <i class="fa fa-search"></i> Search
+                    </button>
+                </div>
+            </div>
+            <div class="col-md-2">
+                <select class="form-control" name="categoryId" asp-items="@ViewBag.Categories">
+                    <option value="">All Categories</option>
+                </select>
+            </div>
+            <div class="col-md-2">
+                <input type="number" class="form-control" placeholder="Min Sale Price" name="minPrice" value="@ViewBag.MinPrice" />
+            </div>
+            <div class="col-md-2">
+                <input type="number" class="form-control" placeholder="Max Sale Price" name="maxPrice" value="@ViewBag.MaxPrice" />
+            </div>
+            <div class="col-md-1 d-flex justify-content-end">
+                <a asp-action="Create" class="btn btn-outline-success">New +</a>
+            </div>
+        </div>
+    </form>
+</div>
+
+<div class="row">
+    <div class="col-12">
+        <ejs-grid id="products-list"
+                  dataSource="@Model"
+                  gridLines="Vertical"
+                  allowSorting="true">
+            <e-grid-columns>
+                <e-grid-column headerText="Id" field="Id" template="#idCellTemplate" type="Text"></e-grid-column>
+                <e-grid-column headerText="Name" field="Name" type="Text"></e-grid-column>
+                <e-grid-column headerText="Sale Price" field="SalePrice" format="C" type="Number"></e-grid-column>
+                <e-grid-column headerText="Supply Price" field="SupplyPrice" format="C" type="Number"></e-grid-column>
+                <e-grid-column headerText="Quantity In Stock" field="QuantityInStock" type="Number"></e-grid-column>
+                <e-grid-column headerText="Category" field="Category" type="Text"></e-grid-column>
+            </e-grid-columns>
+        </ejs-grid>
+    </div>
+</div>
+
+<div class="d-flex justify-content-between">
+    <div class="p-2" style="font-size: 14px;">
+        <a class="btn btn-outline-primary rounded-left no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;&lt;</a>
+        <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;</a>
+        @if (ViewBag.CurrentPage > 1)
+        {
+            <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })">@(@ViewBag.CurrentPage - 1)</a>
+        }
+        <button type="button" class="btn btn-primary rounded-right no-outline" disabled>@ViewBag.CurrentPage</button>
+        @if (ViewBag.CurrentPage < ViewBag.TotalPages)
+        {
+            <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })">@(@ViewBag.CurrentPage + 1)</a>
+        }
+        <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;</a>
+        <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.TotalPages })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;&gt;</a>
+    </div>
+    <div class="p-2">
+        <p class="h6">@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)</p>
+    </div>
+</div>
+
+<br />
+<br />
+<br />
+
+<script id="idCellTemplate" type="text/template">
+    <div>
+        <a rel='nofollow' href="products/details/${Id}">${Id}</a>
+    </div>
+</script>
diff --git a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj
index 424a883..fabc02c 100644
--- a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj
+++ b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj
@@ -7,6 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
     <PackageReference Include="Syncfusion.EJ2.AspNet.Core" Version="25.2.7" />
     <PackageReference Include="Syncfusion.Licensing" Version="25.2.7" />
   </ItemGroup>
diff --git a/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css b/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css
index a3d0220..6bb9689 100644
--- a/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css
+++ b/WMS.WebUI/WMS.WebUI/wwwroot/css/site.css
@@ -69,9 +69,9 @@ body {
         background-color: #222b33;
     }
 
-        .e-grid .e-gridheader .e-headercell {
-            background-color: #222b33;
-        }
+    .e-gird .e-gridheader .e-headercell {
+        background-color: #222b33;
+    }
 
     .e-grid .e-gridpager {
         background-color: #1a222b;

From a19e2392ea170df1a72d789d8ea1145ecf24fe05 Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Thu, 27 Jun 2024 17:56:42 +0500
Subject: [PATCH 2/7] Add Suplier and Customer VIews

---
 .../Constants/ApiResourceConstants.cs         |   2 +
 .../Controllers/CustomersController.cs        | 131 ++++++++++++++++++
 .../Controllers/ProductsController.cs         | 115 ++++++++++++++-
 .../Controllers/SuppliersController.cs        | 128 +++++++++++++++++
 WMS.WebUI/WMS.WebUI/Program.cs                |   5 +-
 .../QueryParams/BaseQueryParameters.cs        |   9 ++
 .../QueryParams/CustomerQueryParameters.cs    |   7 +
 .../QueryParams/ProductQueryParameters.cs     |   7 +-
 .../QueryParams/SupplierQueryParameters.cs    |   7 +
 WMS.WebUI/WMS.WebUI/Services/ApiClient.cs     |   7 +-
 .../Stores/{ => DataStores}/CategoryStore.cs  |  13 +-
 .../Stores/DataStores/CustomerStore.cs        |  77 ++++++++++
 .../Stores/{ => DataStores}/DashboardStore.cs |   2 +-
 .../Stores/{ => DataStores}/ProductStore.cs   |  15 +-
 .../Stores/DataStores/SupplierStore.cs        |  76 ++++++++++
 .../Stores/Interfaces/ICustomerStore.cs       |  14 ++
 .../Stores/Interfaces/ISupplierStore.cs       |  14 ++
 .../CustomerActionViewModel.cs                |  12 ++
 .../CustomerDisplayViewModel.cs               |  14 ++
 .../WMS.WebUI/ViewModels/ProductViewModel.cs  |   6 +-
 .../SupplierActionViewModel.cs                |  15 ++
 .../SupplierDisplayViewModel.cs               |  13 ++
 .../WMS.WebUI/Views/Categories/Delete.cshtml  |   2 +-
 .../WMS.WebUI/Views/Customers/Create.cshtml   |  59 ++++++++
 .../WMS.WebUI/Views/Customers/Delete.cshtml   |  53 +++++++
 .../WMS.WebUI/Views/Customers/Details.cshtml  |  60 ++++++++
 .../WMS.WebUI/Views/Customers/Edit.cshtml     |  58 ++++++++
 .../WMS.WebUI/Views/Customers/Index.cshtml    |  77 ++++++++++
 .../WMS.WebUI/Views/Products/Create.cshtml    |  72 ++++++++++
 .../WMS.WebUI/Views/Products/Delete.cshtml    |  44 ++++++
 .../WMS.WebUI/Views/Products/Details.cshtml   |  47 +++++++
 .../WMS.WebUI/Views/Products/Edit.cshtml      |  61 ++++++++
 .../WMS.WebUI/Views/Products/Index.cshtml     |  14 +-
 .../WMS.WebUI/Views/Shared/_Sidebar.cshtml    |  36 ++++-
 .../WMS.WebUI/Views/Suppliers/Create.cshtml   |  45 ++++++
 .../WMS.WebUI/Views/Suppliers/Delete.cshtml   |  41 ++++++
 .../WMS.WebUI/Views/Suppliers/Details.cshtml  |  50 +++++++
 .../WMS.WebUI/Views/Suppliers/Edit.cshtml     |  45 ++++++
 .../WMS.WebUI/Views/Suppliers/Index.cshtml    |  77 ++++++++++
 39 files changed, 1491 insertions(+), 39 deletions(-)
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs
 rename WMS.WebUI/WMS.WebUI/Stores/{ => DataStores}/CategoryStore.cs (81%)
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
 rename WMS.WebUI/WMS.WebUI/Stores/{ => DataStores}/DashboardStore.cs (92%)
 rename WMS.WebUI/WMS.WebUI/Stores/{ => DataStores}/ProductStore.cs (83%)
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml

diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
index 6da50ba..66a003c 100644
--- a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
+++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
@@ -4,4 +4,6 @@ public static class ApiResourceConstants
 {
     public const string Products = nameof(Products);
     public const string Categories = nameof(Categories);
+    public const string Customers = nameof(Customers);
+    public const string Suppliers = nameof(Suppliers);
 }
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs b/WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs
new file mode 100644
index 0000000..c7eb58f
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/CustomersController.cs
@@ -0,0 +1,131 @@
+using Microsoft.AspNetCore.Mvc;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.CustomerViewModels;
+
+namespace WMS.WebUI.Controllers;
+
+public class CustomersController(ICustomerStore customerStore) : Controller
+{
+    private readonly ICustomerStore _customerStore = customerStore;
+    public async Task<IActionResult> Index(
+        string? searchString,
+        decimal? balanceGreaterThan,
+        decimal? balanceLessThan,
+        int? pageNumber)
+    {
+        var queryParameters = new CustomerQueryParameters()
+        {
+            Search = searchString,
+            BalanceGreaterThan = balanceGreaterThan,
+            BalanceLessThan = balanceLessThan,
+            PageNumber = pageNumber
+        };
+
+        var customers = await _customerStore.GetCustomers(queryParameters);
+
+        PopulateViewBag(customers, queryParameters);
+
+        return View(customers.Data);
+    }
+    public async Task<IActionResult> Details(int id)
+    {
+        var customer = await _customerStore.GetById(id);
+        return View(customer);
+    }
+    [HttpGet]
+    public async Task<IActionResult> Create()
+    {
+        return View();
+    }
+    [HttpPost]
+    public async Task<IActionResult> Create(CustomerActionViewModel customerActionViewModel)
+    {
+        if (!ModelState.IsValid)
+        {
+            return View(customerActionViewModel);
+        }
+        var createdCustomer = await _customerStore.Create(customerActionViewModel);
+
+        return RedirectToAction(nameof(Details), new { id = createdCustomer.Id });
+    }
+    [HttpGet]
+    public async Task<IActionResult> Edit(int id)
+    {
+        var customer = await _customerStore.GetById(id);
+
+        var customerForEdit = ParseCustomerActionViewModel(customer);
+
+        return View(customerForEdit);
+    }
+    [HttpPost]
+    [ValidateAntiForgeryToken]
+    public async Task<IActionResult> Edit(int id,CustomerActionViewModel customerActionViewModel)
+    {
+        if (!ModelState.IsValid)
+        {
+            return View(customerActionViewModel);
+        } 
+        if(customerActionViewModel.Id != id )
+        {
+            return BadRequest("Does not match id with customer id");
+        }
+
+        await _customerStore.Update(customerActionViewModel);
+
+
+        return RedirectToAction(nameof(Details),new {id = customerActionViewModel.Id});
+    }
+    [HttpGet]
+    public async Task<IActionResult> Delete(int id)
+    {
+        var customer = await _customerStore.GetById(id);
+
+        return View(customer);
+    }
+    [HttpPost,ActionName("Delete")]
+    [ValidateAntiForgeryToken] 
+    public async Task<IActionResult> DeleteConfirmed(int id)
+    {
+        await _customerStore.Delete(id);
+        return RedirectToAction(nameof(Index));
+    }
+    private void PopulateViewBag(PaginatedApiResponse<CustomerDisplayViewModel> customers,CustomerQueryParameters queryParameters)
+    {
+        ViewBag.BalanceLessThan = queryParameters.BalanceLessThan;
+        ViewBag.BalanceGreaterThan= queryParameters.BalanceGreaterThan;
+        ViewBag.SearchString = queryParameters.Search;
+
+        ViewBag.PageSize = customers.PageSize;
+        ViewBag.TotalPages = customers.PagesCount;
+        ViewBag.TotalItems = customers.TotalCount;
+        ViewBag.CurrentPage = customers.CurrentPage;
+        ViewBag.HasPreviousPage = customers.HasPreviousPage;
+        ViewBag.HasNextPage = customers.HasNextPage;
+    }
+    private CustomerActionViewModel ParseCustomerActionViewModel(CustomerDisplayViewModel model)
+    {
+        string[] nameParts = model.FullName.Split(new char[] { ' ' }, 2);
+
+        string firstName = nameParts[0]; // First part is the first name
+
+        // If there's more than one part, the rest is considered the last name
+        string lastName = (nameParts.Length > 1) ? nameParts[1] : "";
+
+        var customerForEdit = new CustomerActionViewModel()
+        {
+            Id = model.Id,
+            FirstName = firstName,
+            LastName = lastName,
+            Balance = model.Balance,
+            Address = model.Address,
+            Discount = model.Discount,
+            PhoneNumber = model.PhoneNumber,
+        };
+        return customerForEdit;
+    }
+    
+}
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs
index 0afd51d..91adc39 100644
--- a/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs
+++ b/WMS.WebUI/WMS.WebUI/Controllers/ProductsController.cs
@@ -1,4 +1,5 @@
-using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Rendering;
 using WMS.WebUI.Models.PaginatedResponse;
 using WMS.WebUI.QueryParams;
@@ -13,21 +14,125 @@ public class ProductsController(IProductsStore store,ICategoryStore categoryStor
     private readonly IProductsStore _productsStore = store ?? throw new ArgumentNullException(nameof(store));
 
     public async Task<IActionResult> Index(
-        string? search,
+        string? searchString,
         int? pageNumber,
         int? categoryId,
         decimal? maxPrice,
         decimal? minPrice,
-        bool? lowQuantityInStock)
+        string? isLowQuantity 
+        )
     {
-        var products = await _productsStore.GetProducts(new ProductQueryParameters());
+        var queryParameters = new ProductQueryParameters()
+        {
+            Search = searchString,
+            PageNumber = pageNumber,
+            CategoryId = categoryId,
+            MaxPrice = maxPrice,
+            MinPrice = minPrice,
+            IsLowQuantity = isLowQuantity == "on",
+        };
+
+        var products = await _productsStore.GetProducts(queryParameters);
+        //Problem CAtegories get with pagination with max pagesize=15, I dont choose 16 category
         var categories = await _categoryStore.GetCategoriesAsync();
 
-        PopulateViewBag(products, search);
+        ViewBag.Categories = new SelectList(categories.Data.OrderBy(x => x.Name), "Id", "Name", categoryId);
+        ViewBag.MinPrice = minPrice;
+        ViewBag.IsLowQuantity = isLowQuantity == "on";
+        ViewBag.MaxPrice = maxPrice;
+        ViewBag.SearchString = searchString;
+
+        PopulateViewBag(products, searchString);
 
         return View(products.Data);
     }
+    public async Task<IActionResult> Details(int id)
+    {
+        var product = await _productsStore.GetById(id);
+        
+        if(product is null)
+            return NotFound();
+
+        return View(product);
+    }
+    public async Task<IActionResult> Create()
+    {
+        var categories = await _categoryStore.GetCategoriesAsync();
+
+        ViewBag.Categories = new SelectList(categories.Data, "Id", "Name");
+        
+        return View();
+    }
+    [HttpPost]
+    [ValidateAntiForgeryToken]
+    public async Task<IActionResult> Create(ProductViewModel product)
+    {
+        if (!ModelState.IsValid)
+        {
+            var categories = await _categoryStore.GetCategoriesAsync();
+
+            ViewBag.Categories = new SelectList(categories.Data, "Id", "Name", categories);
+            return View(product);
+        }
+        var createdProduct = await _productsStore.Create(product);
+        return RedirectToAction(nameof(Details),new { id = createdProduct.Id });
+    }
+    public async Task<IActionResult> Edit(int id)
+    {
+        var product = await _productsStore.GetById(id);
+
+        if (product is null)
+            return NotFound();
+
+        var categories = await _categoryStore.GetCategoriesAsync();
+
+        ViewBag.Categories = new SelectList(categories.Data, "Id", "Name");
+
+        return View(product);
+    }
+    [HttpPost]
+    [ValidateAntiForgeryToken]
+    public async Task<IActionResult> Edit(int id,ProductViewModel product)
+    {
+        if (!ModelState.IsValid)
+        {
+            var categories = await _categoryStore.GetCategoriesAsync();
+            ViewBag.Categories = new SelectList(categories.Data, "Id", "Name");
+
+            return View(product);
+        }
 
+        if (product.Id != id)
+        {
+            return BadRequest("Does not match id with product id");
+        }
+        await _productsStore.Update(product);
+        return RedirectToAction(nameof(Details),new { id = product.Id });
+    }
+
+
+    [HttpGet]
+    public async Task<IActionResult> Delete(int id)
+    {
+        var product = await _productsStore.GetById(id);
+
+        if(product is null)
+            return NotFound();
+
+        return View(product);
+    }
+    [HttpPost(),ActionName(nameof(Delete))]
+    public async Task<IActionResult> DeleteConfirmed(int id)
+    {
+        var product = await _productsStore.GetById(id);
+
+        if (product is null)
+            return NotFound();
+
+        await _productsStore.Delete(id);
+
+        return RedirectToAction(nameof(Index));
+    }
     private void PopulateViewBag(
         PaginatedApiResponse<ProductViewModel> products,
         string? searchString)
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs b/WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs
new file mode 100644
index 0000000..943ad0a
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/SuppliersController.cs
@@ -0,0 +1,128 @@
+using Microsoft.AspNetCore.Mvc;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Stores.DataStores;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SupplierViewModels;
+
+namespace WMS.WebUI.Controllers
+{
+    public class SuppliersController(ISupplierStore store) : Controller
+    {
+        private readonly ISupplierStore _supplierStore = store;
+        public async Task<IActionResult> Index(
+            string? searchString,
+            decimal? balanceGreaterThan,
+            decimal? balanceLessThan,
+            int? pageNumber)
+        {
+            var queryParameters = new SupplierQueryParameters()
+            {
+                Search = searchString,
+                BalanceGreaterThan = balanceGreaterThan,
+                BalanceLessThan = balanceLessThan,
+                PageNumber = pageNumber
+            };
+
+            var suppliers = await _supplierStore.GetSuppliers(queryParameters);
+
+            PopulateViewBag(suppliers, queryParameters);
+
+            return View(suppliers.Data);
+        }
+        public async Task<IActionResult> Details(int id)
+        {
+            var supplier = await _supplierStore.GetById(id);
+            return View(supplier);
+        }
+        [HttpGet]
+        public async Task<IActionResult> Create()
+        {
+            return View();
+        }
+        [HttpPost]
+        public async Task<IActionResult> Create(SupplierActionViewModel supplierActionViewModel)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(supplierActionViewModel);
+            }
+            var createdSupplier = await _supplierStore.Create(supplierActionViewModel);
+
+            return RedirectToAction(nameof(Details), new { id = createdSupplier.Id });
+        }
+        [HttpGet]
+        public async Task<IActionResult> Edit(int id)
+        {
+            var supplier = await _supplierStore.GetById(id);
+
+            var supplierForEdit = ParseSupplierActionViewModel(supplier);
+
+            return View(supplierForEdit);
+        }
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> Edit(int id, SupplierActionViewModel supplierActionViewModel)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(supplierActionViewModel);
+            }
+            if (supplierActionViewModel.Id != id)
+            {
+                return BadRequest("Does not match id with supplier id");
+            }
+
+            await _supplierStore.Update(supplierActionViewModel);
+
+
+            return RedirectToAction(nameof(Details), new { id = supplierActionViewModel.Id });
+        }
+        [HttpGet]
+        public async Task<IActionResult> Delete(int id)
+        {
+            var supplier = await _supplierStore.GetById(id);
+
+            return View(supplier);
+        }
+        [HttpPost, ActionName("Delete")]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> DeleteConfirmed(int id)
+        {
+            await _supplierStore.Delete(id);
+            return RedirectToAction(nameof(Index));
+        }
+        private void PopulateViewBag(PaginatedApiResponse<SupplierDisplayViewModel> suppliers, SupplierQueryParameters queryParameters)
+        {
+            ViewBag.BalanceLessThan = queryParameters.BalanceLessThan;
+            ViewBag.BalanceGreaterThan= queryParameters.BalanceGreaterThan;
+            ViewBag.SearchString = queryParameters.Search;
+
+            ViewBag.PageSize = suppliers.PageSize;
+            ViewBag.TotalPages = suppliers.PagesCount;
+            ViewBag.TotalItems = suppliers.TotalCount;
+            ViewBag.CurrentPage = suppliers.CurrentPage;
+            ViewBag.HasPreviousPage = suppliers.HasPreviousPage;
+            ViewBag.HasNextPage = suppliers.HasNextPage;
+        }
+        private SupplierActionViewModel ParseSupplierActionViewModel(SupplierDisplayViewModel model)
+        {
+            string[] nameParts = model.FullName.Split(new char[] { ' ' }, 2);
+
+            string firstName = nameParts[0]; // First part is the first name
+
+            // If there's more than one part, the rest is considered the last name
+            string lastName = (nameParts.Length > 1) ? nameParts[1] : "";
+
+            var supplierForEdit = new SupplierActionViewModel()
+            {
+                Id = model.Id,
+                FirstName = firstName,
+                LastName = lastName,
+                Balance = model.Balance,
+                PhoneNumber = model.PhoneNumber,
+            };
+            return supplierForEdit;
+        }
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs
index 57d4167..faa76cc 100644
--- a/WMS.WebUI/WMS.WebUI/Program.cs
+++ b/WMS.WebUI/WMS.WebUI/Program.cs
@@ -1,5 +1,5 @@
 using WMS.WebUI.Services;
-using WMS.WebUI.Stores;
+using WMS.WebUI.Stores.DataStores;
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.Stores.Mocks;
 
@@ -10,6 +10,9 @@
 builder.Services.AddScoped<IDashboardStore, DashboardStore>();
 builder.Services.AddScoped<ICategoryStore, CategoryStore>();
 builder.Services.AddScoped<IProductsStore, ProductStore>();
+builder.Services.AddScoped<ICustomerStore,CustomerStore>();
+builder.Services.AddScoped<ISupplierStore,SupplierStore>();
+
 builder.Services.AddSingleton<ApiClient>();
 
 Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ;
diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs
new file mode 100644
index 0000000..b57e589
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/QueryParams/BaseQueryParameters.cs
@@ -0,0 +1,9 @@
+namespace WMS.WebUI.QueryParams
+{
+    public abstract class BaseQueryParameters
+    {
+        public string? Search { get; set; }
+        public int? PageNumber { get; set; } = 1;
+        public int? PageSize { get; set; } = 15;
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs
new file mode 100644
index 0000000..d105a6c
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/QueryParams/CustomerQueryParameters.cs
@@ -0,0 +1,7 @@
+namespace WMS.WebUI.QueryParams;
+
+public class CustomerQueryParameters : BaseQueryParameters
+{
+    public decimal? BalanceGreaterThan { get; set; }
+    public decimal? BalanceLessThan { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs
index 43afcf7..b4d0ea4 100644
--- a/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs
+++ b/WMS.WebUI/WMS.WebUI/QueryParams/ProductQueryParameters.cs
@@ -1,12 +1,9 @@
 namespace WMS.WebUI.QueryParams;
 
-public class ProductQueryParameters
+public class ProductQueryParameters : BaseQueryParameters
 {
-    public string? Search { get; set; }
     public int? CategoryId { get; set; }
-    public int? PageNumber { get; set; }
-    public int? PageSize { get; set; } = 10;
     public decimal? MaxPrice { get; set; }
     public decimal? MinPrice { get; set; }
-    public bool? LowQuantityInStock { get; set; }
+    public bool? IsLowQuantity { get; set; }
 }
diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs
new file mode 100644
index 0000000..8b3c68b
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/QueryParams/SupplierQueryParameters.cs
@@ -0,0 +1,7 @@
+namespace WMS.WebUI.QueryParams;
+
+public class SupplierQueryParameters : BaseQueryParameters
+{
+    public decimal? BalanceGreaterThan { get; set; }
+    public decimal? BalanceLessThan { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs
index aae3a41..08f84d6 100644
--- a/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs
+++ b/WMS.WebUI/WMS.WebUI/Services/ApiClient.cs
@@ -12,15 +12,14 @@ public ApiClient()
     {
         _client = new()
         {
-            BaseAddress = new Uri("https://localhost:7097/api/")
+            BaseAddress = new Uri("https://localhost:7108/api/")
         };
     }
 
     public async Task<T> GetAsync<T>(string resource)
     {
         var response = await _client.GetAsync(resource);
-        response.EnsureSuccessStatusCode();
-
+        
         response.EnsureSuccessStatusCode();
 
         var json = await response.Content.ReadAsStringAsync();
@@ -30,7 +29,7 @@ public async Task<T> GetAsync<T>(string resource)
         return result;
     }
 
-    public async Task<T> PostAsync<T>(string resource, T body)
+    public async Task<T> PostAsync<T,TBody>(string resource, TBody body)
     {
         var content = GetStringContent(body);
         var response = await _client.PostAsync(resource, content);
diff --git a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs
similarity index 81%
rename from WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs
rename to WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs
index 04ca545..5aee98d 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/CategoryStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CategoryStore.cs
@@ -1,14 +1,15 @@
-using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.Constants;
+using WMS.WebUI.Models.PaginatedResponse;
 using WMS.WebUI.Services;
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.ViewModels;
 
-namespace WMS.WebUI.Stores;
+namespace WMS.WebUI.Stores.DataStores;
 
 public class CategoryStore : ICategoryStore
 {
     private readonly ApiClient _client;
-    private const string RESOURCE = "categories";
+    private const string RESOURCE = ApiResourceConstants.Categories;
 
     public CategoryStore(ApiClient client)
     {
@@ -17,8 +18,8 @@ public CategoryStore(ApiClient client)
 
     public async Task<CategoryViewModel> CreateCategoryAsync(CategoryViewModel category)
     {
-        var result = await _client.PostAsync(RESOURCE, category);
-        
+        var result = await _client.PostAsync<CategoryViewModel,CategoryViewModel>(RESOURCE, category);
+
         return result;
     }
 
@@ -40,7 +41,7 @@ public async Task<PaginatedApiResponse<CategoryViewModel>> GetCategoriesAsync(st
     public async Task<CategoryViewModel> GetCategoryByIdAsync(int id)
     {
         var category = await _client.GetAsync<CategoryViewModel>($"categories/{id}");
-        
+
         return category;
     }
 
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
new file mode 100644
index 0000000..063ea23
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
@@ -0,0 +1,77 @@
+using System.Reflection.Metadata.Ecma335;
+using System.Runtime.InteropServices;
+using System.Text;
+using WMS.WebUI.Constants;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Services;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.CustomerViewModels;
+
+namespace WMS.WebUI.Stores.DataStores;
+
+public class CustomerStore(ApiClient apiClient) : ICustomerStore
+{
+    private readonly ApiClient _apiClient = apiClient;
+    public async Task<CustomerDisplayViewModel> Create(CustomerActionViewModel customer)
+    {
+        var createdCustomer = await _apiClient.PostAsync<CustomerDisplayViewModel
+            ,CustomerActionViewModel>(ApiResourceConstants.Customers,customer);
+
+        return createdCustomer;
+    }
+
+    public async Task Delete(int id)
+    {
+        await _apiClient.DeleteAsync(ApiResourceConstants.Customers,id);
+    }
+
+    public async Task<CustomerDisplayViewModel> GetById(int id)
+    {
+        var customer = await _apiClient.GetAsync<CustomerDisplayViewModel>(ApiResourceConstants.Customers + "/" + id);
+        return customer;
+    }
+
+    public async Task<PaginatedApiResponse<CustomerDisplayViewModel>> GetCustomers(CustomerQueryParameters queryParameters)
+    {
+        var query = BuildQueryParameters(queryParameters);
+
+        var url = string.IsNullOrEmpty(query) ?
+          ApiResourceConstants.Customers :
+          ApiResourceConstants.Customers + "?" + query;
+
+        var customers = await _apiClient.GetAsync<PaginatedApiResponse<CustomerDisplayViewModel>>(url);
+
+        return customers;
+    }
+
+    public async Task Update(CustomerActionViewModel customer)
+    {
+        await _apiClient.PutAsync(ApiResourceConstants.Customers, customer);
+    }
+    private string BuildQueryParameters(CustomerQueryParameters queryParameters)
+    {
+        var query = new StringBuilder();
+        if (queryParameters.PageNumber.HasValue)
+        {
+            query.Append($"pageNumber={queryParameters.PageNumber}&");
+        }
+        else
+        {
+            query.Append($"pageNumber=1&");
+        }
+        if (!string.IsNullOrWhiteSpace(queryParameters.Search))
+        {
+            query.Append($"Search={queryParameters.Search}&");
+        }
+        if (queryParameters.BalanceGreaterThan.HasValue)
+        {
+            query.Append($"BalanceGreaterThan={queryParameters.BalanceGreaterThan}&");
+        }
+        if (queryParameters.BalanceLessThan.HasValue)
+        {
+            query.Append($"BalanceLessThan={queryParameters.BalanceLessThan}&");
+        }
+        return query.ToString();
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs
similarity index 92%
rename from WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs
rename to WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs
index 5f73dd9..1672f53 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DashboardStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/DashboardStore.cs
@@ -3,7 +3,7 @@
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.ViewModels;
 
-namespace WMS.WebUI.Stores;
+namespace WMS.WebUI.Stores.DataStores;
 
 public class DashboardStore : IDashboardStore
 {
diff --git a/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs
similarity index 83%
rename from WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs
rename to WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs
index b7cdae0..a5f81f1 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/ProductStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/ProductStore.cs
@@ -6,7 +6,7 @@
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.ViewModels;
 
-namespace WMS.WebUI.Stores;
+namespace WMS.WebUI.Stores.DataStores;
 
 public class ProductStore : IProductsStore
 {
@@ -19,9 +19,9 @@ public ProductStore(ApiClient client)
 
     public async Task<ProductViewModel> Create(ProductViewModel product)
     {
-        var result = await _client.PostAsync(ApiResourceConstants.Products, product);
-        
-        return result;
+        var result = await _client.PostAsync<ProductViewModel,ProductViewModel>(ApiResourceConstants.Products, product);
+
+        return result;  
     }
 
     public async Task Delete(int id)
@@ -39,7 +39,6 @@ public async Task<PaginatedApiResponse<ProductViewModel>> GetProducts(ProductQue
         var result = await _client.GetAsync<PaginatedApiResponse<ProductViewModel>>(url);
 
         return result;
-
     }
 
     public async Task<ProductViewModel> GetById(int id)
@@ -51,7 +50,7 @@ public async Task<ProductViewModel> GetById(int id)
 
     public async Task Update(ProductViewModel product)
     {
-        await _client.PutAsync(ApiResourceConstants.Products, product);
+        await _client.PutAsync(ApiResourceConstants.Products + "/" + product.Id, product);
     }
 
     private static string BuildQueryParameters(ProductQueryParameters queryParameters)
@@ -87,9 +86,9 @@ private static string BuildQueryParameters(ProductQueryParameters queryParameter
             queryBuilder.Append($"MaxPrice={queryParameters.MaxPrice}&");
         }
 
-        if (queryParameters.LowQuantityInStock.HasValue && queryParameters.LowQuantityInStock == true)
+        if (queryParameters.IsLowQuantity.HasValue && queryParameters.IsLowQuantity == true)
         {
-            queryBuilder = queryBuilder.Append($"LowQuantityInStock={queryParameters.LowQuantityInStock}");
+            queryBuilder = queryBuilder.Append($"IsLowQuantity={queryParameters.IsLowQuantity}");
         }
 
         return queryBuilder.ToString();
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs
new file mode 100644
index 0000000..7035584
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs
@@ -0,0 +1,76 @@
+using System.Text;
+using WMS.WebUI.Constants;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Services;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SupplierViewModels;
+
+namespace WMS.WebUI.Stores.DataStores;
+
+public class SupplierStore(ApiClient apiClient) : ISupplierStore
+{
+    private readonly ApiClient _apiClient = apiClient;
+    public async Task<SupplierDisplayViewModel> Create(SupplierActionViewModel supplier)
+    {
+        var createdSupplier = await _apiClient.PostAsync<SupplierDisplayViewModel
+            ,SupplierActionViewModel>(ApiResourceConstants.Suppliers, supplier);
+
+        return createdSupplier;
+    }
+
+    public async Task Delete(int id)
+    {
+        await _apiClient.DeleteAsync(ApiResourceConstants.Suppliers,id);
+    }
+
+    public async Task<SupplierDisplayViewModel> GetById(int id)
+    {
+        var supplier = await _apiClient.GetAsync<SupplierDisplayViewModel>(ApiResourceConstants.Suppliers + "/" + id);
+        return supplier;
+    }
+
+    public async Task<PaginatedApiResponse<SupplierDisplayViewModel>> GetSuppliers(SupplierQueryParameters queryParameters)
+    {
+        var query = BuildQueryParameters(queryParameters);
+
+        var url = string.IsNullOrEmpty(query) ?
+          ApiResourceConstants.Suppliers :
+          ApiResourceConstants.Suppliers + "?" + query;
+
+        var suppliers = await _apiClient.GetAsync<PaginatedApiResponse<SupplierDisplayViewModel>>(url);
+
+        return suppliers;
+    }
+
+    public async Task Update(SupplierActionViewModel supplier)
+    {
+        await _apiClient.PutAsync(ApiResourceConstants.Suppliers, supplier);
+    }
+    private string BuildQueryParameters(SupplierQueryParameters queryParameters)
+    {
+        var query = new StringBuilder();
+        if (queryParameters.PageNumber.HasValue)
+        {
+            query.Append($"pageNumber={queryParameters.PageNumber}&");
+        }
+        else
+        {
+            query.Append($"pageNumber=1&");
+        }
+        if (!string.IsNullOrWhiteSpace(queryParameters.Search))
+        {
+            query.Append($"Search={queryParameters.Search}&");
+        }
+        if (queryParameters.BalanceGreaterThan.HasValue)
+        {
+            query.Append($"BalanceGreaterThan={queryParameters.BalanceGreaterThan}&");
+        }
+        if (queryParameters.BalanceLessThan.HasValue)
+        {
+            query.Append($"BalanceLessThan={queryParameters.BalanceLessThan}&");
+        }
+
+        return query.ToString();
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs
new file mode 100644
index 0000000..4b5d1ca
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ICustomerStore.cs
@@ -0,0 +1,14 @@
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.ViewModels.CustomerViewModels;
+
+namespace WMS.WebUI.Stores.Interfaces;
+
+public interface ICustomerStore
+{
+    Task<PaginatedApiResponse<CustomerDisplayViewModel>> GetCustomers(CustomerQueryParameters queryParameters);
+    Task<CustomerDisplayViewModel>GetById(int id);
+    Task<CustomerDisplayViewModel> Create(CustomerActionViewModel customer);
+    Task Update(CustomerActionViewModel customer);
+    Task Delete(int id);
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs
new file mode 100644
index 0000000..44a2188
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplierStore.cs
@@ -0,0 +1,14 @@
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.ViewModels.SupplierViewModels;
+
+namespace WMS.WebUI.Stores.Interfaces;
+
+public interface ISupplierStore
+{
+    Task<PaginatedApiResponse<SupplierDisplayViewModel>> GetSuppliers(SupplierQueryParameters queryParameters);
+    Task<SupplierDisplayViewModel> GetById(int id);
+    Task<SupplierDisplayViewModel> Create(SupplierActionViewModel supplier);
+    Task Update(SupplierActionViewModel supplier);
+    Task Delete(int id);
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs
new file mode 100644
index 0000000..6aedcce
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs
@@ -0,0 +1,12 @@
+namespace WMS.WebUI.ViewModels.CustomerViewModels;
+
+public class CustomerActionViewModel
+{
+    public int Id { get; set; }
+    public string FirstName { get; set; }
+    public string LastName { get; set; }
+    public string PhoneNumber { get; set; }
+    public string Address { get; set; }
+    public decimal Balance { get; set; }
+    public decimal? Discount { get; set; } = 0;
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs
new file mode 100644
index 0000000..11fe7e1
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs
@@ -0,0 +1,14 @@
+namespace WMS.WebUI.ViewModels.CustomerViewModels
+{
+    public class CustomerDisplayViewModel
+    {
+        public int Id { get; set; }
+        public string FullName { get; set; }
+        public string PhoneNumber { get; set; }
+        public string Address { get; set; }
+        public decimal Balance { get; set; }
+        public decimal? Discount { get; set; } = 0;
+        //public ICollection<SaleDto> Sales { get; set; }
+        
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs
index ea736c6..a59fd76 100644
--- a/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/ProductViewModel.cs
@@ -1,4 +1,6 @@
-namespace WMS.WebUI.ViewModels;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+
+namespace WMS.WebUI.ViewModels;
 
 public class ProductViewModel
 {
@@ -9,7 +11,7 @@ public class ProductViewModel
     public decimal SupplyPrice { get; set; }
     public int QuantityInStock { get; set; }
     public int LowQuantityAmount { get; set; }
-
+    [ValidateNever]
     public string Category { get; set; }
     public int CategoryId { get; set; }
 }
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs
new file mode 100644
index 0000000..5d0bade
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs
@@ -0,0 +1,15 @@
+namespace WMS.WebUI.ViewModels.SupplierViewModels;
+
+public class SupplierActionViewModel
+{
+    public int Id { get; set; }
+    public string FirstName { get; set; }
+    public string LastName { get; set; }
+    public string PhoneNumber { get; set; }
+    public decimal Balance { get; set; }
+    //public ICollection<SupplyDto> Supplies { get; set; }
+    //public SupplierDto()
+    //{
+    //    Supplies = new List<SupplyDto>();
+    //}
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs
new file mode 100644
index 0000000..e990e29
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierDisplayViewModel.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel;
+
+namespace WMS.WebUI.ViewModels.SupplierViewModels;
+
+public class SupplierDisplayViewModel
+{
+    public int Id { get; set; }
+    [DisplayName("Full name")]
+    public string FullName{ get; set; }
+    [DisplayName("Phone number")]
+    public string PhoneNumber { get; set; }
+    public decimal Balance { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml
index 41959fc..b77efc5 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Categories/Delete.cshtml
@@ -20,7 +20,7 @@
         <dt class="col-sm-2">
             @Html.DisplayNameFor(model => model.Description)
         </dt>
-        <dd class="col-sm-10">
+        <dd class="col-sm-10">  
             @Html.DisplayFor(model => model.Description)
         </dd>
     </dl>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml
new file mode 100644
index 0000000..4610820
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Create.cshtml
@@ -0,0 +1,59 @@
+@model WMS.WebUI.ViewModels.CustomerViewModels.CustomerActionViewModel
+
+@{
+    ViewData["Title"] = "Create Customer";
+}
+<h2 class="m-5"> Create Customer </h2>
+<hr />  
+
+<div class="row m-5">
+    <div class="col-md-6">
+        <form asp-action="Create" method="post">
+            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
+            <div class="form-group">
+                <label asp-for="FirstName"></label>
+                <input asp-for="FirstName" class="form-control" />
+                <span asp-validation-for="FirstName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="LastName"></label>
+                <input asp-for="LastName" class="form-control" />
+                <span asp-validation-for="LastName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Address"></label>
+                <input asp-for="Address" type="text" class="form-control" />
+                <span asp-validation-for="Address" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Balance"></label>
+                <input asp-for="Balance" class="form-control" />
+                <span asp-validation-for="Balance" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="PhoneNumber"></label>
+                <input asp-for="PhoneNumber" type="tel" class="form-control" />
+                <span asp-validation-for="PhoneNumber" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Discount"></label>
+                <input asp-for="Discount" type="number" class="form-control" />
+                <span asp-validation-for="Discount" class="text-danger"></span>
+            </div>
+            <div class="form-group mt-5">
+                <a asp-action="Index" class="btn btn-outline-info">
+                    Back
+                </a>
+                <button type="submit" class="btn btn-success">
+                    Save
+                </button>
+            </div>
+        </form>
+    </div>
+</div>
+
+@section Scripts {
+    @{
+        await Html.RenderPartialAsync("_ValidationScriptsPartial");
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml
new file mode 100644
index 0000000..0145260
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Delete.cshtml
@@ -0,0 +1,53 @@
+@using WMS.WebUI.ViewModels.CustomerViewModels;
+@model CustomerDisplayViewModel;
+
+<h3 class="m-5"> Are you sure want to delete ?</h3>
+<hr />
+
+<div class="m-5">
+    <dl class="row">
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Id)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Id)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.FullName)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.FullName)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.PhoneNumber)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.PhoneNumber)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Address)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Address)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Balance)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Balance)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Discount)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Discount)
+        </dd>
+    </dl>
+</div>
+
+<form asp-action="Delete" method="post" class="m-5">
+    <div class="form-group">
+        <a asp-action="Index" class="btn btn-outline-info">Back</a>
+        <button asp-route-id="@Model.Id" type="submit" class="btn btn-danger">Delete</button>
+    </div>
+</form>
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml
new file mode 100644
index 0000000..9edcc2a
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Details.cshtml
@@ -0,0 +1,60 @@
+@using WMS.WebUI.ViewModels.CustomerViewModels;
+@model CustomerDisplayViewModel;
+
+<div class="m-5">
+    <h4> Supplier details </h4>
+
+    <hr />
+
+    <dl class="row">
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Id)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Id)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.FullName)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.FullName)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.PhoneNumber)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.PhoneNumber)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Address)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Address)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Balance)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Balance)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Discount)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Discount)
+        </dd>
+
+    </dl>
+    <div class="m-1">
+        <a asp-action="Index" class="btn btn-info fa-solid fa-arrow-left">
+            Back
+        </a>
+        <a asp-action="Edit" asp-route-id="@Model?.Id" class="btn btn-outline-warning fa-solid fa-pen">
+            Edit
+        </a>
+        <a asp-action="Delete" asp-route-id="@Model?.Id" class="btn btn-outline-danger fa-solid fa-trash">
+            Delete
+        </a>
+    </div>
+
+</div>
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml
new file mode 100644
index 0000000..620d66b
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Edit.cshtml
@@ -0,0 +1,58 @@
+@model WMS.WebUI.ViewModels.CustomerViewModels.CustomerActionViewModel
+
+@{
+    ViewData["Title"] = "Edit Customer";
+}
+
+
+<div class="row m-5">
+    <div class="col-md-8">
+        <form asp-action="Edit" method="post">
+            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
+            <div class="form-group">
+                <label asp-for="FirstName"></label>
+                <input asp-for="FirstName" class="form-control" />
+                <span asp-validation-for="FirstName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="LastName"></label>
+                <input asp-for="LastName" class="form-control" />
+                <span asp-validation-for="LastName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Address"></label>
+                <input asp-for="Address" type="text" class="form-control" />
+                <span asp-validation-for="Address" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Balance"></label>
+                <input asp-for="Balance" type="number"  class="form-control" />
+                <span asp-validation-for="Balance" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="PhoneNumber"></label>
+                <input asp-for="PhoneNumber" type="tel" class="form-control" />
+                <span asp-validation-for="PhoneNumber" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Discount"></label>
+                <input asp-for="Discount" type="number" class="form-control" />
+                <span asp-validation-for="Discount" class="text-danger"></span>
+            </div>
+            <div class="form-group mt-5">
+                <a asp-action="Index" class="btn btn-outline-info">
+                    Back
+                </a>
+                <button type="submit" class="btn btn-success">
+                    Save
+                </button>
+            </div>
+        </form>
+    </div>
+</div>
+
+@section Scripts {
+    @{
+        await Html.RenderPartialAsync("_ValidationScriptsPartial");
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml
new file mode 100644
index 0000000..7b64e43
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml
@@ -0,0 +1,77 @@
+@using WMS.WebUI.ViewModels.CustomerViewModels
+@model IEnumerable<CustomerDisplayViewModel>
+
+<div class="mb-4 ms-2">
+    <form asp-action="Index" method="get">
+        <div class="row g-3 align-items-center">
+            <div class="col-md-3">
+                <div class="input-group">
+                    <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
+                    <button type="submit" class="btn btn-primary">
+                        <i class="fa fa-search"></i> Search
+                    </button>
+                </div>
+            </div>
+
+            <div class="col-md-2">
+                <input type="number" class="form-control" placeholder="Balance greater than" name="balanceGreaterThan" value="@ViewBag.BalanceGreaterThan" />
+            </div>
+            
+            <div class="col-md-2">
+                <input type="number" class="form-control" placeholder="Balance less than" name="balanceLessThan" value="@ViewBag.BalanceLessThan" />
+            </div>
+
+            <div class="col-md-1 d-flex justify-content-end">
+                <a asp-action="Create" asp-controller="customers" class="btn btn-outline-success">New +</a>
+            </div>
+
+        </div>
+    </form>
+</div>
+
+<div class="container">
+    <div class="row">
+        <div class="col-12">
+            <ejs-grid id="customers-list"
+                      dataSource="@Model"
+                      gridLines="Vertical"
+                      allowSorting="true">
+                <e-grid-columns>
+                    <e-grid-column headerText="Id" field="Id" template="#idCellTemplate" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Full Name" field="FullName" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Phone Number" field="PhoneNumber" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Balance" field="Balance" format="C" type="Number"></e-grid-column>
+                </e-grid-columns>
+            </ejs-grid>
+        </div>
+    </div>
+</div>
+
+<div class="container mt-4">
+    <div class="d-flex justify-content-between align-items-center">
+        <div>
+            <a class="btn btn-outline-primary rounded-left no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;&lt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;</a>
+            @if (ViewBag.CurrentPage > 1)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })">@(@ViewBag.CurrentPage - 1)</a>
+            }
+            <button type="button" class="btn btn-primary rounded-right no-outline" disabled>@ViewBag.CurrentPage</button>
+            @if (ViewBag.CurrentPage < ViewBag.TotalPages)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })">@(@ViewBag.CurrentPage + 1)</a>
+            }
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.TotalPages })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;&gt;</a>
+        </div>
+        <div>
+            <p class="h6 mb-0">@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)</p>
+        </div>
+    </div>
+</div>
+
+<script id="idCellTemplate" type="text/template">
+    <div>
+        <a rel="nofollow" href="Customers/details/${Id}">${Id}</a>
+    </div>
+</script>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml
new file mode 100644
index 0000000..3a352d9
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml
@@ -0,0 +1,72 @@
+@model WMS.WebUI.ViewModels.ProductViewModel
+
+@{
+    ViewData["Title"] = "Create Product";
+}
+
+<div class="m-5">
+    <h4>Create Product</h4>
+    <hr />
+
+    <form asp-action="Create">
+        <div class="form-group row">
+            <label asp-for="Name" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <input asp-for="Name" class="form-control" />
+                <span asp-validation-for="Name" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label asp-for="Description" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <textarea asp-for="Description" class="form-control"></textarea>
+                <span asp-validation-for="Description" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label asp-for="SalePrice" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <input asp-for="SalePrice" class="form-control" />
+                <span asp-validation-for="SalePrice" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label asp-for="SupplyPrice" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <input asp-for="SupplyPrice" class="form-control" />
+                <span asp-validation-for="SupplyPrice" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label asp-for="QuantityInStock" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <input asp-for="QuantityInStock" class="form-control" />
+                <span asp-validation-for="QuantityInStock" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label asp-for="LowQuantityAmount" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <input asp-for="LowQuantityAmount" class="form-control" />
+                <span asp-validation-for="LowQuantityAmount" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group row">
+            <label asp-for="CategoryId" class="col-sm-2 col-form-label"></label>
+            <div class="col-sm-10">
+                <select asp-for="CategoryId" class="form-control" asp-items="ViewBag.Categories"></select>
+                <span asp-validation-for="CategoryId" class="text-danger"></span>
+            </div>
+        </div>
+        <div class="form-group mt-3">
+            <input type="submit" value="Create" class="btn btn-primary" />
+            <a asp-action="Index" class="btn btn-secondary">Back to List</a>
+        </div>
+    </form>
+</div>
+
+@section Scripts {
+    @{
+        await Html.RenderPartialAsync("_ValidationScriptsPartial");
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml
new file mode 100644
index 0000000..d16a613
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Delete.cshtml
@@ -0,0 +1,44 @@
+@model WMS.WebUI.ViewModels.ProductViewModel
+
+@{
+    ViewData["Title"] = "Delete Product";
+}
+<br />
+<h2>Delete Product</h2>
+
+<hr />
+<div class="row">
+    <div class="col-md-10 offset-md-1">
+        <h4>Are you sure you want to delete this product?</h4>
+        <br />
+        <dl class="row">
+            <dt class="col-sm-3">Name</dt>
+            <dd class="col-sm-9">@Model.Name</dd>
+
+            <dt class="col-sm-3">Description</dt>
+            <dd class="col-sm-9">@Model.Description</dd>
+
+            <dt class="col-sm-3">Sale Price</dt>
+            <dd class="col-sm-9">@Model.SalePrice.ToString("C")</dd>
+
+            <dt class="col-sm-3">Supply Price</dt>
+            <dd class="col-sm-9">@Model.SupplyPrice.ToString("C")</dd>
+
+            <dt class="col-sm-3">Quantity In Stock</dt>
+            <dd class="col-sm-9">@Model.QuantityInStock</dd>
+
+            <dt class="col-sm-3">Low Quantity Amount</dt>
+            <dd class="col-sm-9">@Model.LowQuantityAmount</dd>
+
+            <dt class="col-sm-3">Category</dt>
+            <dd class="col-sm-9">@Model.Category</dd>
+        </dl>
+        <form asp-action="Delete">
+            <input type="hidden" asp-for="Id" />
+            <div class="form-group mt-3">
+                <input type="submit" value="Delete" class="btn btn-danger" />
+                <a asp-action="Index" class="btn btn-secondary">Cancel</a>
+            </div>
+        </form>
+    </div>
+</div>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml
new file mode 100644
index 0000000..d75203e
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Details.cshtml
@@ -0,0 +1,47 @@
+@model WMS.WebUI.ViewModels.ProductViewModel
+
+@{
+    ViewData["Title"] = "Product Details";
+}
+
+<h2>Product Details</h2>
+
+<hr />
+<div class="row">
+    <div class="col-md-10 offset-md-1">
+        <dl class="row">
+            <dt class="col-sm-3">Name</dt>
+            <dd class="col-sm-9">@Model.Name</dd>
+
+            <dt class="col-sm-3">Description</dt>
+            <dd class="col-sm-9">@Model.Description</dd>
+
+            <dt class="col-sm-3">Sale Price</dt>
+            <dd class="col-sm-9">@Model.SalePrice.ToString("C")</dd>
+
+            <dt class="col-sm-3">Supply Price</dt>
+            <dd class="col-sm-9">@Model.SupplyPrice.ToString("C")</dd>
+
+            <dt class="col-sm-3">Quantity In Stock</dt>
+            <dd class="col-sm-9">@Model.QuantityInStock</dd>
+
+            <dt class="col-sm-3">Low Quantity Amount</dt>
+            <dd class="col-sm-9">@Model.LowQuantityAmount</dd>
+
+            <dt class="col-sm-3">Category</dt>
+            <dd class="col-sm-9">@Model.Category</dd>
+        </dl>
+
+        <div class="m-5">
+            <a asp-action="Index" class="btn btn-info fa-solid fa-arrow-left">
+                Back
+            </a>
+            <a asp-action="Edit" asp-route-id="@Model?.Id" class="btn btn-outline-warning fa-solid fa-pen">
+                Edit
+            </a>
+            <a asp-action="Delete" asp-route-id="@Model?.Id" class="btn btn-outline-danger fa-solid fa-trash">
+                Delete
+            </a>
+        </div>
+    </div>
+</div>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml
new file mode 100644
index 0000000..ad33f58
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Edit.cshtml
@@ -0,0 +1,61 @@
+@model WMS.WebUI.ViewModels.ProductViewModel
+
+@{
+    ViewData["Title"] = "Edit Product";
+}
+
+<h2>Edit Product</h2>
+
+<hr />
+<div class="row">
+    <div class="col-md-6 offset-md-3">
+        <form asp-action="Edit">
+            <input type="hidden" asp-for="Id" />
+            <div class="form-group">
+                <label asp-for="Name" class="control-label"></label>
+                <input asp-for="Name" class="form-control" />
+                <span asp-validation-for="Name" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Description" class="control-label"></label>
+                <textarea asp-for="Description" class="form-control"></textarea>
+                <span asp-validation-for="Description" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="SalePrice" class="control-label"></label>
+                <input asp-for="SalePrice" class="form-control" />
+                <span asp-validation-for="SalePrice" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="SupplyPrice" class="control-label"></label>
+                <input asp-for="SupplyPrice" class="form-control" />
+                <span asp-validation-for="SupplyPrice" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="QuantityInStock" class="control-label"></label>
+                <input asp-for="QuantityInStock" class="form-control" />
+                <span asp-validation-for="QuantityInStock" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="LowQuantityAmount" class="control-label"></label>
+                <input asp-for="LowQuantityAmount" class="form-control" />
+                <span asp-validation-for="LowQuantityAmount" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="CategoryId" class="control-label"></label>
+                <select asp-for="CategoryId" class="form-control" asp-items="ViewBag.Categories"></select>
+                <span asp-validation-for="CategoryId" class="text-danger"></span>
+            </div>
+            <div class="form-group mt-3">
+                <input type="submit" value="Save" class="btn btn-primary" />
+                <a asp-action="Index" class="btn btn-secondary">Back to List</a>
+            </div>
+        </form>
+    </div>
+</div>
+
+@section Scripts {
+    @{
+        await Html.RenderPartialAsync("_ValidationScriptsPartial");
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml
index 80dcf64..314f21d 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Index.cshtml
@@ -2,8 +2,8 @@
 
 <br />
 <div class="mb-4">
-    <form asp-action="Index">
-        <div class="row g-3">
+    <form asp-action="Index" method="get">
+        <div class="row g-3 align-items-center">
             <div class="col-md-3">
                 <div class="input-group">
                     <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
@@ -23,8 +23,16 @@
             <div class="col-md-2">
                 <input type="number" class="form-control" placeholder="Max Sale Price" name="maxPrice" value="@ViewBag.MaxPrice" />
             </div>
+            <div class="col-md-2">
+                <div class="form-check d-flex align-items-center">
+                    <input class="form-check-input" type="checkbox" name="isLowQuantity" @(ViewBag.IsLowQuantity ? "checked" : "")>
+                    <label class="form-check-label ms-1" for="isLowQuantity">
+                        <i class="fa-solid fa-exclamation-triangle me-1"></i> <span style="font-size: 1.3rem;">Low quantity</span>
+                    </label>
+                </div>
+            </div>
             <div class="col-md-1 d-flex justify-content-end">
-                <a asp-action="Create" class="btn btn-outline-success">New +</a>
+                <a asp-action="Create" asp-controller="products" class="btn btn-outline-success">New +</a>
             </div>
         </div>
     </form>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml
index 41ff20a..e681bcc 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml
@@ -9,7 +9,7 @@
     menuItems.Add(new
     {
         text = "Dashboard",
-        url = "/",
+        url = "/home",
         iconCss = "fa-solid fa-box"
     });
     menuItems.Add(new
@@ -46,13 +46,43 @@
     {
         text = "Transactions",
         url = "#",
-        iconCss = "fa-solid fa-money-bill-transfer"
+        iconCss = "fa-solid fa-money-bill-transfer",
+        items = new List<object>
+        {
+            new
+            {
+                text = "Sales",
+                url = "/sales",
+                iconCss = "fa-solid fa-shopping-cart"
+            },
+            new
+            {
+                text = "Supplies",
+                url = "/supplies",
+                iconCss = "fa-solid fa-truck"
+            }
+        }
     });
     menuItems.Add(new
     {
         text = "Partners",
         url = "#",
-        iconCss = "fa-solid fa-users"
+        iconCss = "fa-solid fa-users",
+        items = new List<object>()
+        {
+            new
+            {
+                text = "Customers",
+                url = "/customers",
+                iconCss = "fa-solid fa-user-friends"
+            },
+            new
+            {
+                text = "Suppliers",
+                url = "/suppliers",
+                iconCss = "fa-solid fa-truck"
+            }
+        } 
     });
 
     menuItems.Add(new
diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml
new file mode 100644
index 0000000..346c26f
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml
@@ -0,0 +1,45 @@
+@using WMS.WebUI.ViewModels.SupplierViewModels;
+@model SupplierActionViewModel;
+
+<h3 class="m-5" > Create Supplier </h3>
+<hr />
+<div class="row m-5">
+    <div class="col-md-8">
+        <form asp-action="Create" method="post">
+            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
+            <div class="form-group">
+                <label asp-for="FirstName"></label>
+                <input asp-for="FirstName" class="form-control"/>
+                <span asp-validation-for="FirstName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="LastName"></label>
+                <input asp-for="LastName" class="form-control" />
+                <span asp-validation-for="LastName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="PhoneNumber"></label>
+                <input asp-for="PhoneNumber" type="tel" class="form-control" />
+                <span asp-validation-for="PhoneNumber" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Balance"></label>
+                <input asp-for="Balance" class="form-control" />
+                <span asp-validation-for="Balance" class="text-danger"></span>
+            </div>
+            <div class="form-group mt-5">
+                <a asp-action="Index" class="btn btn-outline-info">
+                    Back
+                </a>
+                <button type="submit" class="btn btn-success">
+                    Save
+                </button>
+            </div>
+        </form>
+    </div>
+</div>
+@section Scripts {
+    @{
+        await Html.RenderPartialAsync("_ValidationScriptsPartial");
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml
new file mode 100644
index 0000000..2156eae
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Delete.cshtml
@@ -0,0 +1,41 @@
+@using WMS.WebUI.ViewModels.SupplierViewModels;
+@model SupplierDisplayViewModel ;
+
+<h3 class="m-5"> Are you sure want to delete ?</h3>
+<hr />
+
+<div class="m-5">
+    <dl class="row">
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Id)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Id)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.FullName)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.FullName)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.PhoneNumber)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.PhoneNumber)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Balance)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Balance)
+        </dd>
+    </dl>
+</div>
+
+<form asp-action="Delete" method="post" class="m-5">
+    <div class="form-group">
+        <a asp-action="Index" class="btn btn-outline-info">Back</a>
+        <button asp-route-id="@Model.Id" type="submit" class="btn btn-danger">Delete</button> 
+    </div>
+</form>
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml
new file mode 100644
index 0000000..9072dc4
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Details.cshtml
@@ -0,0 +1,50 @@
+@using WMS.WebUI.ViewModels.SupplierViewModels;
+@model SupplierDisplayViewModel;
+
+<div class="m-5">
+    <h4> Supplier details </h4>
+
+    <hr />
+
+    <dl class="row">
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Id)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Id)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.FullName)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.FullName)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.PhoneNumber)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.PhoneNumber)
+        </dd>
+        <dt class="col-sm-4">
+            @Html.DisplayNameFor(model => model.Balance)
+        </dt>
+        <dd class="col-sm-8">
+            @Html.DisplayFor(model => model.Balance)
+        </dd>
+     
+    </dl>
+    <br />
+    <br />
+
+    <div class="m-1">
+        <a asp-action="Index" class="btn btn-info fa-solid fa-arrow-left">
+            Back
+        </a>
+        <a asp-action="Edit" asp-route-id="@Model?.Id" class="btn btn-outline-warning fa-solid fa-pen">
+            Edit
+        </a>
+        <a asp-action="Delete" asp-route-id="@Model?.Id" class="btn btn-outline-danger fa-solid fa-trash">
+            Delete
+        </a>
+    </div>
+</div>
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml
new file mode 100644
index 0000000..d9d3f9f
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Edit.cshtml
@@ -0,0 +1,45 @@
+@using WMS.WebUI.ViewModels.SupplierViewModels;
+@model SupplierActionViewModel;
+
+<h3 class="m-5"> Edit Supplier </h3>
+
+<div class="row m-5">
+    <div class="col-md-8">
+        <form asp-action="Edit" method="post">
+            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
+            <div class="form-group">
+                <label asp-for="FirstName"></label>
+                <input asp-for="FirstName" class="form-control" />
+                <span asp-validation-for="FirstName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="LastName"></label>
+                <input asp-for="LastName" class="form-control" />
+                <span asp-validation-for="LastName" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="PhoneNumber"></label>
+                <input asp-for="PhoneNumber" type="tel" class="form-control" />
+                <span asp-validation-for="PhoneNumber" class="text-danger"></span>
+            </div>
+            <div class="form-group">
+                <label asp-for="Balance"></label>
+                <input asp-for="Balance" class="form-control" />
+                <span asp-validation-for="Balance" class="text-danger"></span>
+            </div>
+            <div class="form-group mt-5">
+                <a asp-action="Index" class="btn btn-outline-info">
+                    Back
+                </a>
+                <button type="submit" class="btn btn-success">
+                    Save
+                </button>
+            </div>
+        </form>
+    </div>
+</div>
+@section Scripts {
+    @{
+        await Html.RenderPartialAsync("_ValidationScriptsPartial");
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml
new file mode 100644
index 0000000..076711d
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Index.cshtml
@@ -0,0 +1,77 @@
+@using WMS.WebUI.ViewModels.SupplierViewModels
+@model IEnumerable<SupplierDisplayViewModel>
+
+<div class="mb-4 ms-2">
+    <form asp-action="Index" method="get">
+        <div class="row g-3 align-items-center">
+            <div class="col-md-3">
+                <div class="input-group">
+                    <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
+                    <button type="submit" class="btn btn-primary">
+                        <i class="fa fa-search"></i> Search
+                    </button>
+                </div>
+            </div>
+
+            <div class="col-md-2">
+                <input type="number" class="form-control" placeholder="Balance greater than" name="balanceGreaterThan" value="@ViewBag.BalanceGreaterThan" />
+            </div>
+
+            <div class="col-md-2">
+                <input type="number" class="form-control" placeholder="Balance less than" name="balanceLessThan" value="@ViewBag.BalanceLessThan" />
+            </div>
+
+            <div class="col-md-1 d-flex justify-content-end">
+                <a asp-action="Create" asp-controller="suppliers" class="btn btn-outline-success">New +</a>
+            </div>
+
+        </div>
+    </form>
+</div>
+
+<div class="container">
+    <div class="row">
+        <div class="col-12">
+            <ejs-grid id="suppliers-list"
+                      dataSource="@Model"
+                      gridLines="Vertical"
+                      allowSorting="true">
+                <e-grid-columns>
+                    <e-grid-column headerText="Id" field="Id" template="#idCellTemplate" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Full Name" field="FullName" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Phone Number" field="PhoneNumber" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Balance" field="Balance" format="C" type="Number"></e-grid-column>
+                </e-grid-columns>
+            </ejs-grid>
+        </div>
+    </div>
+</div>
+
+<div class="container mt-4">
+    <div class="d-flex justify-content-between align-items-center">
+        <div>
+            <a class="btn btn-outline-primary rounded-left no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;&lt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;</a>
+            @if (ViewBag.CurrentPage > 1)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })">@(@ViewBag.CurrentPage - 1)</a>
+            }
+            <button type="button" class="btn btn-primary rounded-right no-outline" disabled>@ViewBag.CurrentPage</button>
+            @if (ViewBag.CurrentPage < ViewBag.TotalPages)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })">@(@ViewBag.CurrentPage + 1)</a>
+            }
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.TotalPages })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;&gt;</a>
+        </div>
+        <div>
+            <p class="h6 mb-0">@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)</p>
+        </div>
+    </div>
+</div>
+
+<script id="idCellTemplate" type="text/template">
+    <div>
+        <a rel="nofollow" href="Suppliers/details/${Id}">${Id}</a>
+    </div>
+</script>

From 1f8df945cad66cd448e01490c700188383701edf Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Thu, 27 Jun 2024 18:07:04 +0500
Subject: [PATCH 3/7] Fix all bugs

---
 .../WMS.WebUI/Stores/DataStores/CustomerStore.cs      |  2 +-
 .../WMS.WebUI/Stores/DataStores/SupplierStore.cs      |  2 +-
 .../CustomerViewModels/CustomerActionViewModel.cs     | 10 +++++++++-
 .../CustomerViewModels/CustomerDisplayViewModel.cs    |  6 +++++-
 .../SupplierViewModels/SupplierActionViewModel.cs     | 11 ++++++++++-
 WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml     |  2 +-
 6 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
index 063ea23..e160918 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
@@ -47,7 +47,7 @@ public async Task<PaginatedApiResponse<CustomerDisplayViewModel>> GetCustomers(C
 
     public async Task Update(CustomerActionViewModel customer)
     {
-        await _apiClient.PutAsync(ApiResourceConstants.Customers, customer);
+        await _apiClient.PutAsync(ApiResourceConstants.Customers + "/" + customer.Id, customer);
     }
     private string BuildQueryParameters(CustomerQueryParameters queryParameters)
     {
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs
index 7035584..1d11697 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplierStore.cs
@@ -45,7 +45,7 @@ public async Task<PaginatedApiResponse<SupplierDisplayViewModel>> GetSuppliers(S
 
     public async Task Update(SupplierActionViewModel supplier)
     {
-        await _apiClient.PutAsync(ApiResourceConstants.Suppliers, supplier);
+        await _apiClient.PutAsync(ApiResourceConstants.Suppliers + "/" + supplier.Id, supplier);
     }
     private string BuildQueryParameters(SupplierQueryParameters queryParameters)
     {
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs
index 6aedcce..848a240 100644
--- a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerActionViewModel.cs
@@ -1,10 +1,18 @@
-namespace WMS.WebUI.ViewModels.CustomerViewModels;
+using System.ComponentModel;
+
+namespace WMS.WebUI.ViewModels.CustomerViewModels;
 
 public class CustomerActionViewModel
 {
     public int Id { get; set; }
+
+    [DisplayName("First name")]
     public string FirstName { get; set; }
+    
+    [DisplayName("Last name")]
     public string LastName { get; set; }
+    
+    [DisplayName("Phone number")]
     public string PhoneNumber { get; set; }
     public string Address { get; set; }
     public decimal Balance { get; set; }
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs
index 11fe7e1..f542311 100644
--- a/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/CustomerViewModels/CustomerDisplayViewModel.cs
@@ -1,9 +1,13 @@
-namespace WMS.WebUI.ViewModels.CustomerViewModels
+using System.ComponentModel;
+
+namespace WMS.WebUI.ViewModels.CustomerViewModels
 {
     public class CustomerDisplayViewModel
     {
         public int Id { get; set; }
+        [DisplayName("Full name")]
         public string FullName { get; set; }
+        [DisplayName("Phone number")]
         public string PhoneNumber { get; set; }
         public string Address { get; set; }
         public decimal Balance { get; set; }
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs
index 5d0bade..fe71d24 100644
--- a/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplierViewModels/SupplierActionViewModel.cs
@@ -1,11 +1,20 @@
-namespace WMS.WebUI.ViewModels.SupplierViewModels;
+using System.ComponentModel;
+
+namespace WMS.WebUI.ViewModels.SupplierViewModels;
 
 public class SupplierActionViewModel
 {
     public int Id { get; set; }
+
+    [DisplayName("First name")]
     public string FirstName { get; set; }
+
+    [DisplayName("Last name")]
     public string LastName { get; set; }
+    
+    [DisplayName("Phone number")]
     public string PhoneNumber { get; set; }
+    
     public decimal Balance { get; set; }
     //public ICollection<SupplyDto> Supplies { get; set; }
     //public SupplierDto()
diff --git a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml
index 346c26f..6b21a0b 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Suppliers/Create.cshtml
@@ -4,7 +4,7 @@
 <h3 class="m-5" > Create Supplier </h3>
 <hr />
 <div class="row m-5">
-    <div class="col-md-8">
+    <div class="col-md-6">
         <form asp-action="Create" method="post">
             <div asp-validation-summary="ModelOnly" class="text-danger"></div>
             <div class="form-group">

From eebfd1b06c6e3984f2dab532c736a6e30d931c60 Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Sat, 20 Jul 2024 15:07:29 +0500
Subject: [PATCH 4/7] Oldest changes

---
 .../Constants/ApiResourceConstants.cs         |  2 +
 .../Controllers/AdjustmentController.cs       | 50 ++++++++++++
 .../WMS.WebUI/Controllers/SalesController.cs  | 57 ++++++++++++++
 .../Controllers/SuppliesController.cs         | 56 +++++++++++++
 .../Models/Adjustment/Transactions.cs         | 10 +++
 WMS.WebUI/WMS.WebUI/Program.cs                |  5 +-
 .../QueryParams/TransactionQueryParameters.cs |  9 +++
 .../Stores/DataStores/CustomerStore.cs        | 35 ++++-----
 .../WMS.WebUI/Stores/DataStores/SaleStore.cs  | 68 ++++++++++++++++
 .../Stores/DataStores/SupplyStore.cs          | 66 ++++++++++++++++
 .../WMS.WebUI/Stores/Interfaces/ISaleStore.cs | 13 ++++
 .../Stores/Interfaces/ISupplyStore.cs         | 14 ++++
 .../SaleItemViewModels/SaleItemViewModel.cs   | 15 ++++
 .../SaleViewModels/SaleViewModel.cs           | 20 +++++
 .../SupplyItemViewModel.cs                    | 14 ++++
 .../SupplyViewModels/SupplyViewModel.cs       | 21 +++++
 .../WMS.WebUI/Views/Customers/Index.cshtml    |  7 +-
 .../WMS.WebUI/Views/Sales/Details.cshtml      | 46 +++++++++++
 WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml  | 78 +++++++++++++++++++
 .../WMS.WebUI/Views/Supplies/Index.cshtml     | 77 ++++++++++++++++++
 WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj          |  4 +-
 WMS.WebUI/WMS.WebUI/appsettings.json          |  5 +-
 22 files changed, 646 insertions(+), 26 deletions(-)
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml

diff --git a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
index 66a003c..b13c9e0 100644
--- a/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
+++ b/WMS.WebUI/WMS.WebUI/Constants/ApiResourceConstants.cs
@@ -6,4 +6,6 @@ public static class ApiResourceConstants
     public const string Categories = nameof(Categories);
     public const string Customers = nameof(Customers);
     public const string Suppliers = nameof(Suppliers);
+    public const string Sales = nameof(Sales);
+    public const string Supplies = nameof(Supplies);
 }
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs b/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs
new file mode 100644
index 0000000..c237f31
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs
@@ -0,0 +1,50 @@
+using Microsoft.AspNetCore.Mvc;
+using WMS.WebUI.Models.Adjustment;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Controllers;
+
+public class AdjustmentController(ISupplyStore supplyStore,ISaleStore saleStore) : Controller
+{
+    private readonly ISaleStore _saleStore = saleStore;
+    private readonly ISupplyStore _supplyStore = supplyStore;
+    public async Task<IActionResult> Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber)
+    {
+        var queryParameters = new TransactionQueryParameters()
+        {
+            Search = searchString,
+            FromDate = fromDate,
+            ToDate = toDate,
+            PageNumber = pageNumber
+        };
+
+        var supplies = await _supplyStore.GetSupplies(queryParameters);
+        var sales = await _saleStore.GetSales(queryParameters);
+
+        var transactions = new Transactions()
+        {
+            Sales = sales.Data,
+            Supplies = supplies.Data
+        };
+
+      //  PopulateViewBag(transactions, queryParameters);
+
+        return View(supplies.Data);
+    }
+    private void PopulateViewBag(PaginatedApiResponse<SupplyViewModel> sales, TransactionQueryParameters queryParameters)
+    {
+        ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd");
+        ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd");
+        ViewBag.SearchString = queryParameters.Search;
+
+        ViewBag.PageSize = sales.PageSize;
+        ViewBag.TotalPages = sales.PagesCount;
+        ViewBag.TotalItems = sales.TotalCount;
+        ViewBag.CurrentPage = sales.CurrentPage;
+        ViewBag.HasPreviousPage = sales.HasPreviousPage;
+        ViewBag.HasNextPage = sales.HasNextPage;
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs b/WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs
new file mode 100644
index 0000000..57ae057
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/SalesController.cs
@@ -0,0 +1,57 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SaleViewModels;
+
+namespace WMS.WebUI.Controllers;
+
+public class SalesController : Controller
+{
+    private readonly ICustomerStore _customerStore;
+    private readonly ISaleStore _salesStore;
+
+    public SalesController(ISaleStore saleStore, ICustomerStore customerStore)
+    {
+        _customerStore = customerStore;
+        _salesStore = saleStore;
+    }
+
+    public async Task<IActionResult> Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber)
+    {
+        var queryParameters = new TransactionQueryParameters()
+        {
+            Search = searchString,
+            FromDate = fromDate,
+            ToDate = toDate,
+            PageNumber = pageNumber
+        };
+
+        var sales = await _salesStore.GetSales(queryParameters);
+
+        PopulateViewBag(sales, queryParameters);
+
+        return View(sales.Data);
+    }
+
+    public async Task<IActionResult> Details(int id)
+    {
+        var sale = await _salesStore.GetById(id);
+        return View(sale);
+    }
+
+    private void PopulateViewBag(PaginatedApiResponse<SaleViewModel> sales, TransactionQueryParameters queryParameters)
+    {
+        ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd");
+        ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd");
+        ViewBag.SearchString = queryParameters.Search;
+
+        ViewBag.PageSize = sales.PageSize;
+        ViewBag.TotalPages = sales.PagesCount;
+        ViewBag.TotalItems = sales.TotalCount;
+        ViewBag.CurrentPage = sales.CurrentPage;
+        ViewBag.HasPreviousPage = sales.HasPreviousPage;
+        ViewBag.HasNextPage = sales.HasNextPage;
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs b/WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs
new file mode 100644
index 0000000..de3220b
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/SuppliesController.cs
@@ -0,0 +1,56 @@
+using Microsoft.AspNetCore.Mvc;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Controllers;
+
+public class SuppliesController : Controller
+{
+    private readonly ICustomerStore _customerStore;
+    private readonly ISupplyStore _supplyStore;
+
+    public SuppliesController(ISupplyStore supplyStore, ICustomerStore customerStore)
+    {
+        _customerStore = customerStore;
+         _supplyStore = supplyStore;
+    }
+
+    public async Task<IActionResult> Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber)
+    {
+        var queryParameters = new TransactionQueryParameters()
+        {
+            Search = searchString,
+            FromDate = fromDate,
+            ToDate = toDate,
+            PageNumber = pageNumber
+        };
+
+        var supplies = await _supplyStore.GetSupplies(queryParameters);
+
+        PopulateViewBag(supplies, queryParameters);
+
+        return View(supplies.Data);
+    }
+
+    public async Task<IActionResult> Details(int id)
+    {
+        var supply = await _supplyStore.GetById(id);
+        return View(supply);
+    }
+
+    private void PopulateViewBag(PaginatedApiResponse<SupplyViewModel> sales, TransactionQueryParameters queryParameters)
+    {
+        ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd");
+        ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd");
+        ViewBag.SearchString = queryParameters.Search;
+
+        ViewBag.PageSize = sales.PageSize;
+        ViewBag.TotalPages = sales.PagesCount;
+        ViewBag.TotalItems = sales.TotalCount;
+        ViewBag.CurrentPage = sales.CurrentPage;
+        ViewBag.HasPreviousPage = sales.HasPreviousPage;
+        ViewBag.HasNextPage = sales.HasNextPage;
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs b/WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs
new file mode 100644
index 0000000..48dae94
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Models/Adjustment/Transactions.cs
@@ -0,0 +1,10 @@
+using WMS.WebUI.ViewModels.SaleViewModels;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Models.Adjustment;
+
+public class Transactions
+{
+    public IEnumerable<SaleViewModel> Sales { get; set; }
+    public IEnumerable<SupplyViewModel> Supplies { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs
index faa76cc..1d3bfb6 100644
--- a/WMS.WebUI/WMS.WebUI/Program.cs
+++ b/WMS.WebUI/WMS.WebUI/Program.cs
@@ -12,10 +12,11 @@
 builder.Services.AddScoped<IProductsStore, ProductStore>();
 builder.Services.AddScoped<ICustomerStore,CustomerStore>();
 builder.Services.AddScoped<ISupplierStore,SupplierStore>();
-
+builder.Services.AddScoped<ISaleStore,SaleStore>();
+builder.Services.AddScoped<ISupplyStore, SupplyStore>();
 builder.Services.AddSingleton<ApiClient>();
 
-Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NBaF1cXmhPYVJwWmFZfVpgfF9DaFZQTGYuP1ZhSXxXdkNjUH9WdXxUTmNeVE0="); ;
+Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(builder.Configuration.GetValue<string>("Keys:Syncfusion")); 
 
 var app = builder.Build();
 
diff --git a/WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs b/WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs
new file mode 100644
index 0000000..483ad92
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/QueryParams/TransactionQueryParameters.cs
@@ -0,0 +1,9 @@
+using Syncfusion.EJ2.Calendars;
+
+namespace WMS.WebUI.QueryParams;
+
+public class TransactionQueryParameters : BaseQueryParameters
+{
+    public DateTime? FromDate { get; set; }
+    public DateTime? ToDate { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
index e160918..6acba80 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/CustomerStore.cs
@@ -13,42 +13,41 @@ namespace WMS.WebUI.Stores.DataStores;
 public class CustomerStore(ApiClient apiClient) : ICustomerStore
 {
     private readonly ApiClient _apiClient = apiClient;
-    public async Task<CustomerDisplayViewModel> Create(CustomerActionViewModel customer)
+    public async Task<PaginatedApiResponse<CustomerDisplayViewModel>> GetCustomers(CustomerQueryParameters queryParameters)
     {
-        var createdCustomer = await _apiClient.PostAsync<CustomerDisplayViewModel
-            ,CustomerActionViewModel>(ApiResourceConstants.Customers,customer);
+        var query = BuildQueryParameters(queryParameters);
 
-        return createdCustomer;
-    }
+        var url = string.IsNullOrEmpty(query) ?
+          ApiResourceConstants.Customers :
+          ApiResourceConstants.Customers + "?" + query;
 
-    public async Task Delete(int id)
-    {
-        await _apiClient.DeleteAsync(ApiResourceConstants.Customers,id);
-    }
+        var customers = await _apiClient.GetAsync<PaginatedApiResponse<CustomerDisplayViewModel>>(url);
 
+        return customers;
+    }
     public async Task<CustomerDisplayViewModel> GetById(int id)
     {
         var customer = await _apiClient.GetAsync<CustomerDisplayViewModel>(ApiResourceConstants.Customers + "/" + id);
         return customer;
     }
 
-    public async Task<PaginatedApiResponse<CustomerDisplayViewModel>> GetCustomers(CustomerQueryParameters queryParameters)
+    public async Task<CustomerDisplayViewModel> Create(CustomerActionViewModel customer)
     {
-        var query = BuildQueryParameters(queryParameters);
-
-        var url = string.IsNullOrEmpty(query) ?
-          ApiResourceConstants.Customers :
-          ApiResourceConstants.Customers + "?" + query;
-
-        var customers = await _apiClient.GetAsync<PaginatedApiResponse<CustomerDisplayViewModel>>(url);
+        var createdCustomer = await _apiClient.PostAsync<CustomerDisplayViewModel
+            ,CustomerActionViewModel>(ApiResourceConstants.Customers,customer);
 
-        return customers;
+        return createdCustomer;
     }
 
     public async Task Update(CustomerActionViewModel customer)
     {
         await _apiClient.PutAsync(ApiResourceConstants.Customers + "/" + customer.Id, customer);
     }
+    public async Task Delete(int id)
+    {
+        await _apiClient.DeleteAsync(ApiResourceConstants.Customers,id);
+    }
+
     private string BuildQueryParameters(CustomerQueryParameters queryParameters)
     {
         var query = new StringBuilder();
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs
new file mode 100644
index 0000000..2375792
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs
@@ -0,0 +1,68 @@
+using Syncfusion.EJ2.Diagrams;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using WMS.WebUI.Constants;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Services;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SaleViewModels;
+
+namespace WMS.WebUI.Stores.DataStores;
+
+public class SaleStore(ApiClient apiClient) : ISaleStore
+{
+    private readonly ApiClient _apiClient = apiClient;
+    public async Task<PaginatedApiResponse<SaleViewModel>> GetSales(TransactionQueryParameters queryParameters)
+    {
+        var query = BuildQueryParameters(queryParameters);
+        var sales = await _apiClient.GetAsync<PaginatedApiResponse<SaleViewModel>>(ApiResourceConstants.Sales + "?" + query);
+        return sales;
+    }
+    public async Task<SaleViewModel> GetById(int id)
+    {
+        var sale = await _apiClient.GetAsync<SaleViewModel>(ApiResourceConstants.Sales + "/" + id);
+        return sale;
+    }
+
+    public Task<SaleViewModel> Create(SaleViewModel sale)
+    {
+        var createdSale = _apiClient.PostAsync<SaleViewModel, SaleViewModel>(ApiResourceConstants.Sales, sale);
+        return createdSale;
+    }
+    public async Task Update(SaleViewModel sale)
+    {
+        await _apiClient.PutAsync<SaleViewModel>(ApiResourceConstants.Sales, sale);
+    }
+
+    public async Task Delete(int id)
+    {
+        await _apiClient.DeleteAsync(ApiResourceConstants.Sales, id);
+    }
+    private string BuildQueryParameters(TransactionQueryParameters queryParameters)
+    {
+        StringBuilder query = new StringBuilder();
+        
+        if (queryParameters.PageNumber.HasValue)
+        {
+            query.Append($"pageNumber={queryParameters.PageNumber}&");
+        }
+        else
+        {
+            query.Append($"pageNumber=1&");
+        }
+        if (!string.IsNullOrWhiteSpace(queryParameters.Search))
+        {
+            query.Append($"Search={queryParameters.Search}&");
+        }
+        if (queryParameters.FromDate.HasValue)
+        {
+            query.Append($"FromDate={queryParameters.FromDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&");
+        }
+        if (queryParameters.ToDate.HasValue)
+        {
+            query.Append($"ToDate={queryParameters.ToDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&");
+        }
+        return query.ToString();
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs
new file mode 100644
index 0000000..22b0723
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SupplyStore.cs
@@ -0,0 +1,66 @@
+using System.Text;
+using WMS.WebUI.Constants;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.Services;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Stores.DataStores;
+
+public class SupplyStore(ApiClient apiClient) : ISupplyStore
+{
+    private readonly ApiClient _apiClient = apiClient;
+    public async Task<PaginatedApiResponse<SupplyViewModel>> GetSupplies(TransactionQueryParameters queryParameters)
+    {
+        var query = BuildQueryParameters(queryParameters);
+        var supplies = await _apiClient.GetAsync<PaginatedApiResponse<SupplyViewModel>>(ApiResourceConstants.Supplies + "?" + query);
+        return supplies;
+    }
+    public async Task<SupplyViewModel> GetById(int id)
+    {
+        var supply = await _apiClient.GetAsync<SupplyViewModel>(ApiResourceConstants.Supplies + "/" + id);
+        return supply;
+    }
+
+    public Task<SupplyViewModel> Create(SupplyViewModel supply)
+    {
+        var createdSupply = _apiClient.PostAsync<SupplyViewModel, SupplyViewModel>(ApiResourceConstants.Supplies, supply);
+        return createdSupply;
+    }
+    public async Task Update(SupplyViewModel supply)
+    {
+        await _apiClient.PutAsync<SupplyViewModel>(ApiResourceConstants.Supplies, supply);
+    }
+
+    public async Task Delete(int id)
+    {
+        await _apiClient.DeleteAsync(ApiResourceConstants.Supplies, id);
+    }
+    private string BuildQueryParameters(TransactionQueryParameters queryParameters)
+    {
+        StringBuilder query = new StringBuilder();
+
+        if (queryParameters.PageNumber.HasValue)
+        {
+            query.Append($"pageNumber={queryParameters.PageNumber}&");
+        }
+        else
+        {
+            query.Append($"pageNumber=1&");
+        }
+        if (!string.IsNullOrWhiteSpace(queryParameters.Search))
+        {
+            query.Append($"Search={queryParameters.Search}&");
+        }
+        if (queryParameters.FromDate.HasValue)
+        {
+            query.Append($"FromDate={queryParameters.FromDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&");
+        }
+        if (queryParameters.ToDate.HasValue)
+        {
+            query.Append($"ToDate={queryParameters.ToDate.Value:yyyy-MM-ddTHH:mm:ss.fffZ}&");
+        }
+        return query.ToString();
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs
new file mode 100644
index 0000000..57084bf
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs
@@ -0,0 +1,13 @@
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.ViewModels.SaleViewModels;
+
+namespace WMS.WebUI.Stores.Interfaces;
+public interface ISaleStore
+{
+    Task<PaginatedApiResponse<SaleViewModel>> GetSales(TransactionQueryParameters queryParameters);
+    Task<SaleViewModel> GetById(int id);
+    Task<SaleViewModel> Create(SaleViewModel sale);
+    Task Update(SaleViewModel sale);
+    Task Delete(int id);
+}
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs
new file mode 100644
index 0000000..ce1a321
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISupplyStore.cs
@@ -0,0 +1,14 @@
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.QueryParams;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Stores.Interfaces;
+
+public interface ISupplyStore
+{
+    Task<PaginatedApiResponse<SupplyViewModel>> GetSupplies(TransactionQueryParameters queryParameters);
+    Task<SupplyViewModel> GetById(int id);
+    Task<SupplyViewModel> Create(SupplyViewModel supply);
+    Task Update(SupplyViewModel supply);
+    Task Delete(int id);
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs
new file mode 100644
index 0000000..a7912a4
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SaleItemViewModels/SaleItemViewModel.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel;
+
+namespace WMS.WebUI.ViewModels.SaleItemViewModels;
+
+public class SaleItemViewModel
+{
+    public int Id { get; set; }
+    public int Quantity { get; set; }
+
+    [DisplayName("Unit price")]
+    public decimal UnitPrice { get; set; }
+    public int ProductId { get; set; }
+    public string Product { get; set; }
+    public int SaleId { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs
new file mode 100644
index 0000000..133f3e7
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SaleViewModels/SaleViewModel.cs
@@ -0,0 +1,20 @@
+using System.ComponentModel;
+using WMS.WebUI.ViewModels.SaleItemViewModels;
+
+namespace WMS.WebUI.ViewModels.SaleViewModels;
+
+public class SaleViewModel
+{
+    public int Id { get; set; }
+
+    [DisplayName("Total due")]
+    public decimal TotalDue { get; set; }
+    
+    [DisplayName("Total paid")]
+    public decimal TotalPaid { get; set; }
+    public DateTime Date { get; set; }
+    public int CustomerId { get; set; }
+    public string Customer { get; set; }
+    public virtual ICollection<SaleItemViewModel> SaleItems { get; set; }
+    public SaleViewModel() => SaleItems = [];
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs
new file mode 100644
index 0000000..86fa9bb
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyItemViewModels/SupplyItemViewModel.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel;
+
+namespace WMS.WebUI.ViewModels.SupplyItemViewModels;
+
+public class SupplyItemViewModel
+{
+    public int Id { get; set; }
+    public int Quantity { get; set; }
+    [DisplayName("Unit price")]
+    public decimal UnitPrice { get; set; }
+    public int ProductId { get; set; }
+    public virtual string Product { get; set; }
+    public int SupplyId { get; set; }
+}
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs
new file mode 100644
index 0000000..6d099db
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/SupplyViewModels/SupplyViewModel.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel;
+using WMS.WebUI.ViewModels.SupplyItemViewModels;
+
+namespace WMS.WebUI.ViewModels.SupplyViewModels;
+
+public class SupplyViewModel
+{
+    public int Id { get; set; }
+    [DisplayName("Total due")]
+    public decimal TotalDue { get; set; }
+    [DisplayName("Total paid")]
+    public decimal TotalPaid { get; set; }
+    public DateTime Date { get; set; }
+    public int SupplierId { get; set; }
+    public string Supplier { get; set; }
+    public ICollection<SupplyItemViewModel> SupplyItems { get; set; }
+    public SupplyViewModel()
+    {
+        SupplyItems = [];
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml
index 7b64e43..3a7122f 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Customers/Index.cshtml
@@ -1,10 +1,11 @@
 @using WMS.WebUI.ViewModels.CustomerViewModels
 @model IEnumerable<CustomerDisplayViewModel>
 
-<div class="mb-4 ms-2">
+<div class="mb-4 ms-6">
     <form asp-action="Index" method="get">
-        <div class="row g-3 align-items-center">
-            <div class="col-md-3">
+        <div class="row g-10 align-items-center">
+
+            <div class="col-md-4">
                 <div class="input-group">
                     <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
                     <button type="submit" class="btn btn-primary">
diff --git a/WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml b/WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml
new file mode 100644
index 0000000..f1ffa2b
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Sales/Details.cshtml
@@ -0,0 +1,46 @@
+@model WMS.WebUI.ViewModels.SaleViewModels.SaleViewModel
+@{
+    ViewData["Title"] = "Sale Details";
+}
+
+<h2>@ViewData["Title"]</h2>
+
+<div class="mb-4">
+        <h3>Sale Information</h3>
+    </div>
+    <div class="card-body">
+        <dl class="row">
+            <dt class="col-sm-3">Sale ID</dt>
+            <dd class="col-sm-9">@Model.Id</dd>
+
+            <dt class="col-sm-3">Date</dt>
+            <dd class="col-sm-9">@Model.Date.ToString("dd MMM yyyy")</dd>
+
+            <dt class="col-sm-3">Customer</dt>
+            <dd class="col-sm-9">@Model.Customer</dd>
+
+            <dt class="col-sm-3">Total Due</dt>
+            <dd class="col-sm-9">@Model.TotalDue.ToString("C")</dd>
+
+            <dt class="col-sm-3">Total Paid</dt>
+            <dd class="col-sm-9">@Model.TotalPaid.ToString("C")</dd>
+        </dl>
+</div>
+<div class="container">
+    <div class="row">
+        <div class="col-12">
+            <ejs-grid id="customers-list"
+                      dataSource="@Model.SaleItems"
+                      gridLines="Vertical"
+                      allowSorting="true">
+                <e-grid-columns>
+                    <e-grid-column headerText="Quantity" field="Quantity" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Unit price" field="UnitPrice" format="C" type="Number"></e-grid-column>
+                    <e-grid-column headerText="Product" field="Product" type="Text"></e-grid-column>
+                </e-grid-columns>
+            </ejs-grid>
+        </div>
+    </div>
+</div>
+
+<a asp-action="Index" class="btn btn-primary mt-4">Back to List</a>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml
new file mode 100644
index 0000000..b5c2d4e
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Sales/Index.cshtml
@@ -0,0 +1,78 @@
+@using WMS.WebUI.ViewModels.SaleViewModels
+@model IEnumerable<SaleViewModel>
+
+<div class="mb-4 ms-2">
+    <form asp-action="Index" method="get">
+        <div class="row g-3 align-items-center">
+            <div class="col-md-3">
+                <div class="input-group">
+                    <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
+                    <button type="submit" class="btn btn-primary">
+                        <i class="fa fa-search"></i> Search
+                    </button>
+                </div>
+            </div>
+
+            <div class="col-md-2">
+                <input type="date" class="form-control" placeholder="From date" name="fromDate" value="@ViewBag.FromDate" />
+            </div>
+
+            <div class="col-md-2">
+                <input type="date" class="form-control" placeholder="To date" name="toDate" value="@ViewBag.ToDate" />
+            </div>
+
+            <div class="col-md-1 d-flex justify-content-end">
+                <a asp-action="Create" asp-controller="sales" class="btn btn-outline-success">New +</a>
+            </div>
+
+        </div>
+    </form>
+</div>
+
+<div class="container">
+    <div class="row">
+        <div class="col-12">
+            <ejs-grid id="customers-list"
+                      dataSource="@Model"
+                      gridLines="Vertical"
+                      allowSorting="true">
+                <e-grid-columns>
+                    <e-grid-column headerText="Id" field="Id" template="#idCellTemplate" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Customer" field="Customer" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Total due" field="TotalDue" format="C" type="Number"></e-grid-column>
+                    <e-grid-column headerText="Total paid" field="TotalPaid" format="C" type="Number"></e-grid-column>
+                    <e-grid-column headerText="Date" field="Date" type="Date"></e-grid-column>
+                </e-grid-columns>
+            </ejs-grid>
+        </div>
+    </div>
+</div>
+
+<div class="container mt-4">
+    <div class="d-flex justify-content-between align-items-center">
+        <div>
+            <a class="btn btn-outline-primary rounded-left no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;&lt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;</a>
+            @if (ViewBag.CurrentPage > 1)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })">@(@ViewBag.CurrentPage - 1)</a>
+            }
+            <button type="button" class="btn btn-primary rounded-right no-outline" disabled>@ViewBag.CurrentPage</button>
+            @if (ViewBag.CurrentPage < ViewBag.TotalPages)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })">@(@ViewBag.CurrentPage + 1)</a>
+            }
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.TotalPages })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;&gt;</a>
+        </div>
+        <div>
+            <p class="h6 mb-0">@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)</p>
+        </div>
+    </div>
+</div>
+
+<script id="idCellTemplate" type="text/template">
+    <div>
+        <a rel="nofollow" href="Sales/details/${Id}">${Id}</a>
+    </div>
+</script>
diff --git a/WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml
new file mode 100644
index 0000000..29ff616
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Supplies/Index.cshtml
@@ -0,0 +1,77 @@
+@using WMS.WebUI.ViewModels.SupplyViewModels
+@model IEnumerable<SupplyViewModel>
+
+<div class="mb-4 ms-2">
+    <form asp-action="Index" method="get">
+        <div class="row g-3 align-items-center">
+            <div class="col-md-3">
+                <div class="input-group">
+                    <input type="text" class="form-control" placeholder="Search..." name="searchString" value="@ViewBag.SearchString" />
+                    <button type="submit" class="btn btn-primary">
+                        <i class="fa fa-search"></i> Search
+                    </button>
+                </div>
+            </div>
+            <div class="col-md-2">
+                <input type="date" class="form-control" placeholder="From date" name="fromDate" value="@ViewBag.FromDate" />
+            </div>
+
+            <div class="col-md-2">
+                <input type="date" class="form-control" placeholder="To date" name="toDate" value="@ViewBag.ToDate" />
+            </div>
+
+            <div class="col-md-1 d-flex justify-content-end">
+                <a asp-action="Create" asp-controller="Supplies" class="btn btn-outline-success">New +</a>
+            </div>
+
+        </div>
+    </form>
+</div>
+
+<div class="container">
+    <div class="row">
+        <div class="col-12">
+            <ejs-grid id="customers-list"
+                      dataSource="@Model"
+                      gridLines="Vertical"
+                      allowSorting="true">
+                <e-grid-columns>
+                    <e-grid-column headerText="Id" field="Id" template="#idCellTemplate" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Supplier" field="Supplier" type="Text"></e-grid-column>
+                    <e-grid-column headerText="Total due" field="TotalDue" format="C" type="Number"></e-grid-column>
+                    <e-grid-column headerText="Total paid" field="TotalPaid" format="C" type="Number"></e-grid-column>
+                    <e-grid-column headerText="Date" field="Date" type="Date"></e-grid-column>
+                </e-grid-columns>
+            </ejs-grid>
+        </div>
+    </div>
+</div>
+
+<div class="container mt-4">
+    <div class="d-flex justify-content-between align-items-center">
+        <div>
+            <a class="btn btn-outline-primary rounded-left no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;&lt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasPreviousPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })" @(ViewBag.HasPreviousPage ? "" : "tabindex=\"-1\"")>&lt;</a>
+            @if (ViewBag.CurrentPage > 1)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage - 1 })">@(@ViewBag.CurrentPage - 1)</a>
+            }
+            <button type="button" class="btn btn-primary rounded-right no-outline" disabled>@ViewBag.CurrentPage</button>
+            @if (ViewBag.CurrentPage < ViewBag.TotalPages)
+            {
+                <a class="btn btn-outline-primary rounded-right no-outline" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })">@(@ViewBag.CurrentPage + 1)</a>
+            }
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.CurrentPage + 1 })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;</a>
+            <a class="btn btn-outline-primary rounded-right no-outline @(ViewBag.HasNextPage ? "" : "disabled")" href="@Url.Action("Index", new { pageNumber = ViewBag.TotalPages })" @(ViewBag.HasNextPage ? "" : "tabindex=\"-1\"")>&gt;&gt;</a>
+        </div>
+        <div>
+            <p class="h6 mb-0">@ViewBag.CurrentPage of @ViewBag.TotalPages pages (@ViewBag.TotalItems items)</p>
+        </div>
+    </div>
+</div>
+
+<script id="idCellTemplate" type="text/template">
+    <div>
+        <a rel="nofollow" href="Supplies/details/${Id}">${Id}</a>
+    </div>
+</script>
diff --git a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj
index fabc02c..527d341 100644
--- a/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj
+++ b/WMS.WebUI/WMS.WebUI/WMS.WebUI.csproj
@@ -8,8 +8,8 @@
 
   <ItemGroup>
     <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
-    <PackageReference Include="Syncfusion.EJ2.AspNet.Core" Version="25.2.7" />
-    <PackageReference Include="Syncfusion.Licensing" Version="25.2.7" />
+    <PackageReference Include="Syncfusion.EJ2.AspNet.Core" Version="26.1.40" />
+    <PackageReference Include="Syncfusion.Licensing" Version="26.1.40" />
   </ItemGroup>
 
 </Project>
diff --git a/WMS.WebUI/WMS.WebUI/appsettings.json b/WMS.WebUI/WMS.WebUI/appsettings.json
index 10f68b8..430059c 100644
--- a/WMS.WebUI/WMS.WebUI/appsettings.json
+++ b/WMS.WebUI/WMS.WebUI/appsettings.json
@@ -5,5 +5,8 @@
       "Microsoft.AspNetCore": "Warning"
     }
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  "Keys": {
+    "Syncfusion": "Ngo9BigBOggjHTQxAR8/V1NCaF5cXmZCf1FpRmJGdld5fUVHYVZUTXxaS00DNHVRdkdnWXhedHVUR2dZWUV2XUE="
+  }
 }

From 7c7ed307bb32e730c212fd4655ac19ac72a70d2b Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Sat, 20 Jul 2024 15:33:27 +0500
Subject: [PATCH 5/7] Added Partner viewModels and Transactions

---
 .../Controllers/AdjustmentController.cs       | 50 -----------------
 .../Controllers/TransactionsController.cs     | 55 +++++++++++++++++++
 WMS.WebUI/WMS.WebUI/Helpers/Validator.cs      | 13 +++++
 .../WMS.WebUI/Stores/DataStores/SaleStore.cs  |  8 ++-
 .../WMS.WebUI/Stores/Interfaces/ISaleStore.cs |  3 +-
 .../Stores/Interfaces/ITransactionsStore.cs   | 10 ++++
 .../ViewModels/DashboardViewModel.cs          | 31 ++++++++++-
 .../WMS.WebUI/ViewModels/PartnerViewModel.cs  | 15 +++++
 8 files changed, 130 insertions(+), 55 deletions(-)
 delete mode 100644 WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Helpers/Validator.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs

diff --git a/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs b/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs
deleted file mode 100644
index c237f31..0000000
--- a/WMS.WebUI/WMS.WebUI/Controllers/AdjustmentController.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-using WMS.WebUI.Models.Adjustment;
-using WMS.WebUI.Models.PaginatedResponse;
-using WMS.WebUI.QueryParams;
-using WMS.WebUI.Stores.Interfaces;
-using WMS.WebUI.ViewModels.SupplyViewModels;
-
-namespace WMS.WebUI.Controllers;
-
-public class AdjustmentController(ISupplyStore supplyStore,ISaleStore saleStore) : Controller
-{
-    private readonly ISaleStore _saleStore = saleStore;
-    private readonly ISupplyStore _supplyStore = supplyStore;
-    public async Task<IActionResult> Index(string? searchString, DateTime? fromDate, DateTime? toDate, int? pageNumber)
-    {
-        var queryParameters = new TransactionQueryParameters()
-        {
-            Search = searchString,
-            FromDate = fromDate,
-            ToDate = toDate,
-            PageNumber = pageNumber
-        };
-
-        var supplies = await _supplyStore.GetSupplies(queryParameters);
-        var sales = await _saleStore.GetSales(queryParameters);
-
-        var transactions = new Transactions()
-        {
-            Sales = sales.Data,
-            Supplies = supplies.Data
-        };
-
-      //  PopulateViewBag(transactions, queryParameters);
-
-        return View(supplies.Data);
-    }
-    private void PopulateViewBag(PaginatedApiResponse<SupplyViewModel> sales, TransactionQueryParameters queryParameters)
-    {
-        ViewBag.FromDate = queryParameters.FromDate?.ToString("yyyy-MM-dd");
-        ViewBag.ToDate = queryParameters.ToDate?.ToString("yyyy-MM-dd");
-        ViewBag.SearchString = queryParameters.Search;
-
-        ViewBag.PageSize = sales.PageSize;
-        ViewBag.TotalPages = sales.PagesCount;
-        ViewBag.TotalItems = sales.TotalCount;
-        ViewBag.CurrentPage = sales.CurrentPage;
-        ViewBag.HasPreviousPage = sales.HasPreviousPage;
-        ViewBag.HasNextPage = sales.HasNextPage;
-    }
-}
diff --git a/WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs b/WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs
new file mode 100644
index 0000000..3df277f
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Controllers/TransactionsController.cs
@@ -0,0 +1,55 @@
+using Microsoft.AspNetCore.Mvc;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels;
+using Validator = WMS.WebUI.Helpers.Validator;
+
+namespace WMS.WebUI.Controllers;
+
+public class TransactionsController : Controller
+{
+    private readonly ITransactionsStore _transactionsStore;
+    private readonly IProductsStore _productsStore;
+
+    public TransactionsController(ITransactionsStore transactionsStore, IProductsStore productsStore)
+    {
+        _transactionsStore = Validator.NotNull(transactionsStore);
+        _productsStore = Validator.NotNull(productsStore);
+    }
+
+    public async Task<IActionResult> Index(string? searchString = null, string? transactionType = null)
+    {
+        var transactions = await _transactionsStore.GetTransactionsAsync(searchString, transactionType);
+
+        ViewBag.SelectedType = transactionType ?? "All";
+
+        return View(transactions);
+    }
+
+    public async Task<IActionResult> Create()
+    {
+        var partnersTask = _transactionsStore.GetPartnersAsync();
+        var productsTask = _productsStore.GetProducts(new QueryParams.ProductQueryParameters());
+
+        await Task.WhenAll(partnersTask, productsTask);
+
+        ViewBag.Types = new string[] { "Sale", "Supply" };
+        ViewBag.SelectedType = "Sale";
+        ViewBag.Partners = partnersTask.Result;
+        ViewBag.Products= productsTask.Result.Data;
+
+        return View();
+    }
+
+    [HttpPost]
+    public async Task<IActionResult> Create(
+        [FromBody] CreateTransactionViewModel data)
+    {
+        if (!ModelState.IsValid)
+        {
+            return BadRequest();
+        }
+
+        await _transactionsStore.Create(null);
+        return View();
+    }
+}
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Helpers/Validator.cs b/WMS.WebUI/WMS.WebUI/Helpers/Validator.cs
new file mode 100644
index 0000000..2dc9c13
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Helpers/Validator.cs
@@ -0,0 +1,13 @@
+using WMS.WebUI.ViewModels;
+
+namespace WMS.WebUI.Helpers;
+
+public static class Validator
+{
+    public static T NotNull<T>(T value) where T : class
+    {
+        ArgumentNullException.ThrowIfNull(value);
+
+        return value;
+    }
+}
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs
index 2375792..e490b3f 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/SaleStore.cs
@@ -6,6 +6,7 @@
 using WMS.WebUI.QueryParams;
 using WMS.WebUI.Services;
 using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels;
 using WMS.WebUI.ViewModels.SaleViewModels;
 
 namespace WMS.WebUI.Stores.DataStores;
@@ -25,10 +26,11 @@ public async Task<SaleViewModel> GetById(int id)
         return sale;
     }
 
-    public Task<SaleViewModel> Create(SaleViewModel sale)
+    public async Task<TransactionView> Create(CreateTransactionViewModel transaction)
     {
-        var createdSale = _apiClient.PostAsync<SaleViewModel, SaleViewModel>(ApiResourceConstants.Sales, sale);
-        return createdSale;
+        var transactionNew = new TransactionView();
+
+        return transactionNew;
     }
     public async Task Update(SaleViewModel sale)
     {
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs
index 57084bf..29052ed 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ISaleStore.cs
@@ -1,5 +1,6 @@
 using WMS.WebUI.Models.PaginatedResponse;
 using WMS.WebUI.QueryParams;
+using WMS.WebUI.ViewModels;
 using WMS.WebUI.ViewModels.SaleViewModels;
 
 namespace WMS.WebUI.Stores.Interfaces;
@@ -7,7 +8,7 @@ public interface ISaleStore
 {
     Task<PaginatedApiResponse<SaleViewModel>> GetSales(TransactionQueryParameters queryParameters);
     Task<SaleViewModel> GetById(int id);
-    Task<SaleViewModel> Create(SaleViewModel sale);
+    Task<TransactionView> Create(CreateTransactionViewModel transaction);
     Task Update(SaleViewModel sale);
     Task Delete(int id);
 }
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs
new file mode 100644
index 0000000..4fb4677
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/Interfaces/ITransactionsStore.cs
@@ -0,0 +1,10 @@
+using WMS.WebUI.ViewModels;
+
+namespace WMS.WebUI.Stores.Interfaces;
+
+public interface ITransactionsStore
+{
+    Task<List<TransactionView>> GetTransactionsAsync(string? search, string? type);
+    Task<List<PartnerViewModel>> GetPartnersAsync();
+    Task<TransactionView> Create(CreateTransactionViewModel transaction);
+}
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs
index d1262e1..cd005e0 100644
--- a/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/DashboardViewModel.cs
@@ -1,6 +1,7 @@
 using System;
 using System.ComponentModel.DataAnnotations;
 using System.Globalization;
+using System.Runtime.Serialization;
 
 namespace WMS.WebUI.ViewModels;
 
@@ -61,7 +62,35 @@ public class SplineChart
 public class TransactionView
 {
     public int Id { get; set; }
-    public string Type { get; set; }
+    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
+    public TransactionType Type { get; set; }
     public decimal Amount { get; set; }
+    public int PartnerId { get; set; }
+    public string Partner { get; set; }
     public DateTime Date { get; set; }
+}
+
+public class CreateTransactionViewModel
+{
+    public TransactionType Type { get; set; }
+    public int PartnerId { get; set; }
+    public DateTime Date { get; set; }
+    public List<TransactionItem> Items { get; set; }
+}
+
+public class TransactionItem
+{
+    public int ProductId { get; set; }
+    public int Quantity { get; set; }
+    public decimal UnitPrice { get; set; }
+}
+
+public enum TransactionType
+{
+    [EnumMember(Value = "Sale")]
+    Sale,
+    [EnumMember(Value = "Supply")]
+    Supply,
+    [EnumMember(Value = "Refund")]
+    Refund
 }
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs b/WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs
new file mode 100644
index 0000000..8503c58
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/ViewModels/PartnerViewModel.cs
@@ -0,0 +1,15 @@
+namespace WMS.WebUI.ViewModels;
+
+public class PartnerViewModel
+{
+    public int Id { get; set; }
+    public string FullName { get; set; }
+    public PartnerType Type { get; set; }
+    public string PhoneNumber { get; set; }
+}
+
+public enum PartnerType
+{
+    Customer,
+    Supplier
+}

From 640234173cc8ae2b7bcdc5108b9c2cc20f9d217e Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Sat, 20 Jul 2024 15:55:45 +0500
Subject: [PATCH 6/7] Changing Transactions but not Delete Sale and supply
 controllers

---
 WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs |  20 ++
 .../WMS.WebUI/Mappings/SupplyMappings.cs      |  21 +++
 WMS.WebUI/WMS.WebUI/Program.cs                |   2 +
 .../Stores/DataStores/TransactionsStore.cs    |  56 ++++++
 .../Stores/Mocks/MockDashboardStore.cs        |  14 +-
 .../WMS.WebUI/Views/Shared/_Sidebar.cshtml    |   2 +-
 .../Views/Transactions/Create.cshtml          | 178 ++++++++++++++++++
 .../WMS.WebUI/Views/Transactions/Index.cshtml |  82 ++++++++
 8 files changed, 367 insertions(+), 8 deletions(-)
 create mode 100644 WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml
 create mode 100644 WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml

diff --git a/WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs b/WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs
new file mode 100644
index 0000000..475da2c
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Mappings/SalesMappings.cs
@@ -0,0 +1,20 @@
+using WMS.WebUI.ViewModels;
+using WMS.WebUI.ViewModels.SaleViewModels;
+
+namespace WMS.WebUI.Mappings;
+
+public static class SalesMappings
+{
+    public static TransactionView ToTransaction(this SaleViewModel sale)
+    {
+        return new TransactionView
+        {
+            Id = sale.Id,
+            Amount = sale.TotalPaid,
+            Date = sale.Date,
+            Partner = sale.Customer,
+            PartnerId = sale.CustomerId,
+            Type = TransactionType.Sale
+        };  
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs b/WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs
new file mode 100644
index 0000000..8876669
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Mappings/SupplyMappings.cs
@@ -0,0 +1,21 @@
+using WMS.WebUI.ViewModels;
+using WMS.WebUI.ViewModels.SaleViewModels;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Mappings;
+
+public static class SupplyMappings
+{
+    public static TransactionView ToTransaction(this SupplyViewModel supply)
+    {
+        return new TransactionView
+        {
+            Id = supply.Id,
+            Amount = supply.TotalPaid,
+            Date = supply.Date,
+            Partner = supply.Supplier,
+            PartnerId = supply.SupplierId,
+            Type = TransactionType.Supply,
+        };
+    }
+}
diff --git a/WMS.WebUI/WMS.WebUI/Program.cs b/WMS.WebUI/WMS.WebUI/Program.cs
index 1d3bfb6..7c8883c 100644
--- a/WMS.WebUI/WMS.WebUI/Program.cs
+++ b/WMS.WebUI/WMS.WebUI/Program.cs
@@ -1,4 +1,5 @@
 using WMS.WebUI.Services;
+using WMS.WebUI.Stores;
 using WMS.WebUI.Stores.DataStores;
 using WMS.WebUI.Stores.Interfaces;
 using WMS.WebUI.Stores.Mocks;
@@ -13,6 +14,7 @@
 builder.Services.AddScoped<ICustomerStore,CustomerStore>();
 builder.Services.AddScoped<ISupplierStore,SupplierStore>();
 builder.Services.AddScoped<ISaleStore,SaleStore>();
+builder.Services.AddScoped<ITransactionsStore,TransactionsStore>();
 builder.Services.AddScoped<ISupplyStore, SupplyStore>();
 builder.Services.AddSingleton<ApiClient>();
 
diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs
new file mode 100644
index 0000000..0a49309
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs
@@ -0,0 +1,56 @@
+using WMS.WebUI.Mappings;
+using WMS.WebUI.Models.PaginatedResponse;
+using WMS.WebUI.Stores.Interfaces;
+using WMS.WebUI.ViewModels;
+using WMS.WebUI.ViewModels.SaleViewModels;
+using WMS.WebUI.ViewModels.SupplyViewModels;
+
+namespace WMS.WebUI.Stores;
+
+public class TransactionsStore : ITransactionsStore
+{
+    private readonly HttpClient _client;
+
+    public TransactionsStore()
+    {
+        _client = new HttpClient();
+        _client.BaseAddress = new Uri("https://localhost:7108/api/");
+    }
+
+    public async Task<List<TransactionView>> GetTransactionsAsync(string? search, string? type)
+    {
+        var salesTask = _client.GetFromJsonAsync<PaginatedApiResponse<SaleViewModel>>($"sales?search={search}");
+        var suppliesTask = _client.GetFromJsonAsync<PaginatedApiResponse<SupplyViewModel>>($"supplies?search={search}");
+
+        await Task.WhenAll(salesTask, suppliesTask);
+
+        var sales = salesTask.Result;
+        var supplies = suppliesTask.Result;
+        List<TransactionView> transactions = [];
+
+        sales?.Data.ForEach(sale => transactions.Add(sale.ToTransaction()));
+        supplies?.Data.ForEach(supply => transactions.Add(supply.ToTransaction()));
+
+        return transactions;
+    }
+
+    public async Task<List<PartnerViewModel>> GetPartnersAsync()
+    {
+        var customersTask = _client.GetFromJsonAsync<List<PartnerViewModel>>("customers");
+        var suppliersTask = _client.GetFromJsonAsync<List<PartnerViewModel>>("suppliers");
+
+        await Task.WhenAll(customersTask, suppliersTask);
+
+        customersTask.Result!.ForEach(el => el.Type = PartnerType.Customer);
+        suppliersTask.Result!.ForEach(el => el.Type = PartnerType.Supplier);
+
+        return [.. customersTask.Result, .. suppliersTask.Result];
+    }
+
+    public async Task<TransactionView> Create(CreateTransactionViewModel transaction)
+    {
+        var transactionNew = new TransactionView();
+
+        return transactionNew;
+    }
+}
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs b/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs
index bf46fb4..8b3628c 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/Mocks/MockDashboardStore.cs
@@ -156,42 +156,42 @@ public Task<DashboardViewModel> Get()
                 Id = 1,
                 Amount = 500,
                 Date = DateTime.Now,
-                Type = "Sale"
+                Type = TransactionType.Sale,
             },
             new TransactionView
             {
                 Id = 2,
                 Amount = 300,
-                Date = DateTime.Now,
-                Type = "Sale"
+                Type = TransactionType.Sale,
+                Date = DateTime.Now
             },
             new TransactionView
             {
                 Id = 3,
                 Amount = 459,
+                Type = TransactionType.Supply,
                 Date = DateTime.Now,
-                Type = "Supply"
             },
             new TransactionView
             {
                 Id = 4,
                 Amount = 500,
+                Type = TransactionType.Supply,
                 Date = DateTime.Now,
-                Type = "Supply"
             },
             new TransactionView
             {
                 Id = 5,
                 Amount = 250,
+                Type = TransactionType.Refund,
                 Date = DateTime.Now,
-                Type = "Refund"
             },
             new TransactionView
             {
                 Id = 7,
                 Amount = 200,
                 Date = DateTime.Now,
-                Type = "Sale"
+                Type = TransactionType.Sale,
             },
         };
 
diff --git a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml
index e681bcc..cbe8257 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Shared/_Sidebar.cshtml
@@ -45,7 +45,7 @@
     menuItems.Add(new
     {
         text = "Transactions",
-        url = "#",
+        url = "/transactions",
         iconCss = "fa-solid fa-money-bill-transfer",
         items = new List<object>
         {
diff --git a/WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml
new file mode 100644
index 0000000..64ef6a5
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Transactions/Create.cshtml
@@ -0,0 +1,178 @@
+@model WMS.WebUI.ViewModels.TransactionView
+@using System.Collections.Generic
+
+<div class="row m-5">
+    <div id="product-form" class="d-flex flex-column gap-4">
+        <h3 class="text-center">Create Transaction</h3>
+        <div class="form-group d-flex gap-5">
+            <ejs-combobox id="types"
+                          dataSource="@ViewBag.Types"
+                          value="@ViewBag.SelectedType"
+                          placeholder="Select Type"
+                          name="Type"
+                          floatLabelType="Auto"
+                          change="onSelectedTypeChanged">
+            </ejs-combobox>
+            <ejs-combobox id="partners"
+                          dataSource="@ViewBag.Partners"
+                          value="@ViewBag.SelectedPartnerId"
+                          placeholder="Select Partner"
+                          name="PartnerId"
+                          floatLabelType="Auto">
+                <e-combobox-fields value="Id" text="FullName"></e-combobox-fields>
+            </ejs-combobox>
+            <div style="display: none;">
+                <ejs-combobox id="partners-copy"
+                          dataSource="@ViewBag.Partners"
+                          value="@ViewBag.SelectedPartnerId"
+                          placeholder="Select Partner"
+                          name="PartnerId"
+                          floatLabelType="Auto">
+                    <e-combobox-fields value="Id" text="FullName"></e-combobox-fields>
+                </ejs-combobox>
+            </div>
+            <ejs-datetimepicker id="transaction-date" value="@DateTime.Now" name="Date" placeholder="Select Date" floatLabelType="Auto"></ejs-datetimepicker>
+        </div>
+        <div class="form-group d-flex gap-5">
+            <ejs-combobox id="products"
+                          dataSource="@ViewBag.Products"
+                          placeholder="Select Product"
+
+                          name="Products">
+                <e-combobox-fields value="Id" text="Name"></e-combobox-fields>
+            </ejs-combobox>
+            <ejs-button id="addProduct" content="Add" class="ml-auto" cssClass="e-success"></ejs-button>
+        </div>
+        <div class="form-group d-flex gap-5">
+            <ejs-grid id="transaction-items"
+                      dataSource="@ViewBag.TransactionItems"
+                      gridLines="Vertical"
+                      allowSorting="true">
+                <e-grid-editsettings allowDeleting="true" allowEditing="true" mode="Normal"></e-grid-editsettings>
+                <e-grid-columns>
+                    <e-grid-column headerText="Id" field="ProductId" isPrimaryKey="true" typeof="Text"></e-grid-column>
+                    <e-grid-column headerText="Name" field="Name" allowEditing="false" typeof="Text"></e-grid-column>
+                    <e-grid-column headerText="Unit Price" field="UnitPrice" typeof="Text" format="c2"></e-grid-column>
+                    <e-grid-column headerText="Quantity" field="Quantity" typeof="Number" editType="numericedit"></e-grid-column>
+                </e-grid-columns>
+            </ejs-grid>
+        </div>
+        <div class="form-group d-flex gap-5">
+            <p class="ml-auto" id="total-due">0</p>
+        </div>
+
+        <ejs-button id="submit" content="Submit" cssClass="e-success"></ejs-button>
+    </div>
+</div>
+
+<script>
+    document.getElementById('addProduct').onclick = function () {
+        const grid = document.getElementById("transaction-items").ej2_instances[0];
+        const productsList = document.getElementById('products').ej2_instances[0];
+        const selectedProduct = productsList.dataSource.find(el => el.Id == productsList.value);
+        
+        const item = {
+            ProductId: selectedProduct.Id,
+            Name: selectedProduct.Name,
+            Quantity: 1,
+            UnitPrice: selectedProduct.SalePrice
+        };
+
+        if (grid.dataSource.some(el => el.ProductId == item?.ProductId)) {
+            return;
+        }
+
+        grid.dataSource.unshift(item);
+        grid.refresh();
+
+        console.log(grid.dataSource);
+        const totalDue = grid.dataSource.map(el => el.Quantity * el.UnitPrice).reduce((current, previous) => previous + current);
+        console.log(totalDue);
+        let formatter = Intl.NumberFormat('en', { notation: 'compact' });
+        document.getElementById('total-due').innerHTML = formatter.format(totalDue);
+    };
+
+    // // submit sale
+    document.getElementById('submit').onclick = function (e) {
+        e.stopPropagation();
+
+        const type = document.getElementById('types').ej2_instances[0].value;
+        const partnerId = document.getElementById('partners').ej2_instances[0].value;
+        const selectedDate = document.getElementById('transaction-date').ej2_instances[0].value;
+        const items = document.getElementById("transaction-items").ej2_instances[0].dataSource;
+
+        const newSale = {
+            Date: selectedDate,
+            PartnerId: partnerId,
+            Type: type
+        };
+        console.log(newSale);
+        $.ajax({
+            url: '@Url.Action("Create", "Transactions")',
+            type: 'POST',
+            data: JSON.stringify(newSale),
+            contentType: "application/json; charset=utf-8",
+            success: function (response) {
+                console.log('success: ');
+                console.log(response);
+                window.location.href = response.redirectToUrl;
+            },
+            error: function (data) {
+                console.log('error: ');
+                console.log(data);
+                alert('There was an error saving creating new sale! Please, try again.');
+            }
+        });
+    }
+
+
+    // document.addEventListener('DOMContentLoaded', function () {
+    //     const options = {
+    //         rules: {
+    //             'datevalue': { required: true }
+    //         },
+    //         customPlacement: (inputElement, errorElement) => {
+    //             //to place the error message in custom position
+    //             //inputElement - target element where the error text will be appended
+    //             //errorElement - error text which will be displayed.
+    //             inputElement.parentElement.parentElement.appendChild(errorElement);
+    //         }
+    //     };
+    //     const formObject = new ej.inputs.FormValidator('#sale-date', options);
+    // });
+
+    // function dlgButtonClick() {
+    //     const dialogObj = document.getElementById('dialog').ej2_instances[0];
+    //     dialogObj.hide();
+    // }
+
+    // function onSelectedProductChanged() {
+    //     const productsList = document.getElementById('products-list').ej2_instances[0];
+    //     const selectedProduct = productsList.dataSource.find(el => el.Id == productsList.value);
+    //     document.getElementById('item-price').ej2_instances[0].value = selectedProduct.SupplyPrice;
+    //     document.getElementById('item-quantity').ej2_instances[0].max = selectedProduct.QuantityInStock;
+    // }
+
+    function onSelectedTypeChanged() {
+        const selectedValue = document.getElementById('types').ej2_instances[0].value;
+        const partners = document.getElementById('partners').ej2_instances[0];
+        const partnersCopy = document.getElementById('partners-copy').ej2_instances[0].dataSource;
+
+        if (selectedValue == 'Sale') {
+            const customers = partnersCopy.filter(el => el.Type == 0);
+            partners.dataSource = customers; // 50 -> 25
+        } else {
+            const suppliers = partnersCopy.filter(el => el.Type == 1);
+            partners.dataSource = suppliers;
+        }
+
+        partners.index = 0;
+    }
+
+    document.addEventListener('DOMContentLoaded', function () {
+        onSelectedTypeChanged();
+
+        const productsList = document.getElementById('products').ej2_instances[0];
+        productsList.index = 0;
+    });
+</script>
\ No newline at end of file
diff --git a/WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml b/WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml
new file mode 100644
index 0000000..cf7477c
--- /dev/null
+++ b/WMS.WebUI/WMS.WebUI/Views/Transactions/Index.cshtml
@@ -0,0 +1,82 @@
+@using WMS.WebUI.ViewModels
+@model List<TransactionView>
+
+@{
+    var transactionTypes = new string[] { "All", "Sales", "Supplies", "Refunds" };
+}
+
+<form asp-controller="Transactions" asp-action="Index">
+    <input type="hidden" />
+    <div class="row mt-3">
+        <div class="d-flex justify-content-start gap-4">
+            <div class="col-md-3 mb-4">
+                <ejs-combobox id="transactions"
+                              dataSource="transactionTypes"
+                              value="@ViewBag.SelectedType"
+                              placeholder="Select type"
+                              name="transactionType">
+                </ejs-combobox>
+            </div>
+            <!-- Search -->
+            <div class="col-md-4 mb-4">
+                <div class="d-flex">
+                    <ejs-textbox id="search" value="@ViewBag.SearchString" placeholder="Search Transactions..." name="searchString"></ejs-textbox>
+                    <button type="submit" class="btn btn-primary">
+                        <i class="fa fa-search"></i>
+                    </button>
+                </div>
+            </div>
+
+            <div class="d-flex mb-4 justify-content-end" style="gap: 15px;">
+                <a class="btn btn-outline-info" asp-action="download">
+                    <i class="fa fa-solid fa-download"></i> Download
+                </a>
+                <a class="btn btn-outline-info" asp-action="upload">
+                    <i class="fa fa-solid fa-upload"></i> Upload
+                </a>
+                <a class="btn btn-success" asp-action="create">
+                    <i class="fa fa-solid fa-plus"></i> Create
+                </a>
+            </div>
+        </div>
+    </div>
+</form>
+
+<div class="row mb-4">
+    <div class="col-12">
+        <ejs-grid id="categories-list"
+                  dataSource="@Model"
+                  gridLines="Vertical"
+                  allowSorting="true">
+            <e-grid-columns>
+                <e-grid-column headerText="Id" field="Id" template="#idCellTemplate" typeof="Text"></e-grid-column>
+                <e-grid-column headerText="Amount" field="Amount" typeof="Text" format="c2"></e-grid-column>
+                <e-grid-column headerText="Date" field="date" typeof="Text" format="yMd"></e-grid-column>
+                <e-grid-column headerText="Partner" field="Partner" template="#partnerCellTemplate" typeof="Text"></e-grid-column>
+                <e-grid-column headerText="Type" field="Type" typeof="Text"></e-grid-column>
+            </e-grid-columns>
+        </ejs-grid>
+    </div>
+</div>
+
+<script id="idCellTemplate" type="text/template">
+    <div>
+        <a rel='nofollow' href="transactions/details/${Id}">${Id}</a>
+    </div>
+</script>
+<script id="partnerCellTemplate" type="text/template">
+    <div>
+        <a rel='nofollow' href="transaction/partners/${Id}">${Partner}</a>
+    </div>
+</script>
+
+<script id="stockTemplate" type="text/x-template">
+    <div class="template_checkbox text-center">
+        ${if(LowQuantityAmount > QuantityInStock)}
+            <p class="text-danger">${QuantityInStock}</p>
+
+            ${else}
+            <p>${QuantityInStock} </p>
+        ${/if}
+    </div>
+</script>
\ No newline at end of file

From 9cb275c174b8acb7a0ff4fb64c3a3b1ed4d801c0 Mon Sep 17 00:00:00 2001
From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com>
Date: Sun, 21 Jul 2024 12:03:48 +0500
Subject: [PATCH 7/7] a

efe
---
 .../Stores/DataStores/TransactionsStore.cs    | 10 +-
 .../WMS.WebUI/Views/Products/Create.cshtml    | 99 ++++++-------------
 2 files changed, 35 insertions(+), 74 deletions(-)

diff --git a/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs
index 0a49309..5b9c54e 100644
--- a/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs
+++ b/WMS.WebUI/WMS.WebUI/Stores/DataStores/TransactionsStore.cs
@@ -36,15 +36,15 @@ public async Task<List<TransactionView>> GetTransactionsAsync(string? search, st
 
     public async Task<List<PartnerViewModel>> GetPartnersAsync()
     {
-        var customersTask = _client.GetFromJsonAsync<List<PartnerViewModel>>("customers");
-        var suppliersTask = _client.GetFromJsonAsync<List<PartnerViewModel>>("suppliers");
+        var customersTask = _client.GetFromJsonAsync<PaginatedApiResponse<PartnerViewModel>>("customers");
+        var suppliersTask = _client.GetFromJsonAsync<PaginatedApiResponse<PartnerViewModel>>("suppliers");
 
         await Task.WhenAll(customersTask, suppliersTask);
 
-        customersTask.Result!.ForEach(el => el.Type = PartnerType.Customer);
-        suppliersTask.Result!.ForEach(el => el.Type = PartnerType.Supplier);
+        customersTask.Result!.Data.ForEach(el => el.Type = PartnerType.Customer);
+        suppliersTask.Result!.Data.ForEach(el => el.Type = PartnerType.Supplier);
 
-        return [.. customersTask.Result, .. suppliersTask.Result];
+        return [.. customersTask.Result.Data, .. suppliersTask.Result.Data];
     }
 
     public async Task<TransactionView> Create(CreateTransactionViewModel transaction)
diff --git a/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml
index 3a352d9..76d878a 100644
--- a/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml
+++ b/WMS.WebUI/WMS.WebUI/Views/Products/Create.cshtml
@@ -1,72 +1,33 @@
-@model WMS.WebUI.ViewModels.ProductViewModel
+@using WMS.WebUI.ViewModels 
+@model ProductViewModel;
 
-@{
-    ViewData["Title"] = "Create Product";
-}
-
-<div class="m-5">
-    <h4>Create Product</h4>
-    <hr />
-
-    <form asp-action="Create">
-        <div class="form-group row">
-            <label asp-for="Name" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <input asp-for="Name" class="form-control" />
-                <span asp-validation-for="Name" class="text-danger"></span>
-            </div>
-        </div>
-        <div class="form-group row">
-            <label asp-for="Description" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <textarea asp-for="Description" class="form-control"></textarea>
-                <span asp-validation-for="Description" class="text-danger"></span>
-            </div>
-        </div>
-        <div class="form-group row">
-            <label asp-for="SalePrice" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <input asp-for="SalePrice" class="form-control" />
-                <span asp-validation-for="SalePrice" class="text-danger"></span>
-            </div>
-        </div>
-        <div class="form-group row">
-            <label asp-for="SupplyPrice" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <input asp-for="SupplyPrice" class="form-control" />
-                <span asp-validation-for="SupplyPrice" class="text-danger"></span>
-            </div>
-        </div>
-        <div class="form-group row">
-            <label asp-for="QuantityInStock" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <input asp-for="QuantityInStock" class="form-control" />
-                <span asp-validation-for="QuantityInStock" class="text-danger"></span>
-            </div>
+<div class="row m-5">
+    <form id="product-form" class="d-flex flex-column gap-4" asp-action="Create">
+        <h3 class="text-center">Create Product</h3>
+        <div class="form-group d-flex gap-5">
+            <ejs-combobox id="categories"
+                          dataSource="@ViewBag.Categories"
+                          value="@ViewBag.SelectedCategoryId"
+                          placeholder="Select a category"
+                          name="CategoryId"
+                          floatLabelType="Auto"
+                          width="50%">
+                <e-combobox-fields value="Id" text="Name"></e-combobox-fields>
+            </ejs-combobox>
+            <ejs-textbox id="name" name="Name" placeholder="Product Name" floatLabelType="Auto" width="50%"></ejs-textbox>
+        </div>
+        <div class="form-group d-flex gap-5">
+            <ejs-numerictextbox id="sale-price" name="SalePrice" floatLabelType="Auto" format="c2" min="0" value="0" placeholder="Sale Price" width="50%"></ejs-numerictextbox>
+            <ejs-numerictextbox id="supply-price" name="SupplyPrice" floatLabelType="Auto" format="c2" min="0" value="0" placeholder="Supply Price" width="50%"></ejs-numerictextbox>
+        </div>
+        <div class="form-group d-flex gap-5">
+            <ejs-numerictextbox id="in-stock" name="QuantityInStock" floatLabelType="Auto" min="0" value="0" placeholder="Quantity In Stock" width="50%"></ejs-numerictextbox>
+            <ejs-numerictextbox id="low-quantity" name="LowQuantityAmount" floatLabelType="Auto" min="0" value="0" placeholder="Low Quantity Amount" width="50%"></ejs-numerictextbox>
+        </div>
+        <div class="form-group">
+            <ejs-textarea id="description" name="Description" floatLabelType="Auto" placeholder="Description"></ejs-textarea>
         </div>
-        <div class="form-group row">
-            <label asp-for="LowQuantityAmount" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <input asp-for="LowQuantityAmount" class="form-control" />
-                <span asp-validation-for="LowQuantityAmount" class="text-danger"></span>
-            </div>
-        </div>
-        <div class="form-group row">
-            <label asp-for="CategoryId" class="col-sm-2 col-form-label"></label>
-            <div class="col-sm-10">
-                <select asp-for="CategoryId" class="form-control" asp-items="ViewBag.Categories"></select>
-                <span asp-validation-for="CategoryId" class="text-danger"></span>
-            </div>
-        </div>
-        <div class="form-group mt-3">
-            <input type="submit" value="Create" class="btn btn-primary" />
-            <a asp-action="Index" class="btn btn-secondary">Back to List</a>
-        </div>
-    </form>
-</div>
 
-@section Scripts {
-    @{
-        await Html.RenderPartialAsync("_ValidationScriptsPartial");
-    }
-}
+        <ejs-button id="submit" content="Submit" class="btn-success"></ejs-button>
+    </form>
+</div>
\ No newline at end of file