diff --git a/Model/Response.cs b/Model/Response.cs index 08957a0..d9c2720 100644 --- a/Model/Response.cs +++ b/Model/Response.cs @@ -17,6 +17,8 @@ namespace Model public string? UserName { get; set; } // To store the user's name public string? UserEmail { get; set; } // To store the user's email public DateTime SubmissionDate { get; set; } + + public List ResponseDetails { get; set; } = new List(); } } diff --git a/Services/Implemnetation/NotificationHub.cs b/Services/Implemnetation/NotificationHub.cs new file mode 100644 index 0000000..94e4432 --- /dev/null +++ b/Services/Implemnetation/NotificationHub.cs @@ -0,0 +1,14 @@ + +using Microsoft.AspNetCore.SignalR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Services.Implemnetation +{ + public class NotificationHub:Hub + { + } +} diff --git a/Services/Services.csproj b/Services/Services.csproj index 649d9e9..7e048a3 100644 --- a/Services/Services.csproj +++ b/Services/Services.csproj @@ -8,6 +8,7 @@ + diff --git a/Web/Areas/Admin/Controllers/AdminController.cs b/Web/Areas/Admin/Controllers/AdminController.cs index b14c915..817d2e1 100644 --- a/Web/Areas/Admin/Controllers/AdminController.cs +++ b/Web/Areas/Admin/Controllers/AdminController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Model; using Services.Interaces; +using System.Security.Claims; using Web.ViewModel.DashboardVM; namespace Web.Areas.Admin.Controllers @@ -14,11 +15,13 @@ namespace Web.Areas.Admin.Controllers { private readonly SignInManager _signInManager; private readonly IDashboardRepository _dashboard; + private readonly UserManager _userManager; - public AdminController(SignInManager signInManager,IDashboardRepository dashboard) + public AdminController(SignInManager signInManager,IDashboardRepository dashboard, UserManager userManager) { _signInManager = signInManager; _dashboard = dashboard; + _userManager = userManager; } public async Task Index() { @@ -30,12 +33,56 @@ namespace Web.Areas.Admin.Controllers { ModelCounts = modelCounts, BannerSelections = bannerSelections, - FooterSelections = footerSelections + FooterSelections = footerSelections, + PerformanceData = new List(), + VisitorData = new List() // Initialize the new property }; + if (User.Identity.IsAuthenticated) + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + var user = await _userManager.FindByIdAsync(userId); + if (user != null) + { + viewModel.FirstName = user.FirstName; + viewModel.LastName = user.LastName; + } + } + else + { + viewModel.FirstName = "Guest"; + viewModel.LastName = string.Empty; + } return View(viewModel); } + + [HttpGet] + public JsonResult GetVisitorData() + { + var visitorData = new List + { + new VisitorDataViewModel { Time = DateTime.Now.ToString("HH:mm:ss"), VisitorCount = new Random().Next(0, 500) }, + new VisitorDataViewModel { Time = DateTime.Now.AddSeconds(-5).ToString("HH:mm:ss"), VisitorCount = new Random().Next(0, 500) }, + new VisitorDataViewModel { Time = DateTime.Now.AddSeconds(-10).ToString("HH:mm:ss"), VisitorCount = new Random().Next(0, 500) } + }; + + return Json(visitorData); + } + + [HttpGet] + public JsonResult GetPerformanceData() + { + var performanceData = new List + { + new PerformanceDataViewModel { Time = DateTime.Now.ToString("HH:mm:ss"), CPUUsage = new Random().Next(0, 100), MemoryUsage = new Random().Next(0, 100) }, + new PerformanceDataViewModel { Time = DateTime.Now.AddSeconds(-5).ToString("HH:mm:ss"), CPUUsage = new Random().Next(0, 100), MemoryUsage = new Random().Next(0, 100) }, + new PerformanceDataViewModel { Time = DateTime.Now.AddSeconds(-10).ToString("HH:mm:ss"), CPUUsage = new Random().Next(0, 100), MemoryUsage = new Random().Next(0, 100) } + }; + + return Json(performanceData); + } + [HttpPost] [ValidateAntiForgeryToken] public async Task Logout() diff --git a/Web/Areas/Admin/Controllers/UserResponseStatusController.cs b/Web/Areas/Admin/Controllers/UserResponseStatusController.cs index 330b23d..4c4e27d 100644 --- a/Web/Areas/Admin/Controllers/UserResponseStatusController.cs +++ b/Web/Areas/Admin/Controllers/UserResponseStatusController.cs @@ -289,52 +289,291 @@ namespace Web.Areas.Admin.Controllers } - //private IActionResult GenerateExcelReport(List responses) + + + + + public async Task GenerateQuestionnairePdfReport(int questionnaireId) + { + var response = await _context.Responses + .Include(r => r.Questionnaire) + .Include(r => r.ResponseDetails) + .ThenInclude(rd => rd.Question) + .ThenInclude(q => q.Answers) + .Include(r => r.ResponseDetails) + .ThenInclude(rd => rd.ResponseAnswers) + .FirstOrDefaultAsync(r => r.QuestionnaireId == questionnaireId); + + if (response == null) + { + return NotFound(); + } + + return GeneratePdfReportForQuestionnaire(response); + } + + private IActionResult GeneratePdfReportForQuestionnaire(Response response) + { + var userName = response.UserName; + var userEmail = response.UserEmail; + + var stream = new MemoryStream(); + var document = new Document(PageSize.A4, 50, 50, 25, 25); + var writer = PdfWriter.GetInstance(document, stream); + writer.CloseStream = false; // Prevent the stream from being closed when the document is closed + + document.Open(); + + // Add a title + var titleFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 18, BaseColor.BLACK); + var title = new Paragraph($"Report for {response.Questionnaire.Title}", titleFont) + { + Alignment = Element.ALIGN_CENTER, + SpacingAfter = 20 + }; + document.Add(title); + + // Add a logo + var logoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "logo.png"); + if (System.IO.File.Exists(logoPath)) + { + var logo = Image.GetInstance(logoPath); + logo.ScaleToFit(100f, 100f); + logo.Alignment = Image.ALIGN_CENTER; + document.Add(logo); + } + + // Add a table + var headerFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 14, BaseColor.WHITE); + var cellFont = FontFactory.GetFont(FontFactory.HELVETICA, 12, BaseColor.BLACK); + var table = new PdfPTable(2) + { + WidthPercentage = 100, + SpacingBefore = 20, + SpacingAfter = 20 + }; + table.SetWidths(new float[] { 1, 3 }); + + var cellForResponse = new PdfPCell(new Phrase($"{response.UserName} ({response.UserEmail})", headerFont)) + { + Colspan = 2, + BackgroundColor = new BaseColor(0, 150, 0), + HorizontalAlignment = Element.ALIGN_CENTER, + Padding = 10 + }; + + table.AddCell(cellForResponse); + var cell = new PdfPCell(new Phrase($"Survey: {response.Questionnaire.Title}", headerFont)) + { + Colspan = 2, + BackgroundColor = new BaseColor(0, 150, 0), + HorizontalAlignment = Element.ALIGN_CENTER, + Padding = 10 + }; + table.AddCell(cell); + + table.AddCell(new PdfPCell(new Phrase("Submitted on:", cellFont)) { Padding = 5 }); + table.AddCell(new PdfPCell(new Phrase(response.SubmissionDate.ToString(), cellFont)) { Padding = 5 }); + + foreach (var detail in response.ResponseDetails) + { + table.AddCell(new PdfPCell(new Phrase("Question:", cellFont)) { Padding = 5 }); + table.AddCell(new PdfPCell(new Phrase(detail.Question.Text, cellFont)) { Padding = 5 }); + + if (detail.QuestionType == QuestionType.Text || detail.QuestionType == QuestionType.Slider || detail.QuestionType == QuestionType.Open_ended) + { + table.AddCell(new PdfPCell(new Phrase("Answer:", cellFont)) { Padding = 5 }); + table.AddCell(new PdfPCell(new Phrase(detail.TextResponse, cellFont)) { Padding = 5 }); + } + else + { + table.AddCell(new PdfPCell(new Phrase("Answers:", cellFont)) { Padding = 5 }); + var answers = string.Join(", ", detail.ResponseAnswers.Select(a => detail.Question.Answers.FirstOrDefault(ans => ans.Id == a.AnswerId)?.Text)); + table.AddCell(new PdfPCell(new Phrase(answers, cellFont)) { Padding = 5 }); + } + } + + document.Add(table); + document.Close(); + writer.Close(); + + stream.Position = 0; + return File(stream, "application/pdf", $"{response.Questionnaire.Title}_{userEmail}.pdf"); + } + + public async Task GenerateQuestionnaireExcelReport(int questionnaireId) + { + var response = await _context.Responses + .Include(r => r.Questionnaire) + .Include(r => r.ResponseDetails) + .ThenInclude(rd => rd.Question) + .ThenInclude(q => q.Answers) + .Include(r => r.ResponseDetails) + .ThenInclude(rd => rd.ResponseAnswers) + .FirstOrDefaultAsync(r => r.QuestionnaireId == questionnaireId); + + if (response == null) + { + return NotFound(); + } + + return GenerateExcelReportForQuestionnaire(response); + } + + + private IActionResult GenerateExcelReportForQuestionnaire(Response response) + { + var userName = response.UserName; + var userEmail = response.UserEmail; + + using (var package = new ExcelPackage()) + { + var worksheet = package.Workbook.Worksheets.Add("Report"); + + // Add a logo + var logoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "logo.png"); + if (System.IO.File.Exists(logoPath)) + { + var logo = new FileInfo(logoPath); + var picture = worksheet.Drawings.AddPicture("Logo", logo); + picture.SetPosition(0, 0, 2, 0); + picture.SetSize(300, 60); // Adjust the size as needed + } + + // Add user details + worksheet.Cells[5, 1].Value = $"{userName} ({userEmail})"; + worksheet.Cells[5, 1, 5, 4].Merge = true; + worksheet.Cells[5, 1, 5, 4].Style.Font.Size = 15; + worksheet.Cells[5, 1, 5, 4].Style.Font.Bold =true; + worksheet.Cells[5, 1, 5, 4].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + + // Add a title + worksheet.Cells[6, 1].Value = $"Report for {response.Questionnaire.Title}"; + worksheet.Cells[6, 1, 6, 4].Merge = true; + worksheet.Cells[6, 1, 6, 4].Style.Font.Size = 18; + worksheet.Cells[6, 1, 6, 4].Style.Font.Bold = true; + worksheet.Cells[6, 1, 6, 4].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + + // Add headers + worksheet.Cells[7, 1].Value = "Survey"; + worksheet.Cells[7, 2].Value = "Submitted on"; + worksheet.Cells[7, 3].Value = "Question"; + worksheet.Cells[7, 4].Value = "Response"; + + using (var range = worksheet.Cells[7, 1, 7, 4]) + { + range.Style.Font.Bold = true; + range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; + range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray); + range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + } + + // Add data + var row = 8; + worksheet.Cells[row, 1].Value = response.Questionnaire.Title; + worksheet.Cells[row, 2].Value = response.SubmissionDate.ToString(); + row++; + + foreach (var detail in response.ResponseDetails) + { + worksheet.Cells[row, 3].Value = detail.Question.Text; + + if (detail.QuestionType == QuestionType.Text || detail.QuestionType == QuestionType.Slider || detail.QuestionType == QuestionType.Open_ended) + { + worksheet.Cells[row, 4].Value = detail.TextResponse; + } + else + { + var answers = string.Join(", ", detail.ResponseAnswers.Select(a => detail.Question.Answers.FirstOrDefault(ans => ans.Id == a.AnswerId)?.Text)); + worksheet.Cells[row, 4].Value = answers; + } + row++; + } + + worksheet.Cells.AutoFitColumns(); + + var stream = new MemoryStream(); + package.SaveAs(stream); + stream.Position = 0; + + return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{response.Questionnaire.Title}_{userEmail}.xlsx"); + } + } + + //private IActionResult GenerateExcelReportForQuestionnaire(Response response) //{ - // var userName = responses.First().UserName; - // var userEmail = responses.First().UserEmail; + // var userName = response.UserName; + // var userEmail = response.UserEmail; // using (var package = new ExcelPackage()) // { // var worksheet = package.Workbook.Worksheets.Add("Report"); - // worksheet.Cells[1, 1].Value = $"Report for {userName} ({userEmail})"; - // worksheet.Cells[2, 1].Value = "Survey"; - // worksheet.Cells[2, 2].Value = "Submitted on"; - // worksheet.Cells[2, 3].Value = "Question"; - // worksheet.Cells[2, 4].Value = "Response"; - - // var row = 3; - // foreach (var response in responses) + // // Add a logo + // var logoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "logo.png"); + // if (System.IO.File.Exists(logoPath)) // { - // worksheet.Cells[row, 1].Value = response.Questionnaire.Title; - // worksheet.Cells[row, 2].Value = response.SubmissionDate.ToString(); - // row++; + // var logo = new FileInfo(logoPath); + // var picture = worksheet.Drawings.AddPicture("Logo", logo); + // picture.SetPosition(0, 0, 0, 0); + // picture.SetSize(300, 70); // Adjust the size as needed + // } - // foreach (var detail in response.ResponseDetails) + // // Add a title + // worksheet.Cells[6, 1].Value = $"Report for {response.Questionnaire.Title}"; + // worksheet.Cells[6, 1, 6, 4].Merge = true; + // worksheet.Cells[6, 1, 6, 4].Style.Font.Size = 18; + // worksheet.Cells[6, 1, 6, 4].Style.Font.Bold = true; + // worksheet.Cells[6, 1, 6, 4].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + + // // Add headers + // worksheet.Cells[7, 1].Value = "Survey"; + // worksheet.Cells[7, 2].Value = "Submitted on"; + // worksheet.Cells[7, 3].Value = "Question"; + // worksheet.Cells[7, 4].Value = "Response"; + + // using (var range = worksheet.Cells[7, 1, 7, 4]) + // { + // range.Style.Font.Bold = true; + // range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; + // range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray); + // range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + // } + + // // Add data + // var row = 8; + // worksheet.Cells[row, 1].Value = response.Questionnaire.Title; + // worksheet.Cells[row, 2].Value = response.SubmissionDate.ToString(); + // row++; + + // foreach (var detail in response.ResponseDetails) + // { + // worksheet.Cells[row, 3].Value = detail.Question.Text; + + // if (detail.QuestionType == QuestionType.Text || detail.QuestionType == QuestionType.Slider || detail.QuestionType == QuestionType.Open_ended) // { - // worksheet.Cells[row, 3].Value = detail.Question.Text; - - // if (detail.QuestionType == QuestionType.Text || detail.QuestionType == QuestionType.Slider || detail.QuestionType == QuestionType.Open_ended) - // { - // worksheet.Cells[row, 4].Value = detail.TextResponse; - // } - // else - // { - // var answers = string.Join(", ", detail.ResponseAnswers.Select(a => detail.Question.Answers.FirstOrDefault(ans => ans.Id == a.AnswerId)?.Text)); - // worksheet.Cells[row, 4].Value = answers; - // } - // row++; + // worksheet.Cells[row, 4].Value = detail.TextResponse; + // } + // else + // { + // var answers = string.Join(", ", detail.ResponseAnswers.Select(a => detail.Question.Answers.FirstOrDefault(ans => ans.Id == a.AnswerId)?.Text)); + // worksheet.Cells[row, 4].Value = answers; // } // row++; // } + // worksheet.Cells.AutoFitColumns(); + // var stream = new MemoryStream(); // package.SaveAs(stream); // stream.Position = 0; - // return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{userName}_report.xlsx"); + // return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{response.Questionnaire.Title}_{userEmail}.xlsx"); // } //} + + + + } } diff --git a/Web/Areas/Admin/Views/Admin/Index.cshtml b/Web/Areas/Admin/Views/Admin/Index.cshtml index 15e61c2..7ec4d12 100644 --- a/Web/Areas/Admin/Views/Admin/Index.cshtml +++ b/Web/Areas/Admin/Views/Admin/Index.cshtml @@ -1,11 +1,64 @@ @model DashboardViewModel +@{ + ViewData["Title"] = "Admin"; +} + + + +
+ + +
+
+
+ +

Welcome

+

@Model.FirstName @Model.LastName

+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+ + +
+ +
+
+
+ +
+
+
+
+ + + +
+ + + -

Admin Dashboard

-
-
-
+ + + diff --git a/Web/Areas/Admin/Views/Questionnaire/Details.cshtml b/Web/Areas/Admin/Views/Questionnaire/Details.cshtml index 249faaa..cca96bc 100644 --- a/Web/Areas/Admin/Views/Questionnaire/Details.cshtml +++ b/Web/Areas/Admin/Views/Questionnaire/Details.cshtml @@ -6,10 +6,13 @@ -
+
+ -
+
Details
@@ -20,7 +23,9 @@

Questionnaire details


- +
+ ID +
Questionnaire
@@ -32,45 +37,26 @@
- +
- + - - - + - +
IdID QuestionnaireDescription Questions
@Model.Id@Model.Id -
-
- - @Html.Raw(Model.Title.Length >= 30 ? Model.Title.Substring(0, 30) : Model.Title) - - Read More - - -
-
-
-
-
- - @Html.Raw(Model.Description.Length >= 30 ? Model.Description.Substring(0, 30) : Model.Title) - - - Read More -
-
+ + @Model.Title +
- +
@@ -83,18 +69,7 @@
Id Question
@question.Id -
-
- - @Html.Raw(question.Text.Length >= 30 ? question.Text.Substring(0, 30) : question.Text) - - Read More - - - - -
-
+ @question.Text
@question.Type @@ -132,10 +107,10 @@
- + @@ -144,65 +119,3 @@ - -@section Scripts { - - -} \ No newline at end of file diff --git a/Web/Areas/Admin/Views/Questionnaire/Index.cshtml b/Web/Areas/Admin/Views/Questionnaire/Index.cshtml index 68adee0..a55b5f5 100644 --- a/Web/Areas/Admin/Views/Questionnaire/Index.cshtml +++ b/Web/Areas/Admin/Views/Questionnaire/Index.cshtml @@ -16,17 +16,16 @@

Create New

- +
- - + @@ -35,28 +34,11 @@ - @* *@ + - @* *@ -
Id TitleDescription Total Questions Questions | Type | Answers ActionAction
@item.Id @item.Title -
-
- @Html.Raw(item.Title.Length >= 30 ? item.Title.Substring(0, 30) : item.Title) - - Read More -
-
+ @item.Title
@Html.Raw(item.Description) - -
-
- @Html.Raw(item.Description.Length >= 30 ? item.Description.Substring(0, 30) : item.Title) - - Read More -
-
-
@* + + + +
+
+
- - + +
@@ -170,7 +220,171 @@ @section Scripts { - + + + + + + +