diff --git a/Model/Answer.cs b/Model/Answer.cs index 2ce01b5..0185bde 100644 --- a/Model/Answer.cs +++ b/Model/Answer.cs @@ -21,6 +21,7 @@ namespace Model [ForeignKey("QuestionId")] public Question? Question { get; set; } + public bool IsOtherOption { get; set; } = false; public string? ConditionJson { get; set; } } } diff --git a/Model/ResponseDetail.cs b/Model/ResponseDetail.cs index 46a3c32..aae8e7b 100644 --- a/Model/ResponseDetail.cs +++ b/Model/ResponseDetail.cs @@ -23,7 +23,7 @@ namespace Model public QuestionType QuestionType { get; set; } public string? TextResponse { get; set; } public List ResponseAnswers { get; set; } = new List(); - + public string? OtherText { get; set; } public ResponseStatus Status { get; set; } = ResponseStatus.Shown; public string? SkipReason { get; set; } // Why it was skipped (JSON of condition) } diff --git a/Web/Areas/Admin/Controllers/QuestionnaireController.cs b/Web/Areas/Admin/Controllers/QuestionnaireController.cs index 0d8bd5c..a367a73 100644 --- a/Web/Areas/Admin/Controllers/QuestionnaireController.cs +++ b/Web/Areas/Admin/Controllers/QuestionnaireController.cs @@ -93,12 +93,8 @@ namespace Web.Areas.Admin.Controllers [HttpPost] public async Task Create(QuestionnaireViewModel viewmodel) { - - - if (ModelState.IsValid) { - var questionnaire = new Questionnaire { Id = viewmodel.Id, @@ -106,7 +102,6 @@ namespace Web.Areas.Admin.Controllers Description = viewmodel.Description, }; - var questions = viewmodel.Questions; foreach (var questionViewModel in viewmodel.Questions) @@ -121,30 +116,27 @@ namespace Web.Areas.Admin.Controllers foreach (var answerViewModel in questionViewModel.Answers) { + // Skip empty answers + if (string.IsNullOrWhiteSpace(answerViewModel.Text)) + continue; + var answer = new Answer { Text = answerViewModel.Text, QuestionId = answerViewModel.QuestionId, - + IsOtherOption = answerViewModel.IsOtherOption // NEW: Handle IsOtherOption property }; - question.Answers.Add(answer); } - questionnaire.Questions.Add(question); } - - - _questionnaire.Add(questionnaire); await _questionnaire.commitAsync(); TempData["Success"] = "Questionnaire created successfully"; - - return RedirectToAction("Index"); } return View(viewmodel); @@ -201,10 +193,9 @@ namespace Web.Areas.Admin.Controllers [HttpPost] public async Task Edit(EditQuestionnaireViewModel viewModel) { - var questionTypes = Enum.GetValues(typeof(QuestionType)) - .Cast() - .Select(e => new SelectListItem { Value = e.ToString(), Text = e.ToString() }); + .Cast() + .Select(e => new SelectListItem { Value = e.ToString(), Text = e.ToString() }); ViewBag.QuestionTypes = questionTypes; if (ModelState.IsValid) @@ -214,7 +205,7 @@ namespace Web.Areas.Admin.Controllers if (existingQuestionnaire == null) { - return NotFound(); // Or handle not found case appropriately + return NotFound(); } // Update the existing questionnaire with the data from the view model @@ -226,22 +217,13 @@ namespace Web.Areas.Admin.Controllers // Iterate through existing questions and remove those not found in the view model foreach (var existingQuestion in existingQuestionnaire.Questions.ToList()) { - // If the ID of the existing question is not found in the view model, remove it if (!viewModel.Questions.Any(q => q.Id == existingQuestion.Id)) { existingQuestionnaire.Questions.Remove(existingQuestion); - } await _questionnaire.Update(existingQuestionnaire); } - // Update the questionnaire with the modified list of questions - - - - - - var newQuestions = new List(); // Update or add new questions @@ -253,11 +235,9 @@ namespace Web.Areas.Admin.Controllers { if (existingQuestion != null) { - var answersToRemove = new List(); existingQuestion.Text = questionViewModel.Text; existingQuestion.Type = questionViewModel.Type; - foreach (var answerViewModel in questionViewModel.Answers) { // Check if the answer already exists @@ -265,32 +245,27 @@ namespace Web.Areas.Admin.Controllers if (answerViewModel.Id == 0) { - - existingQuestion.Answers.Add(new Answer { Text = answerViewModel.Text }); - - + // NEW: Add IsOtherOption property when creating new answers + existingQuestion.Answers.Add(new Answer + { + Text = answerViewModel.Text, + IsOtherOption = answerViewModel.IsOtherOption + }); } else if (answerViewModel.Text == null) { existingQuestion.Answers.Remove(existingAnswer); await _questionnaire.Update(existingQuestionnaire); } - - else if (existingAnswer != null) { - existingAnswer.Text = answerViewModel.Text; + // NEW: Update IsOtherOption property for existing answers + existingAnswer.IsOtherOption = answerViewModel.IsOtherOption; } - } - - - } } - - else { // Create a new question @@ -305,52 +280,33 @@ namespace Web.Areas.Admin.Controllers { if (!string.IsNullOrEmpty(answerViewModel.Text)) { - // Add new answer if text is not null or empty - newQuestion.Answers.Add(new Answer { Text = answerViewModel.Text }); + // NEW: Add IsOtherOption property when creating new answers + newQuestion.Answers.Add(new Answer + { + Text = answerViewModel.Text, + IsOtherOption = answerViewModel.IsOtherOption + }); } } - // Add new question to the list of new questions newQuestions.Add(newQuestion); } + existingQuestionnaire.Questions.AddRange(newQuestions); - //else - //{ - // // Add new question - // var newQuestion = new Question - // { - // Text = questionViewModel.Text, // Make sure question text is not null - // Type = questionViewModel.Type, // Make sure question type is not null - // Answers = new List() // Initialize answers list - // }; - - // foreach (var answerViewModel in questionViewModel.Answers) - // { - // // Add new answer - // newQuestion.Answers.Add(new Answer { Text = answerViewModel.Text }); - // } - - // // Add new question to questionnaire - // existingQuestionnaire.Questions.Add(newQuestion); - //} - } - await _questionnaire.Update(existingQuestionnaire); TempData["Success"] = "Questionnaire updated successfully"; return RedirectToAction(nameof(Index)); } - // If ModelState is not valid, re-display the form with validation errors return View(viewModel); } [HttpGet] public IActionResult Delete(int id) { - var questionTypes = Enum.GetValues(typeof(QuestionType)).Cast(); ViewBag.QuestionTypes = new SelectList(questionTypes); @@ -358,7 +314,7 @@ namespace Web.Areas.Admin.Controllers if (questionnaire == null) { - return NotFound(); // Or handle not found case appropriately + return NotFound(); } var viewModel = new QuestionnaireViewModel @@ -375,7 +331,8 @@ namespace Web.Areas.Admin.Controllers Answers = q.Answers.Select(a => new Answer { Id = a.Id, - Text = a.Text + Text = a.Text, + IsOtherOption = a.IsOtherOption // NEW: Include IsOtherOption property }).ToList() }).ToList() }; @@ -422,7 +379,7 @@ namespace Web.Areas.Admin.Controllers if (questionnaire == null) { - return NotFound(); // Or handle not found case appropriately + return NotFound(); } var viewModel = new QuestionnaireViewModel @@ -439,7 +396,8 @@ namespace Web.Areas.Admin.Controllers Answers = q.Answers.Select(a => new Answer { Id = a.Id, - Text = a.Text + Text = a.Text, + IsOtherOption = a.IsOtherOption // NEW: Include IsOtherOption property }).ToList() }).ToList() }; diff --git a/Web/Areas/Admin/Controllers/UserResponseStatusController.cs b/Web/Areas/Admin/Controllers/UserResponseStatusController.cs index 375d3ac..4e84098 100644 --- a/Web/Areas/Admin/Controllers/UserResponseStatusController.cs +++ b/Web/Areas/Admin/Controllers/UserResponseStatusController.cs @@ -8,8 +8,6 @@ using OfficeOpenXml; using Services.Interaces; using Web.ViewModel.QuestionnaireVM; - - namespace Web.Areas.Admin.Controllers { public class UserResponseStatusController : Controller @@ -17,7 +15,7 @@ namespace Web.Areas.Admin.Controllers private readonly SurveyContext _context; private readonly IUserResponseRepository _userResponse; - public UserResponseStatusController(SurveyContext context,IUserResponseRepository userResponse) + public UserResponseStatusController(SurveyContext context, IUserResponseRepository userResponse) { _context = context; _userResponse = userResponse; @@ -41,7 +39,6 @@ namespace Web.Areas.Admin.Controllers return View(usersWithQuestionnaires); } - public async Task UserResponsesStatus(string userEmail) { var responses = await _context.Responses @@ -72,8 +69,6 @@ namespace Web.Areas.Admin.Controllers return View(viewModel); } - - [HttpPost] public async Task DeleteSelected(string[] selectedEmails) { @@ -95,8 +90,6 @@ namespace Web.Areas.Admin.Controllers return RedirectToAction(nameof(Index)); } - - public async Task GenerateReport(string userEmail, string format) { var responses = await _context.Responses @@ -125,7 +118,6 @@ namespace Web.Areas.Admin.Controllers } } - private IActionResult GeneratePdfReport(List responses) { var userName = responses.First().UserName; @@ -197,6 +189,15 @@ namespace Web.Areas.Admin.Controllers { 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)); + + // NEW: Include "Other" text if available + if (!string.IsNullOrEmpty(detail.OtherText)) + { + answers += string.IsNullOrEmpty(answers) + ? $"Other: {detail.OtherText}" + : $"; Other: {detail.OtherText}"; + } + table.AddCell(new PdfPCell(new Phrase(answers, cellFont)) { Padding = 5 }); } } @@ -211,8 +212,6 @@ namespace Web.Areas.Admin.Controllers return File(stream, "application/pdf", $"{userName}_report.pdf"); } - - private IActionResult GenerateExcelReport(List responses) { var userName = responses.First().UserName; @@ -272,6 +271,15 @@ namespace Web.Areas.Admin.Controllers else { var answers = string.Join(", ", detail.ResponseAnswers.Select(a => detail.Question.Answers.FirstOrDefault(ans => ans.Id == a.AnswerId)?.Text)); + + // NEW: Include "Other" text if available + if (!string.IsNullOrEmpty(detail.OtherText)) + { + answers += string.IsNullOrEmpty(answers) + ? $"Other: {detail.OtherText}" + : $"; Other: {detail.OtherText}"; + } + worksheet.Cells[row, 4].Value = answers; } row++; @@ -289,11 +297,6 @@ namespace Web.Areas.Admin.Controllers } } - - - - - public async Task GenerateQuestionnairePdfReport(int questionnaireId) { var response = await _context.Responses @@ -390,6 +393,15 @@ namespace Web.Areas.Admin.Controllers { 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)); + + // NEW: Include "Other" text if available + if (!string.IsNullOrEmpty(detail.OtherText)) + { + answers += string.IsNullOrEmpty(answers) + ? $"Other: {detail.OtherText}" + : $"; Other: {detail.OtherText}"; + } + table.AddCell(new PdfPCell(new Phrase(answers, cellFont)) { Padding = 5 }); } } @@ -421,7 +433,6 @@ namespace Web.Areas.Admin.Controllers return GenerateExcelReportForQuestionnaire(response); } - private IActionResult GenerateExcelReportForQuestionnaire(Response response) { var userName = response.UserName; @@ -445,7 +456,7 @@ namespace Web.Areas.Admin.Controllers 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.Font.Bold = true; worksheet.Cells[5, 1, 5, 4].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; // Add a title @@ -486,6 +497,15 @@ namespace Web.Areas.Admin.Controllers else { var answers = string.Join(", ", detail.ResponseAnswers.Select(a => detail.Question.Answers.FirstOrDefault(ans => ans.Id == a.AnswerId)?.Text)); + + // NEW: Include "Other" text if available + if (!string.IsNullOrEmpty(detail.OtherText)) + { + answers += string.IsNullOrEmpty(answers) + ? $"Other: {detail.OtherText}" + : $"; Other: {detail.OtherText}"; + } + worksheet.Cells[row, 4].Value = answers; } row++; @@ -500,81 +520,5 @@ namespace Web.Areas.Admin.Controllers return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{response.Questionnaire.Title}_{userEmail}.xlsx"); } } - - //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, 0, 0); - // picture.SetSize(300, 70); // Adjust the size as needed - // } - - // // 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"); - // } - //} - - - - } -} +} \ No newline at end of file diff --git a/Web/Areas/Admin/Views/Questionnaire/Create.cshtml b/Web/Areas/Admin/Views/Questionnaire/Create.cshtml index 1e069ea..c274fdf 100644 --- a/Web/Areas/Admin/Views/Questionnaire/Create.cshtml +++ b/Web/Areas/Admin/Views/Questionnaire/Create.cshtml @@ -1,10 +1,559 @@ - -@model QuestionnaireViewModel +@model QuestionnaireViewModel @{ ViewData["Title"] = "Create"; } + +
@@ -24,17 +573,17 @@
-
-
+
+

