Response questionnaire for multiple choice completed
This commit is contained in:
parent
31faec4f73
commit
ab3daa46f6
10 changed files with 358 additions and 241 deletions
|
|
@ -65,7 +65,7 @@ namespace Web.Areas.Admin.Controllers
|
||||||
// Prepare request body
|
// Prepare request body
|
||||||
var requestBody = new
|
var requestBody = new
|
||||||
{
|
{
|
||||||
model = "babbage-002",
|
model = "gpt-3.5-turbo",
|
||||||
prompt = inputText,
|
prompt = inputText,
|
||||||
max_tokens = 100
|
max_tokens = 100
|
||||||
|
|
||||||
|
|
@ -77,8 +77,6 @@ namespace Web.Areas.Admin.Controllers
|
||||||
// Make HTTP POST request to OpenAI API
|
// Make HTTP POST request to OpenAI API
|
||||||
var response = await httpClient.PostAsync("https://api.openai.com/v1/completions", new StringContent(jsonContent, Encoding.UTF8, "application/json"));
|
var response = await httpClient.PostAsync("https://api.openai.com/v1/completions", new StringContent(jsonContent, Encoding.UTF8, "application/json"));
|
||||||
|
|
||||||
// Check if request was successful
|
|
||||||
//response.EnsureSuccessStatusCode();
|
|
||||||
|
|
||||||
// Read response content
|
// Read response content
|
||||||
string responseBody = await response.Content.ReadAsStringAsync();
|
string responseBody = await response.Content.ReadAsStringAsync();
|
||||||
|
|
|
||||||
|
|
@ -494,9 +494,9 @@ namespace Web.Areas.Admin.Controllers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}?token={tokenWithExpiry}";
|
//var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}?token={tokenWithExpiry}";
|
||||||
|
|
||||||
//var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}";
|
var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}";
|
||||||
|
|
||||||
|
|
||||||
var toEmail = viewModel.Email;
|
var toEmail = viewModel.Email;
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form id="generateForm">
|
<form id="generateForm">
|
||||||
<div class="mb-3 col-12">
|
<div class="mb-3 col-12">
|
||||||
<label for="inputText" class="control-label">Input Text</label>
|
|
||||||
<textarea id="inputText" name="inputText" class="form-control" rows="4"></textarea>
|
<textarea id="inputText" name="inputText" class="form-control" rows="4" placeholder="Write here"></textarea>
|
||||||
<span class="text-danger" id="inputTextError"></span>
|
<span class="text-danger" id="inputTextError"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,27 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Data;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Model;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Services.Interaces;
|
using Services.Interaces;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Web.ViewModel.AnswerVM;
|
||||||
using Web.ViewModel.QuestionnaireVM;
|
using Web.ViewModel.QuestionnaireVM;
|
||||||
|
using Web.ViewModel.QuestionVM;
|
||||||
|
|
||||||
namespace Web.Controllers
|
namespace Web.Controllers
|
||||||
{
|
{
|
||||||
public class QuestionnaireResponseController : Controller
|
public class QuestionnaireResponseController : Controller
|
||||||
{
|
{
|
||||||
private readonly IQuestionnaireRepository _questionnaireRepository;
|
private readonly IQuestionnaireRepository _questionnaireRepository;
|
||||||
|
private readonly SurveyContext _context;
|
||||||
|
|
||||||
public QuestionnaireResponseController(IQuestionnaireRepository questionnaireRepository)
|
public QuestionnaireResponseController(IQuestionnaireRepository questionnaireRepository,SurveyContext context)
|
||||||
{
|
{
|
||||||
_questionnaireRepository = questionnaireRepository;
|
_questionnaireRepository = questionnaireRepository;
|
||||||
|
_context = context;
|
||||||
}
|
}
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
|
|
@ -28,49 +36,108 @@ namespace Web.Controllers
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult DisplayQuestionnaire(int id, string token)
|
public IActionResult DisplayQuestionnaire(int id)
|
||||||
{
|
{
|
||||||
// Check if the token is null or empty
|
|
||||||
if (string.IsNullOrEmpty(token))
|
|
||||||
{
|
|
||||||
ViewBag.ErrorMessage = "The URL is invalid. Please provide a valid token.";
|
|
||||||
return View("Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the token to extract the expiration date and time
|
|
||||||
string[] tokenParts = token.Split('|');
|
|
||||||
if (tokenParts.Length != 2)
|
|
||||||
{
|
|
||||||
ViewBag.ErrorMessage = "The URL is invalid. Please provide a valid token.";
|
|
||||||
return View("Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
string expiryDateTimeString = tokenParts[1];
|
|
||||||
|
|
||||||
// Parse the expiration datetime in UTC format
|
|
||||||
if (!DateTime.TryParseExact(expiryDateTimeString, "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out DateTime expiryDateTimeUtc))
|
|
||||||
{
|
|
||||||
ViewBag.ErrorMessage = "The URL is invalid. Please provide a valid token.";
|
|
||||||
return View("Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the expiration datetime to local time
|
|
||||||
DateTime expiryDateTimeLocal = expiryDateTimeUtc.ToLocalTime();
|
|
||||||
|
|
||||||
// Check if the token is expired (accounting for UTC+2 offset)
|
|
||||||
if (expiryDateTimeLocal < DateTime.Now.AddHours(2))
|
|
||||||
{
|
|
||||||
|
|
||||||
return RedirectToAction(nameof(Error));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the questionnaire using the numeric ID
|
|
||||||
var questionnaire = _questionnaireRepository.GetQuestionnaireWithQuestionAndAnswer(id);
|
var questionnaire = _questionnaireRepository.GetQuestionnaireWithQuestionAndAnswer(id);
|
||||||
|
|
||||||
return View(questionnaire);
|
return View(MapToViewModel(questionnaire));
|
||||||
}
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult DisplayQuestionnaire([FromForm] ResponseQuestionnaireViewModel questionnaire)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var question in questionnaire.Questions)
|
||||||
|
{
|
||||||
|
var dbQuestion = _context.Questions.Include(q => q.Answers).FirstOrDefault(q => q.Id == question.Id);
|
||||||
|
|
||||||
|
if (dbQuestion != null)
|
||||||
|
{
|
||||||
|
foreach (var selectedId in question.SelectedAnswerIds)
|
||||||
|
{
|
||||||
|
var selectedAnswer = dbQuestion.Answers.FirstOrDefault(a => a.Id == selectedId);
|
||||||
|
if (selectedAnswer != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Selected Answer: {selectedAnswer.Text}");
|
||||||
|
// Here you could further process each selected answer, e.g., saving user responses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ResponseQuestionnaireViewModel MapToViewModel(Questionnaire questionnaire)
|
||||||
|
{
|
||||||
|
var viewModel = new ResponseQuestionnaireViewModel
|
||||||
|
{
|
||||||
|
Id = questionnaire.Id,
|
||||||
|
Title = questionnaire.Title,
|
||||||
|
Description = questionnaire.Description,
|
||||||
|
Questions = questionnaire.Questions.Select(q => new ResponseQuestionViewModel
|
||||||
|
{
|
||||||
|
Id = q.Id,
|
||||||
|
Text = q.Text,
|
||||||
|
Type = q.Type,
|
||||||
|
Answers = q.Answers.Select(a => new ResponseAnswerViewModel
|
||||||
|
{
|
||||||
|
Id = a.Id,
|
||||||
|
Text = a.Text
|
||||||
|
}).ToList()
|
||||||
|
}).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// Check if the token is null or empty
|
||||||
|
//if (string.IsNullOrEmpty(t))
|
||||||
|
//{
|
||||||
|
// ViewBag.ErrorMessage = "The URL is invalid. Please provide a valid token.";
|
||||||
|
// return View("Error");
|
||||||
|
//}
|
||||||
|
|
||||||
|
//// Split the token to extract the expiration date and time
|
||||||
|
//string[] tokenParts = t.Split('|');
|
||||||
|
//if (tokenParts.Length != 2)
|
||||||
|
//{
|
||||||
|
// ViewBag.ErrorMessage = "The URL is invalid. Please provide a valid token.";
|
||||||
|
// return View("Error");
|
||||||
|
//}
|
||||||
|
|
||||||
|
//string expiryDateTimeString = tokenParts[1];
|
||||||
|
|
||||||
|
//// Parse the expiration datetime in UTC format
|
||||||
|
//if (!DateTime.TryParseExact(expiryDateTimeString, "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out DateTime expiryDateTimeUtc))
|
||||||
|
//{
|
||||||
|
// ViewBag.ErrorMessage = "The URL is invalid. Please provide a valid token.";
|
||||||
|
// return View("Error");
|
||||||
|
//}
|
||||||
|
|
||||||
|
//// Convert the expiration datetime to local time
|
||||||
|
//DateTime expiryDateTimeLocal = expiryDateTimeUtc.ToLocalTime();
|
||||||
|
|
||||||
|
//// Check if the token is expired (accounting for UTC+2 offset)
|
||||||
|
//if (expiryDateTimeLocal < DateTime.Now.AddHours(2))
|
||||||
|
//{
|
||||||
|
|
||||||
|
// return RedirectToAction(nameof(Error));
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Retrieve the questionnaire using the numeric ID
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
8
Web/ViewModel/QuestionnaireVM/ResponseAnswerViewModel.cs
Normal file
8
Web/ViewModel/QuestionnaireVM/ResponseAnswerViewModel.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Web.ViewModel.QuestionnaireVM
|
||||||
|
{
|
||||||
|
public class ResponseAnswerViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; } // Answer ID
|
||||||
|
public string? Text { get; set; } // Answer text
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Web/ViewModel/QuestionnaireVM/ResponseQuestionViewModel.cs
Normal file
18
Web/ViewModel/QuestionnaireVM/ResponseQuestionViewModel.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Model;
|
||||||
|
using Web.ViewModel.AnswerVM;
|
||||||
|
|
||||||
|
namespace Web.ViewModel.QuestionnaireVM
|
||||||
|
{
|
||||||
|
public class ResponseQuestionViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; } // Question ID
|
||||||
|
public string? Text { get; set; } // Question text
|
||||||
|
public QuestionType Type { get; set; } // Question type
|
||||||
|
|
||||||
|
// List of selectable answers
|
||||||
|
public List<ResponseAnswerViewModel> Answers { get; set; } = new List<ResponseAnswerViewModel>();
|
||||||
|
|
||||||
|
// IDs of selected answers, used for submitting form data
|
||||||
|
public List<int> SelectedAnswerIds { get; set; } = new List<int>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
using Web.ViewModel.QuestionVM;
|
||||||
|
|
||||||
|
namespace Web.ViewModel.QuestionnaireVM
|
||||||
|
{
|
||||||
|
public class ResponseQuestionnaireViewModel
|
||||||
|
{
|
||||||
|
|
||||||
|
public int Id { get; set; } // Questionnaire ID
|
||||||
|
public string? Title { get; set; } // Title of the questionnaire
|
||||||
|
public string? Description { get; set; } // Description of the questionnaire
|
||||||
|
|
||||||
|
// Collection of questions
|
||||||
|
public List<ResponseQuestionViewModel> Questions { get; set; } = new List<ResponseQuestionViewModel>();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@model Questionnaire
|
@model ResponseQuestionnaireViewModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "DisplayQuestionnaire";
|
ViewData["Title"] = "DisplayQuestionnaire";
|
||||||
Layout = "~/Views/Shared/_QuestionnaireResponse.cshtml";
|
Layout = "~/Views/Shared/_QuestionnaireResponse.cshtml";
|
||||||
|
|
@ -124,12 +124,17 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="QuestionContainer">
|
<div class="QuestionContainer">
|
||||||
<section class="hero container card">
|
<section class="hero container card">
|
||||||
|
<form id="questionnaireForm" method="post" asp-action="DisplayQuestionnaire">
|
||||||
|
<input type="hidden" name="Id" value="@Model.Id">
|
||||||
|
<input type="hidden" name="Title" value="@Model.Title">
|
||||||
|
<input type="hidden" name="Description" value="@Model.Description">
|
||||||
|
|
||||||
|
<h4>@Model.Title</h4>
|
||||||
|
<p>@Html.Raw(Model.Description)</p>
|
||||||
|
|
||||||
|
|
||||||
<h4>@Model.Title</h4>
|
|
||||||
<p>@Html.Raw(Model.Description) </p>
|
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
|
|
@ -141,7 +146,7 @@
|
||||||
var question = Model.Questions[i];
|
var question = Model.Questions[i];
|
||||||
string stepClass = i == 0 ? "active" : ""; // Adjusted the index to start from the first question
|
string stepClass = i == 0 ? "active" : ""; // Adjusted the index to start from the first question
|
||||||
<div class="step-indicator @(stepClass)" data-step-index="@i">
|
<div class="step-indicator @(stepClass)" data-step-index="@i">
|
||||||
<span class="step-number">@((i + 1)). </span> <!-- Adjusted to start from 1 -->
|
<span class="step-number">@((i + 1)). </span>
|
||||||
<span class="step-label">@question.Type</span>
|
<span class="step-label">@question.Type</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -149,18 +154,28 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- Form Content -->
|
<!-- Form Content -->
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<form id="questionnaireForm">
|
@for (int i = 0; i < Model.Questions.Count; i++)
|
||||||
@for (int i = 0; i < Model.Questions.Count; i++)
|
{
|
||||||
|
var question = Model.Questions[i];
|
||||||
|
<input type="hidden" name="Id" value="@question.Id">
|
||||||
|
<input type="hidden" name="Questions[@i].Text" value="@question.Text">
|
||||||
|
<input type="hidden" name="Questions[@i].Id" value="@question.Id">
|
||||||
|
<input type="hidden" name="Questions[@i].Type" value="@((int)question.Type)">
|
||||||
|
@for (int j = 0; j < question.Answers.Count; j++)
|
||||||
{
|
{
|
||||||
var question = Model.Questions[i];
|
var answer = question.Answers[j];
|
||||||
<div class="step @(i == 0 ? "active" : "")">
|
<input type="hidden" name="Questions[@i].Answers[@j].Id" value="@answer.Id">
|
||||||
<p class="font-weight-normal">@(i + 1). @question.Text</p>
|
<input type="hidden" name="Questions[@i].Answers[@j].Text" value="@answer.Text">
|
||||||
<div id="QuestionCard">
|
<!-- Add more hidden fields as needed for other properties of the answer -->
|
||||||
|
}
|
||||||
|
<div class="step @(i == 0 ? "active" : "")">
|
||||||
|
<p class="font-weight-normal">@(i + 1). @question.Text</p>
|
||||||
|
<div id="QuestionCard">
|
||||||
@switch (question.Type)
|
@switch (question.Type)
|
||||||
{
|
{
|
||||||
case QuestionType.Text:
|
case QuestionType.Text:
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" name="question@(i + 1)" placeholder="Enter answer">
|
<input type="text" class="form-control" name="Questions[@i].SelectedAnswerIds" placeholder="Enter answer">
|
||||||
</div>
|
</div>
|
||||||
break;
|
break;
|
||||||
case QuestionType.CheckBox:
|
case QuestionType.CheckBox:
|
||||||
|
|
@ -173,32 +188,34 @@
|
||||||
@foreach (var answer in question.Answers)
|
@foreach (var answer in question.Answers)
|
||||||
{
|
{
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="question@(i + 1)_answer@(answer.Id)" name="question@(i + 1)" value="@answer.Id">
|
<input class="form-check-input answer-input" type="checkbox" id="question@(i)_answer@(answer.Id)" name="Questions[@i].SelectedAnswerIds" value="@answer.Id">
|
||||||
<label class="form-check-label" for="question@(i + 1)_answer@(answer.Id)">
|
<label class="form-check-label" for="question@(i)_answer@(answer.Id)">
|
||||||
@answer.Text
|
@answer.Text
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
break;
|
break;
|
||||||
case QuestionType.TrueFalse:
|
case QuestionType.TrueFalse:
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" id="question@(i + 1)_true" name="question@(i + 1)" value="true">
|
<input class="form-check-input" type="radio" id="question@(i + 1)_true" name="Questions[@i].SelectedAnswerIds" value="true">
|
||||||
<label class="form-check-label" for="question@(i + 1)_true">True</label>
|
<label class="form-check-label" for="question@(i + 1)_true">True</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" id="question@(i + 1)_false" name="question@(i + 1)" value="false">
|
<input class="form-check-input" type="radio" id="question@(i + 1)_false" name="Questions[@i].SelectedAnswerIds" value="false">
|
||||||
<label class="form-check-label" for="question@(i + 1)_false">False</label>
|
<label class="form-check-label" for="question@(i + 1)_false">False</label>
|
||||||
</div>
|
</div>
|
||||||
break;
|
break;
|
||||||
case QuestionType.Open_ended:
|
case QuestionType.Open_ended:
|
||||||
<textarea class="form-control" id="question@(i + 1)" name="question@(i + 1)" rows="3" placeholder="Enter answer"></textarea>
|
<textarea class="form-control" id="question@(i + 1)" name="Questions[@i].SelectedAnswerIds" rows="3" placeholder="Enter answer"></textarea>
|
||||||
break;
|
break;
|
||||||
case QuestionType.Image:
|
case QuestionType.Image:
|
||||||
<input type="file" class="form-control-file" id="question@(i + 1)" name="question@(i + 1)">
|
<input type="file" class="form-control-file" id="question@(i + 1)" name="Questions[@i].SelectedAnswerIds">
|
||||||
break;
|
break;
|
||||||
case QuestionType.Slider:
|
case QuestionType.Slider:
|
||||||
<input type="range" class="form-range" id="question@(i + 1)" name="question@(i + 1)" min="0" max="100" step="1">
|
<input type="range" class="form-range" id="question@(i + 1)" name="Questions[@i].SelectedAnswerIds" min="0" max="100" step="1">
|
||||||
<output id="question@(i + 1)_output">50</output>
|
<output id="question@(i + 1)_output">50</output>
|
||||||
<script>
|
<script>
|
||||||
document.getElementById('question@(i + 1)').addEventListener('input', function () {
|
document.getElementById('question@(i + 1)').addEventListener('input', function () {
|
||||||
|
|
@ -207,15 +224,12 @@
|
||||||
</script>
|
</script>
|
||||||
break;
|
break;
|
||||||
case QuestionType.Rating:
|
case QuestionType.Rating:
|
||||||
<div class="rating" data-question="@i">
|
<div class="rating" data-question="@i">
|
||||||
@foreach (var answer in question.Answers)
|
@foreach (var answer in question.Answers)
|
||||||
{
|
{
|
||||||
@* <span class="text-white">@answer.Id</span> *@
|
<i class="bi bi-star ml-3" data-value="@answer.Id"></i>
|
||||||
<i class="bi bi-star ml-3" data-value="@answer.Id"></i>
|
}
|
||||||
|
</div>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
|
|
@ -223,91 +237,29 @@
|
||||||
</div>
|
</div>
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@* @switch (question.Type)
|
|
||||||
{
|
|
||||||
case QuestionType.Text:
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" class="form-control" name="question@(i + 1)" placeholder="Enter answer">
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
case QuestionType.CheckBox:
|
|
||||||
case QuestionType.Multiple_choice:
|
|
||||||
case QuestionType.Rating:
|
|
||||||
case QuestionType.Likert:
|
|
||||||
case QuestionType.Matrix:
|
|
||||||
case QuestionType.Demographic:
|
|
||||||
case QuestionType.Ranking:
|
|
||||||
<div class="form-group">
|
|
||||||
@foreach (var answer in question.Answers)
|
|
||||||
{
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="question@(i + 1)_answer@(answer.Id)" name="question@(i + 1)" value="@answer.Id">
|
|
||||||
<label class="form-check-label" for="question@(i + 1)_answer@(answer.Id)">
|
|
||||||
@answer.Text
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
case QuestionType.TrueFalse:
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" id="question@(i + 1)_true" name="question@(i + 1)" value="true">
|
|
||||||
<label class="form-check-label" for="question@(i + 1)_true">True</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="radio" id="question@(i + 1)_false" name="question@(i + 1)" value="false">
|
|
||||||
<label class="form-check-label" for="question@(i + 1)_false">False</label>
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
case QuestionType.Open_ended:
|
|
||||||
<textarea class="form-control" id="question@(i + 1)" name="question@(i + 1)" rows="3" placeholder="Enter answer"></textarea>
|
|
||||||
break;
|
|
||||||
case QuestionType.Image:
|
|
||||||
<input type="file" class="form-control-file" id="question@(i + 1)" name="question@(i + 1)">
|
|
||||||
break;
|
|
||||||
case QuestionType.Slider:
|
|
||||||
<input type="range" class="form-range" id="question@(i + 1)" name="question@(i + 1)" min="0" max="100" step="1">
|
|
||||||
<output id="question@(i + 1)_output">50</output>
|
|
||||||
<script>
|
|
||||||
document.getElementById('question@(i + 1)').addEventListener('input', function () {
|
|
||||||
document.getElementById('question@(i + 1)_output').value = this.value;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
Unsupported question type.
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
} *@
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="mt-3">
|
|
||||||
@if (i > 0)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-secondary btn-sm mr-3 prev" id="BannerButon"><i class="bi bi-arrow-left"></i> Previous </button>
|
|
||||||
}
|
|
||||||
@if (i < Model.Questions.Count - 1)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary btn-sm next" id="BannerButon">Next <i class="bi bi-arrow-right"></i></button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
}
|
<div class="mt-3">
|
||||||
|
@if (i > 0)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm mr-3 prev" id="BannerButon"><i class="bi bi-arrow-left"></i> Previous </button>
|
||||||
|
}
|
||||||
|
@if (i < Model.Questions.Count - 1)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary btn-sm next" id="BannerButon">Next <i class="bi bi-arrow-right"></i></button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary submit btn-sm mt-4" id="BannerButon">Submit</button>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary submit btn-sm mt-4" id="BannerButon" style="display: none;">Submit</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</form>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
|
|
@ -317,106 +269,158 @@
|
||||||
<partial name="_ValidationScriptsPartial" />
|
<partial name="_ValidationScriptsPartial" />
|
||||||
}
|
}
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
const form = document.getElementById('questionnaireForm');
|
|
||||||
const steps = form.querySelectorAll('.step');
|
|
||||||
const stepIndicators = document.querySelectorAll('.step-indicator');
|
|
||||||
const submitButton = form.querySelector('.submit');
|
|
||||||
let currentStep = 0;
|
|
||||||
|
|
||||||
function showStep(index) {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
steps.forEach((step, i) => {
|
const form = document.getElementById('questionnaireForm');
|
||||||
if (i === index) {
|
const steps = form.querySelectorAll('.step');
|
||||||
step.style.display = 'block';
|
const stepIndicators = document.querySelectorAll('.step-indicator');
|
||||||
} else {
|
const submitButton = form.querySelector('.submit');
|
||||||
step.style.display = 'none';
|
let currentStep = 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const form = document.getElementById('questionnaireForm'); // Make sure this is your form ID
|
||||||
|
|
||||||
|
form.addEventListener('submit', function (event) {
|
||||||
|
event.preventDefault(); // Prevent the default form submission action
|
||||||
|
|
||||||
|
const formData = new FormData(form);
|
||||||
|
const refinedFormData = new FormData(); // This will hold only the necessary data
|
||||||
|
|
||||||
|
// Iterate over the original FormData entries
|
||||||
|
formData.forEach((value, key) => {
|
||||||
|
if (key.includes("SelectedAnswerIds")) {
|
||||||
|
// Handle checkbox fields specially to ensure only checked boxes are included
|
||||||
|
let selector = `input[name="${key}"]:checked`;
|
||||||
|
document.querySelectorAll(selector).forEach(input => {
|
||||||
|
refinedFormData.append(key, input.value);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Append other data normally
|
||||||
|
refinedFormData.append(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log for debugging to see what will be submitted
|
||||||
|
console.log('Prepared formData for submission:');
|
||||||
|
refinedFormData.forEach((value, key) => {
|
||||||
|
console.log(`${key}: ${value}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use Fetch API to submit the refined FormData
|
||||||
|
fetch(form.action, {
|
||||||
|
method: 'POST',
|
||||||
|
body: refinedFormData
|
||||||
|
}).then(response => response.json()).then(data => {
|
||||||
|
console.log('Submission successful', data);
|
||||||
|
// Optional: Redirect or handle post-submission here
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Submission failed', error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
document.getElementById('questionnaireForm').addEventListener('submit', handleSubmit);
|
||||||
|
|
||||||
stepIndicators.forEach((indicator, i) => {
|
|
||||||
if (i === index) {
|
|
||||||
indicator.classList.add('active');
|
|
||||||
} else {
|
|
||||||
indicator.classList.remove('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (index === steps.length - 1) {
|
|
||||||
submitButton.style.display = 'block';
|
|
||||||
|
|
||||||
|
function showStep(index) {
|
||||||
|
steps.forEach((step, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
step.style.display = 'block';
|
||||||
} else {
|
} else {
|
||||||
submitButton.style.display = 'none';
|
step.style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
function goToNextStep() {
|
stepIndicators.forEach((indicator, i) => {
|
||||||
if (currentStep < steps.length - 1) {
|
if (i === index) {
|
||||||
currentStep++;
|
indicator.classList.add('active');
|
||||||
showStep(currentStep);
|
} else {
|
||||||
|
indicator.classList.remove('active');
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
function goToPrevStep() {
|
if (index === steps.length - 1) {
|
||||||
if (currentStep > 0) {
|
submitButton.style.display = 'block';
|
||||||
currentStep--;
|
} else {
|
||||||
showStep(currentStep);
|
submitButton.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextStep() {
|
||||||
|
if (currentStep < steps.length - 1) {
|
||||||
|
currentStep++;
|
||||||
|
showStep(currentStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToPrevStep() {
|
||||||
|
if (currentStep > 0) {
|
||||||
|
currentStep--;
|
||||||
|
showStep(currentStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextButtons = form.querySelectorAll('.next');
|
||||||
|
nextButtons.forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
goToNextStep();
|
||||||
|
updateStepper();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const prevButtons = form.querySelectorAll('.prev');
|
||||||
|
prevButtons.forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
goToPrevStep();
|
||||||
|
updateStepper();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateStepper() {
|
||||||
|
const currentStepIndex = currentStep;
|
||||||
|
stepIndicators.forEach((indicator, i) => {
|
||||||
|
if (i === currentStepIndex) {
|
||||||
|
indicator.style.backgroundColor = '#33b3ae'; // Change to your primary color
|
||||||
|
} else {
|
||||||
|
indicator.style.backgroundColor = ''; // Reset to default color for non-active steps
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const nextButtons = form.querySelectorAll('.next');
|
|
||||||
nextButtons.forEach(button => {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
goToNextStep();
|
|
||||||
updateStepper();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const prevButtons = form.querySelectorAll('.prev');
|
// Add submit event listener to the form
|
||||||
prevButtons.forEach(button => {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
goToPrevStep();
|
|
||||||
updateStepper();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateStepper() {
|
showStep(currentStep);
|
||||||
const currentStepIndex = currentStep;
|
updateStepper();
|
||||||
stepIndicators.forEach((indicator, i) => {
|
|
||||||
if (i === currentStepIndex) {
|
|
||||||
indicator.style.backgroundColor = '#33b3ae'; // Change to your primary color
|
|
||||||
} else {
|
|
||||||
indicator.style.backgroundColor = ''; // Reset to default color for non-active steps
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showStep(currentStep);
|
$('.rating i').on('click', function () {
|
||||||
updateStepper();
|
var value = $(this).data('value');
|
||||||
$('.rating i').on('click', function() {
|
var questionIndex = $(this).closest('.rating').data('question');
|
||||||
var value = $(this).data('value');
|
var selectedStars = $(this).closest('.rating').find('i.selected').length;
|
||||||
var questionIndex = $(this).closest('.rating').data('question');
|
|
||||||
var selectedStars = $(this).closest('.rating').find('i.selected').length;
|
|
||||||
|
|
||||||
// Unselect all stars
|
// Unselect all stars
|
||||||
$(this).closest('.rating').find('i').removeClass('selected');
|
$(this).closest('.rating').find('i').removeClass('selected');
|
||||||
|
|
||||||
// Select the clicked star and all preceding stars
|
// Select the clicked star and all preceding stars
|
||||||
$(this).addClass('selected').prevAll().addClass('selected');
|
$(this).addClass('selected').prevAll().addClass('selected');
|
||||||
|
|
||||||
// Update the hidden input value if needed
|
// Update the hidden input value if needed
|
||||||
$('input[name="question' + questionIndex + '_rating"]').val(value);
|
$('input[name="question' + questionIndex + '_rating"]').val(value);
|
||||||
|
|
||||||
// Update the label with the number of selected stars
|
// Update the label with the number of selected stars
|
||||||
$(this).closest('.rating').next('.selected-count').text(selectedStars);
|
$(this).closest('.rating').next('.selected-count').text(selectedStars);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prevent the default action for the anchor tags within the rating
|
// Prevent the default action for the anchor tags within the rating
|
||||||
$('.rating a').on('click', function(e) {
|
$('.rating a').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
@using Web
|
@using Web
|
||||||
@using Model
|
@using Model
|
||||||
@using Web.Models
|
@using Web.Models
|
||||||
|
@using Web.ViewModel.QuestionnaireVM
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@addTagHelper *,Web
|
@addTagHelper *,Web
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@
|
||||||
"MailJet": {
|
"MailJet": {
|
||||||
"ApiKey": "f545eee3a4743464b9d25fb9c5ab3f6c",
|
"ApiKey": "f545eee3a4743464b9d25fb9c5ab3f6c",
|
||||||
"SecretKey": "9fa430ef00873fdefe333fdc40ee3f8f"
|
"SecretKey": "9fa430ef00873fdefe333fdc40ee3f8f"
|
||||||
|
},
|
||||||
|
"OpenAI": {
|
||||||
|
"ApiKey": "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"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue