Introduction
As you know dashboard system has become very important because it helps the managers taking the right decisions. Generally, a dashboard has so many KPIs (Key Performance Indicator) which represent what happens in business. The KPIs or metrics can be number of users, number of orders, top customers, top orders etc...
All of these KPIs give visibility that can allow the top management of any enterprise to make good decisions. In this article, the idea is to build simple dashboard system with KPIs, then represent them in charts (using Google Charts).
Finally, I would like to point out that we will use ASP.NET MVC 5 and jQuery to build our app. I hope you will like it.
Prerequisites
Make sure you have installed Visual Studio 2015 (.NETFramework 4.5.2) and SQL Server.
In this post, we are going to,
- Create MVC application.
- Create database (Using Entity Framework Code First).
- Create controllers (Customer Order, Product, and Dashboard).
Create your MVC application
Open Visual Studio and select File >> New Project.
The "New Project" window will pop up. Select ASP.NET Web Application (.NET Framework), name your project, and click OK.
Next, new dialog will pop up for selecting the template. We are going choose MVC template and click Ok.
Once our project is created, we will create database using entity framework (Code first approach).
SQL Database part
As you know, entity framework has different approach to map database such as database first, model first, and code first. In this article, I’d like to show you how we can create database using code first approach.
Let’s follow the steps below to create our database. Before of all, we are going create Data Access folder.
To do that. From solution explorer >> right click on project name >> Add >> New Folder.
After that, we are adding two new folders, entities and configurations respectively.
Here entities folder contains the definition of all the implied entities in our application whereas configurations folder is used to define characteristics of different properties of each entity.
Entities Folder
Now, we are adding the following entities
IEntity.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace ApplicationDashboardMVC.DataAccess.Entitites
- {
- public interface IEntity
- {
- int ID { get; set; }
- }
- }
Customer.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Entitites
- {
- public class Customer : IEntity
- {
- public Customer()
- {
- Orders = new List<Order>();
- }
-
- public int ID { get; set; }
- public string CustomerName { get; set; }
- public string CustomerEmail { get; set; }
- public string CustomerPhone { get; set; }
- public string CustomerCountry { get; set; }
- public string CustomerImage { get; set; }
-
- public virtual ICollection<Order> Orders { get; set; }
- }
- }
Order.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Entitites
- {
- public class Order: IEntity
- {
- public Order()
- {
- OrderDetail = new List<OrderDetails>();
- }
- public int ID { get; set; }
- public DateTime OrderDate { get; set; }
-
- public virtual Customer Customer { get; set; }
- public virtual ICollection<OrderDetails> OrderDetail { get; set; }
- }
- }
OrderDetails.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Entitites
- {
- public class OrderDetails : IEntity
- {
- public int ID { get; set; }
- public int Quatity { get; set; }
- public virtual Order Order { get; set; }
- public virtual Product Product { get; set; }
- }
- }
Product.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Entitites
- {
- public class Product : IEntity
- {
- public Product()
- {
- OrderDetails = new List<OrderDetails>();
- }
- public int ID { get; set; }
- public string ProductName { get; set; }
- public decimal UnitPrice { get; set; }
- public int UnitsInStock { get; set; }
- public string ProductImage { get; set; }
- public string ProductType { get; set; }
- public virtual ICollection<OrderDetails> OrderDetails { get; set; }
-
- }
- }
Now, it’s time to add configurations of all entities which will be used in our application.
EntityConfiguration.cs
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using System;
- using System.Collections.Generic;
- using System.Data.Entity.ModelConfiguration;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Configurations
- {
- public class EntityConfiguration<T> : EntityTypeConfiguration<T> where T: class, IEntity
- {
- public EntityConfiguration()
- {
- HasKey(e=>e.ID);
- }
- }
- }
CustomerConfiguration.cs
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Configurations
- {
- public class CustomerConfiguration : EntityConfiguration<Customer>
- {
- public CustomerConfiguration()
- {
- Property(c => c.CustomerName).IsRequired().HasMaxLength(100);
- Property(c => c.CustomerEmail).IsRequired().HasMaxLength(60);
- Property(c => c.CustomerPhone).IsRequired().HasMaxLength(100);
- Property(c => c.CustomerCountry).IsRequired().HasMaxLength(100);
- Property(c => c.CustomerImage).IsOptional();
- }
- }
- }
OrderConfiguration.cs
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Configurations
- {
- public class OrderConfiguration : EntityConfiguration<Order>
- {
- public OrderConfiguration()
- {
- Property(o => o.OrderDate).IsRequired();
- }
- }
- }
OrderDetailsConfiguration.cs
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Configurations
- {
- public class OrderDetailsConfiguration : EntityConfiguration<OrderDetails>
- {
-
- public OrderDetailsConfiguration()
- {
- Property(o => o.Quatity).IsRequired();
- }
- }
- }
ProductConfiguration.cs
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess.Configurations
- {
- public class ProductConfiguration : EntityConfiguration<Product>
- {
- public ProductConfiguration()
- {
- Property(p => p.ProductName).IsRequired().HasMaxLength(100);
- Property(p => p.UnitPrice).IsRequired();
- Property(p => p.ProductImage).IsRequired().HasMaxLength(100);
- Property(p => p.UnitsInStock).IsRequired();
- }
- }
- }
As final step. We are adding our dashboard context which will help us to access data from database. Usually context inherits from dbcontext class.
DashboardContext.cs
- using ApplicationDashboardMVC.DataAccess.Configurations;
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using System;
- using System.Collections.Generic;
- using System.Data.Entity;
- using System.Data.Entity.ModelConfiguration.Conventions;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.DataAccess
- {
- public class DashboardContext : DbContext
- {
-
- public DashboardContext():base("DashboardOrder")
- {
-
- }
-
- #region Entities
- public IDbSet<Customer> CustomerSet { get; set; }
- public IDbSet<Order> OrderSet { get; set; }
- public IDbSet<Product> ProductSet { get; set; }
- public IDbSet<OrderDetails> OrderDetailSet { get; set; }
-
- #endregion
-
- protected override void OnModelCreating(DbModelBuilder modelBuilder)
- {
- modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
-
- modelBuilder.Configurations.Add(new CustomerConfiguration());
- modelBuilder.Configurations.Add(new OrderConfiguration());
- modelBuilder.Configurations.Add(new ProductConfiguration());
- modelBuilder.Configurations.Add(new OrderDetailsConfiguration());
- }
-
- }
- }
Note
Make sure that you have added connection string of your database in Web.config file.
- <connectionStrings>
- <add name="DashboardOrder" connectionString="Data Source=.;Initial Catalog=DashboardOrder;Integrated Security=True" providerName="System.Data.SqlClient" />
- </connectionStrings>
Now, Open Package Manager console and type the following command.
Enable-migrations
After that, I can see that we are ready to create our database. Run the following commands respectively.
add-migration "initial_migration"
update-database –verbose
As you can see above, all the table have been added successfully.
Create a controller
Now, we are going to create a controller. Right click on the controllers folder> > Add >> Controller>> selecting MVC 5 Controller - Empty>> click Add. In the next dialog name the controller CustomerOrderController and then click Add.
CustomerOrderController.cs
- using ApplicationDashboardMVC.DataAccess;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace ApplicationDashboardMVC.Controllers
- {
- public class CustomerOrderController : Controller
- {
-
- public ActionResult Index()
- {
- return View();
- }
-
- [HttpGet]
- public ActionResult CustomersList()
- {
- return View();
- }
-
- [HttpGet]
- public ActionResult GetCustomers()
- {
- using (DashboardContext _context = new DashboardContext())
- {
- var customerList = _context.CustomerSet.Select(c => new
- {
- c.ID,
- c.CustomerName,
- c.CustomerEmail,
- c.CustomerPhone,
- c.CustomerCountry,
- c.CustomerImage
- }).ToList();
-
- return Json(new { data = customerList }, JsonRequestBehavior.AllowGet);
- }
-
-
- }
-
- }
- }
Here, we have added two actions CustomersList decorated with HttpGet attribute and GetCustomers with HttpGet attribute respectively.
CustomersList returns view that contains customer’s datatable whereas GetCustomers retrieves all customers from customer table and returns them in JSON format.
Now, we need to add CustomersList view. To do that, right click on CustomersList action >> Add view >> Add.
CustomersList.cshtml
- @{
- ViewBag.Title = "CustomersList";
- }
-
- <!-- CSS -->
- @*<link href="~/Content/bootstrap.min.css" rel="stylesheet" />*@
- <link href="~/Content/dataTables.bootstrap.min.css" rel="stylesheet" />
-
- <div id="page-wrapper">
- <div class="row">
- <div class="col-lg-12">
- <h1 class="page-header">Customer - Order</h1>
- </div>
- <!-- /.col-lg-12 -->
- </div>
- <!-- /.row -->
- <div class="row">
- <div class="col-lg-12">
- <div class="panel panel-default">
- <div class="panel-heading">
- CUSTOMER LIST
- </div>
- <div class="panel-body">
- <div class="row">
- <div class="col-lg-12">
-
- <table id="myDataTable" class="table table-bordered table-striped table-hover">
- <thead>
- <tr>
- <th>Customer Profil</th>
- <th>Customer ID</th>
- <th>Customer Name</th>
- <th>Customer Email</th>
- <th>Customer Phone</th>
- <th>Customer Country</th>
- <th>Order</th>
-
- </tr>
- </thead>
- </table>
-
- </div>
- </div>
- <!-- /.row (nested) -->
- </div>
- <!-- /.panel-body -->
- </div>
- <!-- /.panel -->
- </div>
- <!-- /.col-lg-12 -->
- </div>
- <!-- /.row -->
- </div>
- <!-- /#page-wrapper -->
-
- @section Scripts{
-
- <!-- JS -->
- @*<script src="~/Scripts/jquery-1.10.2.min.js"></script>*@
- <script src="https://cdn.datatables.net/1.10.13/js/jquery.dataTables.min.js"></script>
- @*<script src="~/Scripts/bootstrap.min.js"></script>*@
- <script src="~/Scripts/dataTables.bootstrap.min.js"></script>
-
- <script type="text/javascript">
-
- $(document).ready(function () {
-
-
- var oTable = $("#myDataTable").DataTable({
-
- "ajax": {
- "url": "/CustomerOrder/GetCustomers",
- "type": "GET",
- "dataType": "json"
- },
-
- "columns": [
- {
- "data": "CustomerImage", "width": "50px", "render": function (data) {
- return '<img class="rounded img-thumbnail" style="width:60px; height:58px;" src="/Images/Customers/' + data + '"/>';
- }
- },
- { "data": "ID", "autowidth": true },
- { "data": "CustomerName", "autowidth": true },
- { "data": "CustomerEmail", "autowidth": true },
- { "data": "CustomerPhone", "autowidth": true },
- { "data": "CustomerCountry", "autowidth": true },
- {
- "data": "ID", "width": "50px", "render": function (data) {
-
- return '<a href=/Products/ProductList/'+ data + ' class="btn btn-primary">Order</a>';
-
- }
- }
- ]
- });
-
- });
-
- </script>
-
- }
Notice that, we must add DataTable libraries in order to display customers list into DataTable grid, thus do not forget add the following libraries.
- <script src="https://cdn.datatables.net/1.10.13/js/jquery.dataTables.min.js"></script>
- <script src="~/Scripts/dataTables.bootstrap.min.js"></script>
ProductsController.cs
- using ApplicationDashboardMVC.DataAccess;
- using ApplicationDashboardMVC.DataAccess.Entitites;
- using ApplicationDashboardMVC.Models;
- using System;
- using System.Collections.Generic;
- using System.Data.Entity;
- using System.Globalization;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace ApplicationDashboardMVC.Controllers
- {
- public class ProductsController : Controller
- {
-
- public static List<ProductsViewModel> productList = new List<ProductsViewModel>();
-
-
- public ActionResult Index()
- {
- return View();
- }
-
- [HttpGet]
- public ActionResult ProductList(int id)
- {
- Session["CustomerId"] = id;
-
- return View();
- }
-
- [HttpGet]
- public ActionResult GetProductByCategory(string category)
- {
- using (DashboardContext _context = new DashboardContext())
- {
- List<ProductsViewModel> productList = _context.ProductSet
- .Where(p => p.ProductType.ToLower().Equals(category.ToLower()))
- .Select(p => new ProductsViewModel
- {
- ProductID = p.ID,
- ProductName = p.ProductName,
- UnitPriceProduct = p.UnitPrice,
- UnitsInStock = p.UnitsInStock,
- ProductImage = p.ProductImage,
- ProductType = p.ProductType
-
- }).ToList();
-
- return PartialView("~/Views/Products/GetProductByCategory.cshtml", productList);
-
- }
-
- }
-
- [HttpPost]
- public ActionResult ShoppingCart(ProductsViewModel product)
- {
- string message = string.Empty;
-
- if(product != null)
- {
- productList.Add(product);
- message = "product has been added successfully !";
- }
- else
- {
- message = "something Wrong !";
- }
-
- return Json( new { message = message}, JsonRequestBehavior.AllowGet);
- }
-
- public ActionResult DisplayShoppingCart()
- {
- List<ProductsViewModel> myShoppingCart = productList;
-
- return PartialView("~/Views/Products/DisplayShoppingCart.cshtml", myShoppingCart);
- }
-
-
- [HttpPost]
- public ActionResult AddOrder(int[] arrIdProduct, int[] arrQteProduct)
- {
- int countProduct = arrIdProduct.Length;
- int customerId = (int)Session["CustomerId"];
- bool statusTran = false;
-
- DashboardContext _context = new DashboardContext();
-
- using (DbContextTransaction dbTran = _context.Database.BeginTransaction())
- {
- try
- {
- Customer customer = _context.CustomerSet.Find(customerId);
- if (customer != null)
- {
- customer.Orders.Add(new Order { OrderDate = DateTime.Now });
- }
-
- Order orderSelected = customer.Orders.LastOrDefault();
-
- if (orderSelected != null)
- {
- for (int i = 0; i < countProduct; i++)
- {
- Product selectedProduct = _context.ProductSet.Find(arrIdProduct[i]);
- orderSelected.OrderDetail.Add(new OrderDetails { Product = selectedProduct, Quatity = arrQteProduct[i] });
- }
- }
-
-
- int countResult = _context.SaveChanges();
-
-
- dbTran.Commit();
-
- if(countProduct > 0)
- {
- statusTran = true;
- productList.Clear();
- }
-
-
- }
- catch (Exception)
- {
- dbTran.Rollback();
- }
- }
-
-
- return Json(new { data = statusTran }, JsonRequestBehavior.AllowGet);
- }
-
-
- }
- }
Let’s explain the different actions implemented within products controller.
ProductList action has an id as parameter which means customer id that would make an order.
Now, we are going add ProductList view. Right click on ProductList action >> Add View >> Add.
ProductList.cshtml
GetProductByCategory accepts category as parameter and it is used to retrieve products from database based on the given category, then display them into GetProductByCategory partial view.
In order to display products by category, we will add new partial view with GetProductByCategory as name.
GetProductByCategory.cshtml
- @model IEnumerable<ApplicationDashboardMVC.Models.ProductsViewModel>
- @using ApplicationDashboardMVC.Helpers;
-
- <div class="row">
-
- @if (Model != null && Model.Any())
- {
- foreach (var product in Model)
- {
-
- <div class="col-md-4">
- <div class="thumbnail">
-
- @Html.ProductImage(product.ProductType, product.ProductImage, "300px", "165px")
-
- <div class="caption">
- <h3 style="text-align:center">@product.ProductName</h3>
-
- <span style="position: relative; left: 29%; font-size: 16px;" class="label label-default">
- @string.Format("{0} {1}", product.UnitPriceProduct, "$")
- </span>
-
- <select id="[email protected]" class="form-control" style="margin-top: 10px;">
- <option value="1">1</option>
- <option value="2">2</option>
- <option value="3">3</option>
- <option value="4">4</option>
- <option value="5">5</option>
- </select>
-
- <p>
- <a class="btn btn-success" id="test" role="button"
- data-productId="@product.ProductID"
- data-productImage="@product.ProductImage"
- data-productName="@product.ProductName"
- data-productType="@product.ProductType"
- data-UnitPriceProduct="@product.UnitPriceProduct"
- style="margin-left: 65px; margin-top: 10px;">
-
- <span class="glyphicon glyphicon-shopping-cart"></span> Add To Card
- </a>
- @*<button type="button" class="btn btn-success" style="margin-left: 25%; margin-top: 2%;">
- <span class="glyphicon glyphicon-shopping-cart"></span> Add To Card
- </button>*@
- </p>
-
- </div> <!-- END caption -->
-
- </div> <!--END thumbnail-->
-
- </div> <!-- END col-md-4-->
-
- }
-
- }
-
-
- </div>
- <!-- /.row (nested) -->
-
- <!-- JS -->
-
-
- <script type="text/javascript">
-
- $(document).ready(function () {
-
- $('.btn-success').click(function () {
-
- var selectedProduct = {
-
- ProductID: $(this).attr('data-productId'),
- ProductImage: $(this).attr('data-productImage'),
- ProductName: $(this).attr('data-productName'),
- ProductType: $(this).attr('data-productType'),
- UnitPriceProduct: $(this).attr('data-UnitPriceProduct'),
- QteSelected: $('#Qte_' + $(this).attr('data-productId')).val()
- };
-
- console.log(selectedProduct);
-
- $.ajax({
- type: 'POST',
- url: '@Url.Action("ShoppingCart", "Products")',
- data: selectedProduct,
- success: function (response) {
- alert(response.message);
- },
- error: function (response) {
- alert(response.message);
- }
-
- });
-
- });
-
-
-
- });
-
- </script>
ShoppingCart action is used when customers select their products, then they will be added in memory at first this is why we have used productList.
public static List<ProductsViewModel> productList = new List<ProductsViewModel>();
Now, to display all the selected products by customer, we will add DisplayShoppingCart action which is able to show all customer’s products.
So, what we need to do, it’s adding new partial view with DisplayShoppingCart as name then copy-past the following code snippet.
DisplayShoppingCart.cshtml
- @model IEnumerable<ApplicationDashboardMVC.Models.ProductsViewModel>
- @using ApplicationDashboardMVC.Helpers;
-
- @{
- decimal totalOrder = 0;
- }
-
- @if (Model != null && Model.Any())
- {
- using (Html.BeginForm("AddOrder", "Products", new { id = "f"}))
- {
- <div class="row">
-
- <div class="col-md-12">
-
- <table id="tableOrder" class="table table-hover">
- <tr>
- <th>Product Image</th>
- <th>Product Name</th>
- <th>Unit Price</th>
- <th>Qte Selected</th>
- <th>Product Type</th>
- <th>Total Price</th>
- </tr>
- @foreach (var product in Model)
- {
- <tr>
- <td>
- @Html.ProductImage(product.ProductType, product.ProductImage, "60px", "58px")
- </td>
- <td>@product.ProductName</td>
- <td>@string.Format("{0} $", product.UnitPriceProduct)</td>
- <td>@product.QteSelected</td>
- <td>@ProductType(product.ProductType)</td>
- <td>@string.Format("{0} $", (product.UnitPriceProduct * product.QteSelected))</td>
- </tr>
- totalOrder += (product.QteSelected * product.UnitPriceProduct);
-
- @Html.HiddenFor(p=>product.ProductID)
- @Html.HiddenFor(p => product.QteSelected)
-
- }
- </table>
-
- <!-- TOTAL PRICE-->
- <h4 style="margin-left: 66%;">Total : <span class="label label-info">@string.Format("{0} $", totalOrder)</span></h4>
- </div>
- </div>
-
- <div class="modal-footer">
- <button type="button" class="btn btn-secondary" id="close" data-dismiss="modal">Close</button>
- <button type="button" class="btn btn-primary" id="SaveOrder">Save Order</button>
- </div> <!-- MODAL FOOTER-->
- }
- }
- else
- {
- <div class="alert alert-warning" role="alert"> your basket is empty !</div>
- }
-
-
- <!-- HELPER -->
-
- @helper ProductType(string productType) {
-
- switch (productType)
- {
- case "Cars":
- <span class="label label-success">@productType</span>
- break;
- case "Clothing":
- <span class="label label-warning">@productType</span>
- break;
- case "Electronics":
- <span class="label label-info">@productType</span>
- break;
- }
- }
-
- <!--JS-->
-
- <script type="text/javascript">
-
- $(document).ready(function () {
-
-
- $('img').addClass('rounded img-thumbnail');
-
-
- $("#SaveOrder").click(function () {
-
- var $form = $(this).closest('form');
- var dataProduct = $form.serializeArray();
-
- console.log(dataProduct);
-
- var arrIdProduct = [];
- var arrQteProduct = [];
-
- for( i = 0; i < dataProduct.length; i++)
- {
- if (dataProduct[i].name == 'product.ProductID')
- {
- arrIdProduct.push(dataProduct[i].value);
- }
- else if (dataProduct[i].name == 'product.QteSelected')
- {
- arrQteProduct.push(dataProduct[i].value);
-
- }
- }
-
- $.ajax({
- type: 'POST',
- url: '@Url.Action("AddOrder", "Products")',
- data: { arrIdProduct, arrQteProduct },
- success: function (response) {
- if(response.data == true)
- {
- alert("Order has saved successfully ");
- }
- else
- {
- alert("Something Wrong ! ");
- }
-
- },
- error: function (error) {
- alert("Something Wrong ! ");
- }
- });
- });
-
- });
-
- </script>
Finally, AddOrder action is responsible to add new order with different products which are included to it.
Now, let's take a look at DashboardController
DashboardController.cs
- using ApplicationDashboardMVC.DataAccess;
- using ApplicationDashboardMVC.Models;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace ApplicationDashboardMVC.Controllers
- {
- public class DashboardController : Controller
- {
-
- public ActionResult Index()
- {
- return View();
- }
-
- public ActionResult Dashboard()
- {
-
- using (DashboardContext _context = new DashboardContext())
- {
- ViewBag.CountCustomers = _context.CustomerSet.Count();
- ViewBag.CountOrders = _context.OrderSet.Count();
- ViewBag.CountProducts = _context.ProductSet.Count();
- }
-
- return View();
- }
-
- public ActionResult GetDetails(string type)
- {
- List<ProductOrCustomerViewModel> result = GetProductOrCustomer(type);
-
- return PartialView("~/Views/Dashboard/GetDetails.cshtml", result);
-
- }
-
-
- public ActionResult TopCustomers()
- {
- List<TopCustomerViewModel> topFiveCustomers = null;
- using (DashboardContext _context = new DashboardContext())
- {
- var OrderByCustomer = (from o in _context.OrderSet
- group o by o.Customer.ID into g
- orderby g.Count() descending
- select new
- {
- CustomerID = g.Key,
- Count = g.Count()
- }).Take(5);
-
- topFiveCustomers = (from c in _context.CustomerSet
- join o in OrderByCustomer
- on c.ID equals o.CustomerID
- select new TopCustomerViewModel
- {
- CustomerName = c.CustomerName,
- CustomerImage = c.CustomerImage,
- CustomerCountry = c.CustomerCountry,
- CountOrder = o.Count
- }).ToList();
- }
-
- return PartialView("~/Views/Dashboard/TopCustomers.cshtml", topFiveCustomers);
- }
-
- public ActionResult OrdersByCountry()
- {
- DashboardContext _context = new DashboardContext();
-
- var ordersByCountry = (from o in _context.OrderSet
- group o by o.Customer.CustomerCountry into g
- orderby g.Count() descending
- select new
- {
- Country = g.Key,
- CountOrders = g.Count()
- }).ToList();
-
- return Json(new { result = ordersByCountry }, JsonRequestBehavior.AllowGet);
- }
-
- public ActionResult CustomersByCountry()
- {
- DashboardContext _context = new DashboardContext();
-
- var customerByCountry = (from c in _context.CustomerSet
- group c by c.CustomerCountry into g
- orderby g.Count() descending
- select new
- {
- Country = g.Key,
- CountCustomer = g.Count()
- }).ToList();
-
- return Json(new { result = customerByCountry }, JsonRequestBehavior.AllowGet);
- }
-
- public ActionResult OrdersByCustomer()
- {
- DashboardContext _context = new DashboardContext();
- var ordersByCustomer = (from o in _context.OrderSet
- group o by o.Customer.ID into g
- select new
- {
- Name = from c in _context.CustomerSet
- where c.ID == g.Key
- select c.CustomerName,
-
- CountOrders = g.Count()
-
- }).ToList();
-
-
- return Json(new { result = ordersByCustomer }, JsonRequestBehavior.AllowGet);
- }
-
-
- public List<ProductOrCustomerViewModel> GetProductOrCustomer(string type)
- {
- List<ProductOrCustomerViewModel> result = null;
-
- using (DashboardContext _context = new DataAccess.DashboardContext())
- {
- if (!string.IsNullOrEmpty(type))
- {
- if (type == "customers")
- {
- result = _context.CustomerSet.Select(c => new ProductOrCustomerViewModel
- {
- Name = c.CustomerName,
- Image = c.CustomerImage,
- TypeOrCountry = c.CustomerCountry,
- Type = "Customers"
-
- }).ToList();
-
- }
- else if (type == "products")
- {
- result = _context.ProductSet.Select(p => new ProductOrCustomerViewModel
- {
- Name = p.ProductName,
- Image = p.ProductImage,
- TypeOrCountry = p.ProductType,
- Type = p.ProductType
-
- }).ToList();
-
- }
- }
-
- return result;
- }
-
- }
- }
- }
Now, we will explain all the actions which are defined within DashboardController.
Dashboard action is the main action that represents our dashboard with different KPIs (Key Performance Indicator).
Dashboard.cshtml
- @{
- ViewBag.Title = "Dashboard";
- }
- <div id="page-wrapper">
- <div class="row">
- <div class="col-lg-12">
- <h1 class="page-header">Dashboard</h1>
- </div>
- <!-- /.col-lg-12 -->
- </div>
- <!-- /.row -->
- <div class="row">
- <div class="col-lg-4 col-md-6">
- <div class="panel panel-primary">
- <div class="panel-heading">
- <div class="row">
- <div class="col-xs-3">
- <i class="fa fa-comments fa-5x"></i>
- </div>
- <div class="col-xs-9 text-right">
- <div class="huge" id="CountCustomers">
- <span>
- @if (ViewBag.CountCustomers != null)
- {
- @ViewBag.CountCustomers;
- }
- </span>
-
- </div>
- <div>Customers!</div>
- </div>
- </div>
- </div>
- <a href="#" class="viewDetails" data-type="customers">
- <div class="panel-footer">
- <span class="pull-left">View Details</span>
- <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
- <div class="clearfix"></div>
- </div>
- </a>
- </div>
- </div>
- <div class="col-lg-4 col-md-6">
- <div class="panel panel-green">
- <div class="panel-heading">
- <div class="row">
- <div class="col-xs-3">
- <i class="fa fa-tasks fa-5x"></i>
- </div>
- <div class="col-xs-9 text-right">
- <div class="huge" id="CountOrders">
- <span>
- @if (ViewBag.CountOrders != null)
- {
- @ViewBag.CountOrders;
- }
- </span>
- </div>
- <div>Orders!</div>
- </div>
- </div>
- </div>
- <a href="#">
- <div class="panel-footer">
- <span class="pull-left">View Details</span>
- <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
- <div class="clearfix"></div>
- </div>
- </a>
- </div>
- </div>
- <div class="col-lg-4 col-md-6">
- <div class="panel panel-yellow">
- <div class="panel-heading">
- <div class="row">
- <div class="col-xs-3">
- <i class="fa fa-shopping-cart fa-5x"></i>
- </div>
- <div class="col-xs-9 text-right">
- <div class="huge" id="CountProducts">
- <span>
- @if (ViewBag.CountProducts != null)
- {
- @ViewBag.CountProducts;
- }
- </span>
- </div>
- <div>Products!</div>
- </div>
- </div>
- </div>
- <a href="#" class="viewDetails" data-type="products">
- <div class="panel-footer">
- <span class="pull-left">View Details</span>
- <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
- <div class="clearfix"></div>
- </div>
- </a>
- </div>
- </div>
-
- </div>
- <!-- /.row -->
- <div class="row">
- <div class="col-lg-8">
- <div class="panel panel-default">
- <div class="panel-heading">
- <i class="fa fa-bar-chart-o fa-fw"></i> ORDERS BY COUNTRY
-
- </div>
- <!-- /.panel-heading -->
- <div class="panel-body">
- <div id="orderByCountry"></div>
- </div>
- <!-- /.panel-body -->
- </div>
- <!-- /.panel -->
- <div class="panel panel-default">
- <div class="panel-heading">
- <i class="fa fa-bar-chart-o fa-fw"></i> ORDERS BY CUSTOMER
- </div>
- <!-- /.panel-heading -->
- <div class="panel-body">
- <div class="row">
-
- <div class="col-lg-12">
- <div id="ordersByCustomer"></div>
- </div>
- <!-- /.col-lg-8 (nested) -->
- </div>
- <!-- /.row -->
- </div>
- <!-- /.panel-body -->
- </div>
- <!-- /.panel -->
- <div class="panel panel-default">
- <div class="panel-heading">
- <i class="fa fa-clock-o fa-fw"></i> CUSTOMERS LIST
- </div>
- <!-- /.panel-heading -->
- <div class="panel-body">
- <table id="myDataTable" class="table table-bordered table-striped table-hover">
- <thead>
- <tr>
- <th>Customer Profil</th>
- <th>Customer ID</th>
- <th>Customer Name</th>
- <th>Customer Email</th>
- <th>Customer Phone</th>
- <th>Customer Country</th>
- </tr>
- </thead>
- </table>
- </div>
- <!-- /.panel-body -->
- </div>
- <!-- /.panel -->
- </div>
- <!-- /.col-lg-8 -->
- <div class="col-lg-4">
- <div class="panel panel-default">
- <div class="panel-heading">
- <i class="fa fa-bell fa-fw"></i> TOP 5 CUSTOMERS
- </div>
- <!-- /.panel-heading -->
- <div class="panel-body topCustomer">
- </div>
- <!-- /.panel-body -->
- </div>
- <!-- /.panel -->
- <div class="panel panel-default">
- <div class="panel-heading">
- <i class="fa fa-bar-chart-o fa-fw"></i> CUSTOMER BY COUNTRY
- </div>
- <div class="panel-body">
- <div id="customerByCountry"></div>
- </div>
- <!-- /.panel-body -->
- </div>
- <!-- /.panel -->
-
- </div>
- <!-- /.col-lg-4 -->
- </div>
- <!-- /.row -->
- </div>
- <!-- /#page-wrapper -->
- <!-- MODAL -->
- <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <h4 class="modal-title" id="exampleModalLabel"> <span class="glyphicon glyphicon-search"></span> View Details </h4>
- <button type="button" class="close" data-dismiss="modal" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </div> <!-- MODEL HEADER-->
- <div class="modal-body">
-
- </div> <!-- MODAL BODY-->
- </div>
- </div>
- </div>
- <!-- JS -->
- @section Scripts{
- <script src="https://cdn.datatables.net/1.10.13/js/jquery.dataTables.min.js"></script>
- <script type="text/javascript" src="https://www.google.com/jsapi"></script>
- <script type="text/javascript" src="https://www.google.com/uds/api/visualization/1.0/40ff64b1d9d6b3213524485974f36cc0/format+en,default+en,ui+en,corechart+en.I.js"></script>
- <script src="~/Scripts/dataTables.bootstrap.min.js"></script>
- <script type="text/javascript">
-
- google.load("visualization", "1", { packages: ["corechart"] });
- $(document).ready(function () {
-
-
-
-
- $(".viewDetails").click(function () {
- $(".modal-body").html('');
- $.ajax({
- type: 'GET',
- url: '@Url.Action("GetDetails", "Dashboard")',
- data: { type: $(this).attr("data-type") },
- success: function (response) {
- $(".modal-body").html(response);
- $("#exampleModal").modal('show');
- },
- error: function () {
- alert("Something wrong");
- }
- });
- });
-
- $.ajax({
- type: 'GET',
- url: '@Url.Action("TopCustomers", "Dashboard")',
- success: function (response) {
- $(".topCustomer").html(response);
- },
- error: function () {
- alert("Something Wrong");
- }
- });
-
-
- OrdersByCountry()
-
-
- CustomersByCountry()
-
-
- OrdersByCustomer()
-
-
- CustomerList()
-
- function OrdersByCountry() {
-
- $.ajax({
- type: 'GET',
- url: '@Url.Action("OrdersByCountry", "Dashboard")',
- success: function (response) {
- console.log(response);
-
- var data = new google.visualization.DataTable();
-
- data.addColumn('string', 'Country');
- data.addColumn('number', 'CountOrders');
-
- for (var i = 0; i < response.result.length; i++) {
- data.addRow([response.result[i].Country, response.result[i].CountOrders]);
- }
-
-
- var chart = new google.visualization.ColumnChart(document.getElementById('orderByCountry'));
-
- chart.draw(data,
- {
- title: "",
- position: "top",
- fontsize: "14px",
- chartArea: { width: '100%' },
- });
- },
- error: function () {
- alert("Error loading data!");
- }
- });
-
- }
-
- function CustomersByCountry() {
-
- $.ajax({
- type: 'GET',
- url: '@Url.Action("CustomersByCountry", "Dashboard")',
- success: function (response) {
-
- console.log(response);
-
- var data = new google.visualization.DataTable();
-
- data.addColumn('string', 'Country');
- data.addColumn('number', 'CountCustomer');
-
- for (var i = 0; i < response.result.length; i++) {
- data.addRow([response.result[i].Country, response.result[i].CountCustomer]);
- }
-
-
- var chart = new google.visualization.PieChart(document.getElementById('customerByCountry'));
-
- chart.draw(data,
- {
- title: "",
- position: "top",
- fontsize: "14px",
- chartArea: { width: '100%' },
- });
- },
- error: function () {
- alert("Error loading data!");
- }
- });
-
- }
- function OrdersByCustomer() {
- $.ajax({
- type: 'GET',
- url: '@Url.Action("OrdersByCustomer", "Dashboard")',
- success: function (response) {
- console.log(response);
- var data = new google.visualization.DataTable();
- data.addColumn('string', 'Name');
- data.addColumn('number', 'CountOrders');
- for (var i = 0; i < response.result.length; i++) {
- data.addRow([response.result[i].Name[0], response.result[i].CountOrders]);
- }
- var chart = new google.visualization.BarChart(document.getElementById('ordersByCustomer'));
-
- chart.draw(data,
- {
- title: "",
- position: "top",
- fontsize: "14px",
- chartArea: { width: '100%' },
- });
- },
- error: function () {
- alert("Error loading data!");
- }
- });
-
- }
- function CustomerList() {
-
- var oTable = $(".panel #myDataTable").DataTable({
-
- "ajax": {
- "url": "/CustomerOrder/GetCustomers",
- "type": "GET",
- "dataType": "json"
- },
-
- "columns": [
- {
- "data": "CustomerImage", "width": "50px", "render": function (data) {
- return '<img class="rounded img-thumbnail" style="width:60px; height:58px;" src="/Images/Customers/' + data + '"/>';
- }
- },
- { "data": "ID", "autowidth": true },
- { "data": "CustomerName", "autowidth": true },
- { "data": "CustomerEmail", "autowidth": true },
- { "data": "CustomerPhone", "autowidth": true },
- { "data": "CustomerCountry", "autowidth": true }
- ]
- });
- }
- });
- </script>
- }
Here, GetDetails action is responsible to get all products or customers based on type parameter which takes as value customer or product type then we will loop the returned result within GetDetails partial view.
GetDetails.cshtml
Copy-past the following code snipped
- @model IEnumerable<ApplicationDashboardMVC.Models.ProductOrCustomerViewModel>
- @using ApplicationDashboardMVC.Helpers;
-
- <table class="table table-hover">
-
- @foreach (var md in Model)
- {
- <tr>
- <td> @Html.ProductImage(@md.Type, @md.Image, "60px", "58px") </td>
- <td>@md.Name </td>
- <td>@md.TypeOrCountry </td>
- </tr>
- }
-
- </table>
-
- <script type="text/javascript">
-
- $('img').addClass('rounded img-thumbnail');
-
- </script>
TopCustomers action is used to get top 5 customers who made more orders, then we will use TopCustomers partial view to display result.
TopCustomers.cshtml
- @model IEnumerable<ApplicationDashboardMVC.Models.TopCustomerViewModel>
-
- <div class="list-group">
-
- @foreach (var customer in Model)
- {
- <a href="#" class="list-group-item">
- <div style="display: inline-block;width: 60px;">
- <img class="rounded img-thumbnail" src="@string.Format("/Images/Customers/{0}", customer.CustomerImage)" alt="" style="width:50px; height:60px;" />
- </div>
-
- @customer.CustomerName
- <span class="label label-info"> @string.Format("{0} : {1}", "Count Orders", customer.CountOrder) </span>
- <span class="label label-success" style="margin-left: 10px;"> @string.Format("{0} : {1}", "From", customer.CustomerCountry) </span>
-
- </a>
- }
-
- </div>
Next, OrdersByCountry action will help us to return as result the number of orders by country in JSON format.
Now, let’s switch to CustomersByCountry which has the role to return the number of customers by country in JSON format.
Finally, we have OrdersbyCustomer action which is used to return the number of orders by customer.
Note
Do not forget to add the following view models
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace ApplicationDashboardMVC.Models
- {
- public class ProductsViewModel
- {
- public int ProductID { get; set; }
- public string ProductName { get; set; }
- public decimal UnitPriceProduct { get; set; }
- public int UnitsInStock { get; set; }
- public string ProductImage { get; set; }
- public string ProductType { get; set; }
- public int QteSelected { get; set; }
-
- }
-
- public class ProductOrCustomerViewModel
- {
- public string Name { get; set; }
- public string Image { get; set; }
- public string TypeOrCountry { get; set; }
- public string Type { get; set; }
- }
-
- public class TopCustomerViewModel
- {
- public string CustomerName { get; set; }
- public string CustomerImage { get; set; }
- public string CustomerCountry { get; set; }
- public int CountOrder { get; set; }
- }
- }
That’s all, Please send your feedback and queries in comments box.