Create Questions

@for (int i = 0; i < Model.Questions?.Count; i++) { -
+
- +
@@ -44,10 +593,12 @@ {
+
} +
| @@ -60,7 +611,7 @@
@@ -85,14 +636,15 @@ } - + - - -} \ No newline at end of file +} \ No newline at end of file diff --git a/Web/Areas/Admin/Views/Questionnaire/Edit.cshtml b/Web/Areas/Admin/Views/Questionnaire/Edit.cshtml index ff34695..eeec880 100644 --- a/Web/Areas/Admin/Views/Questionnaire/Edit.cshtml +++ b/Web/Areas/Admin/Views/Questionnaire/Edit.cshtml @@ -4,136 +4,868 @@ ViewData["Title"] = "Edit"; } +
-
-
-
Edit Survey
+
+
+
Edit Survey
+
+
+
+ -
- - -
- - - -
-
- - - -
- -
-
-

Edit existing questions or add new question

+ +
+
+
+ + +
+
+
+
+ + + +
+
+
+ +
+
+

Edit Questions or Add New Questions

+
-
- @for (int i = 0; i < Model.Questions.Count; i++) - { -
-
- -
-
-
- -
-

NEXT QUESTION

-
- -
-
-
+
+ @for (int i = 0; i < Model.Questions.Count; i++) + { +
+
+
+
- - @*
- @Model.Questions[i].Text - | -
*@ -
- @Html.Raw(Model.Questions[i].Text.Length >= 30 ? Model.Questions[i].Text.Substring(0, 30) : Model.Questions[i].Text) - - | | - +
+ Question @(i + 1)
- + - } -
+
+
+
+ @Html.Raw(Model.Questions[i].Text) +
+
+ + +
+
+
+ +
+ }
- -
- - | Back to list -
- -
+
+ +
+ +
+ +
+ + + Back to List + +
+
+