Implement condition logic for the questionnaire

This commit is contained in:
Qaisyousuf 2025-08-08 17:21:29 +02:00
parent 9bfed53e71
commit d1dfcdd2ba
14 changed files with 3297 additions and 130 deletions

View file

@ -20,5 +20,7 @@ namespace Model
public int QuestionId { get; set; } // Foreign key for Question public int QuestionId { get; set; } // Foreign key for Question
[ForeignKey("QuestionId")] [ForeignKey("QuestionId")]
public Question? Question { get; set; } public Question? Question { get; set; }
public string? ConditionJson { get; set; }
} }
} }

View file

@ -387,32 +387,29 @@ namespace Web.Areas.Admin.Controllers
[ActionName("Delete")] [ActionName("Delete")]
public async Task<IActionResult> DeleteConfirm(int id) public async Task<IActionResult> DeleteConfirm(int id)
{ {
try try
{ {
var deletedQuestionnaire = _questionnaire.Delete(id); // Your Delete method is async Task, so you need to await it
// It doesn't return anything, so don't assign it to a variable
await _questionnaire.Delete(id);
// If we reach here, deletion was successful (no exception thrown)
if (deletedQuestionnaire == null)
{
return NotFound(); // Or handle not found case appropriately
}
// If deletion is successful, you can redirect to a success page or return a success message
return Json(new { success = true, message = "Item deleted successfully" }); return Json(new { success = true, message = "Item deleted successfully" });
} }
catch (Exception) catch (ArgumentNullException ex)
{ {
// Log the exception or handle it appropriately return Json(new { success = false, message = "Invalid ID provided" });
return StatusCode(500, "An error occurred while processing your request."); }
catch (ArgumentException ex)
{
return Json(new { success = false, message = "Questionnaire not found" });
}
catch (Exception ex)
{
// Log the actual exception to see what's wrong
System.Diagnostics.Debug.WriteLine($"Delete error: {ex.Message}");
return Json(new { success = false, message = "An error occurred while deleting the questionnaire" });
} }
} }
[HttpGet] [HttpGet]
@ -667,7 +664,117 @@ namespace Web.Areas.Admin.Controllers
return tokenWithExpiry; return tokenWithExpiry;
} }
// Add these methods to your existing QuestionnaireController class
[HttpGet]
public IActionResult SetLogic(int id)
{
var questionnaire = _questionnaire.GetQuestionnaireWithQuestionAndAnswer(id);
if (questionnaire == null)
{
return NotFound();
}
var viewModel = new SetLogicViewModel
{
QuestionnaireId = questionnaire.Id,
QuestionnaireName = questionnaire.Title ?? "Untitled Survey",
Questions = questionnaire.Questions.Select((q, index) => new QuestionLogicViewModel
{
QuestionId = q.Id,
QuestionText = q.Text ?? "",
QuestionType = q.Type,
QuestionNumber = index + 1,
Answers = q.Answers.Select(a =>
{
var answerCondition = new AnswerConditionViewModel
{
AnswerId = a.Id,
AnswerText = a.Text ?? ""
};
// Parse existing condition if it exists
if (!string.IsNullOrEmpty(a.ConditionJson))
{
try
{
var condition = System.Text.Json.JsonSerializer.Deserialize<AnswerConditionViewModel>(a.ConditionJson);
if (condition != null)
{
answerCondition.ActionType = condition.ActionType;
answerCondition.TargetQuestionNumber = condition.TargetQuestionNumber;
answerCondition.SkipCount = condition.SkipCount;
answerCondition.EndMessage = condition.EndMessage;
}
}
catch (System.Text.Json.JsonException)
{
// If JSON is malformed, use default values
}
}
return answerCondition;
}).ToList()
}).ToList()
};
// Pass total question count for dropdown options
ViewBag.TotalQuestions = questionnaire.Questions.Count;
return View(viewModel);
}
[HttpPost]
public async Task<IActionResult> SaveLogic(SaveConditionsViewModel model)
{
if (!ModelState.IsValid)
{
TempData["Error"] = "Invalid data provided.";
return RedirectToAction(nameof(SetLogic), new { id = model.QuestionnaireId });
}
try
{
// Get questionnaire with answers
var questionnaire = _questionnaire.GetQuestionnaireWithQuestionAndAnswer(model.QuestionnaireId);
if (questionnaire == null)
{
TempData["Error"] = "Questionnaire not found.";
return RedirectToAction(nameof(Index));
}
// Update each answer's condition
foreach (var conditionUpdate in model.Conditions)
{
var answer = questionnaire.Questions
.SelectMany(q => q.Answers)
.FirstOrDefault(a => a.Id == conditionUpdate.AnswerId);
if (answer != null)
{
answer.ConditionJson = string.IsNullOrEmpty(conditionUpdate.ConditionJson)
? null
: conditionUpdate.ConditionJson;
}
}
// Save changes
await _questionnaire.Update(questionnaire);
await _questionnaire.commitAsync();
TempData["Success"] = "Conditional logic saved successfully!";
return RedirectToAction(nameof(SetLogic), new { id = model.QuestionnaireId });
}
catch (Exception ex)
{
TempData["Error"] = "An error occurred while saving conditions: " + ex.Message;
return RedirectToAction(nameof(SetLogic), new { id = model.QuestionnaireId });
}
}
}
}
} }

View file

@ -199,106 +199,6 @@
}); });
</script> </script>
@* <script>
$(document).ready(function () {
var questionIndex = @Model.Questions?.Count;
$("#add-question-btn").click(function () {
var newQuestionHtml = `
<div class="question-group" data-question-index="${questionIndex}">
<label>Question ${questionIndex + 1}</label>
<textarea name="Questions[${questionIndex}].Text" class="form-control"></textarea>
<br>
<label class=h5>Select question type</label>
<select name="Questions[${questionIndex}].Type" class="form-control question-type-${questionIndex}">`;
var questionTypes = @Html.Raw(Json.Serialize(Enum.GetNames(typeof(QuestionType))));
for (var i = 0; i < questionTypes.length; i++) {
newQuestionHtml += `<option value="${questionTypes[i]}">${questionTypes[i]}</option>`;
}
newQuestionHtml += `</select>`;
// Add answers input fields
newQuestionHtml += `<div class="container-ms mx-5 py-2 px-5 ">`;
newQuestionHtml += `<div class="answers-container" data-question-index="${questionIndex}"><br>`;
newQuestionHtml += `<label class="h3">Create Answers:</label>`;
newQuestionHtml += `<div class="answer-group" data-answer-index="0"><hr class="border border-primary border-1 opacity-35">`;
newQuestionHtml += `<label>Answer 1</label>`;
newQuestionHtml += `<input type="text" name="Questions[${questionIndex}].Answers[0].Text" class="form-control" placeholder="new answer"/><br>`;
newQuestionHtml += `<button type="button" class="btn btn-sm btn-success add-answer mt-2 shadow"><i class="bi bi-plus-lg"></i> create Answer</button>`;
newQuestionHtml += `<hr class="border m-2">`
newQuestionHtml += `</div> `;
newQuestionHtml += `</div>`;
newQuestionHtml += `</div> `;
// Add Remove Question button
newQuestionHtml += `<button type="button" class="btn btn-sm btn-danger m-4 shadow remove-question"><i class="bi bi-trash3-fill"></i> Remove Question </button>`;
newQuestionHtml += `<button type="button" class="btn btn-sm btn-primary shadow save-question">Save Question</button>`;
newQuestionHtml += `<button type="button" class="btn btn-sm btn-secondary shadow edit-question" style="display: none;">Edit Question</button>`;
newQuestionHtml += `<hr class="border border-primary border-4 opacity-75 mb-5">`
newQuestionHtml += `</div>`;
$("#questions-container .form-group").append(newQuestionHtml);
questionIndex++;
});
$("#questions-container").on("click", ".add-answer", function () {
var questionIndex = $(this).closest('.answers-container').data('question-index');
var answerIndex = $(this).closest('.answers-container').find('.answer-group').length;
var answerGroupHtml = `
<div class="answer-group">
<br>
<label class="control-label">Answer ${answerIndex + 1}</label>
<input type="text" class="form-control" name="Questions[${questionIndex}].Answers[${answerIndex}].Text" placeholder="new answer"/>
<button type="button" class="btn btn-danger btn-sm mt-1 shadow remove-answer"><i class="bi bi-trash3-fill"></i></button>
<br>
</div>`;
$(this).before(answerGroupHtml);
$(this).prev('.answer-group').find('.remove-answer').show();
});
// Remove answer dynamically
$("#questions-container").on("click", ".remove-answer", function () {
$(this).closest('.answer-group').remove();
});
// Remove question dynamically
$(document).on("click", ".remove-question", function () {
$(this).closest('.question-group').remove();
});
// Save question
$("#questions-container").on("click", ".save-question", function () {
var questionGroup = $(this).closest('.question-group');
questionGroup.find('.edit-question').show();
questionGroup.find('.remove-question').hide();
questionGroup.find('.save-question').hide();
questionGroup.find('.question-type').prop('disabled', true).hide(); // Hide question type
questionGroup.find('textarea').prop('disabled', true);
questionGroup.find('.answers-container').slideUp();
questionGroup.addClass('collapsed');
});
// Edit question
$("#questions-container").on("click", ".edit-question", function () {
var questionGroup = $(this).closest('.question-group');
questionGroup.find('.save-question').show();
questionGroup.find('.remove-question').show();
questionGroup.find('.edit-question').hide();
questionGroup.find('.question-type').prop('disabled', false).show(); // Show question type
questionGroup.find('textarea').prop('disabled', false);
questionGroup.find('.answers-container').slideDown();
questionGroup.removeClass('collapsed');
});
});
</script>
*@
} }

View file

@ -12,7 +12,7 @@
Are you sure you want to delete: Are you sure you want to delete:
<span class="badge bg-danger p-2 shadow rounded"> <span class="badge bg-danger p-2 shadow rounded">
<span class="item-title ">@Html.Raw(Model.Title.Length >= 30 ? Model.Title.Substring(0, 30) : Model.Title)</span> <span class="item-title ">@Html.Raw(Model.Title.Length >= 100 ? Model.Title.Substring(0, 100) : Model.Title)</span>
<span class="more-title " style="display:none;">@(Model.Title.Length > 30 ? Model.Title.Substring(30) : "")</span> <span class="more-title " style="display:none;">@(Model.Title.Length > 30 ? Model.Title.Substring(30) : "")</span>
</span> </span>
<button type="button" class="btn btn-link readMoreBtn">Read More</button> <button type="button" class="btn btn-link readMoreBtn">Read More</button>

View file

@ -323,10 +323,7 @@
// Append the new question HTML to the container // Append the new question HTML to the container
$('#questionsContainer').append(questionHtml); $('#questionsContainer').append(questionHtml);
// Show success message
// var successMessage = $('<div class="alert alert-success" role="alert">Question created successfully!</div>');
// $('.question-title').prepend(successMessage);
// successMessage.fadeIn().delay(2000).fadeOut();
}); });

View file

@ -66,11 +66,24 @@
</td> </td>
<td> <td>
<a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger btn-sm m-1"><i class="bi bi-trash"></i> Delete</a> <!-- Your existing buttons -->
<a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-primary btn-sm m-1"><i class="bi bi-pencil-square"></i> Edit</a> <a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger btn-sm">
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-info btn-sm m-1"><i class="bi bi-pencil-square"></i> Details</a> 🗑️ DELETE
<a asp-action="SendQuestionnaire" asp-route-id="@item.Id" class="btn btn-success btn-sm m-1"><i class="bi bi-pencil-square"></i> Send</a> </a>
<a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-primary btn-sm">
✏️ EDIT
</a>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-info btn-sm">
👁️ DETAILS
</a>
<a asp-action="SendQuestionnaire" asp-route-id="@item.Id" class="btn btn-success btn-sm">
📧 SEND
</a>
<!-- NEW: SET LOGIC button with purple/orange styling -->
<a asp-action="SetLogic" asp-route-id="@item.Id" class="btn btn-sm" style="background-color: #6f42c1; color: white;">
🔀 SET LOGIC
</a>
</td> </td>
</tr> </tr>
} }

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
@using Web.ViewModel.AccountVM @using Web.ViewModel.AccountVM
@using Web.ViewModel.NewsLetterVM @using Web.ViewModel.NewsLetterVM
@using Web.ViewModel.DashboardVM @using Web.ViewModel.DashboardVM
@using Services.EmailSend @using Services.EmailSend
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View file

@ -0,0 +1,844 @@
// <auto-generated />
using System;
using Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Web.Migrations
{
[DbContext(typeof(SurveyContext))]
[Migration("20250807114646_AddConditionalLogicToAnswers")]
partial class AddConditionalLogicToAnswers
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderKey")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("RoleId")
.HasColumnType("nvarchar(450)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("Name")
.HasColumnType("nvarchar(450)");
b.Property<string>("Value")
.HasColumnType("nvarchar(max)");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Model.Address", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("CVR")
.HasColumnType("nvarchar(max)");
b.Property<string>("City")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Country")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Mobile")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("PostalCode")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("State")
.HasColumnType("nvarchar(max)");
b.Property<string>("Street")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Addresss");
});
modelBuilder.Entity("Model.Answer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int?>("NextQuestionId")
.HasColumnType("int");
b.Property<int>("QuestionId")
.HasColumnType("int");
b.Property<bool>("SkipToEnd")
.HasColumnType("bit");
b.Property<string>("Text")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.ToTable("Answers");
});
modelBuilder.Entity("Model.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("bit");
b.Property<string>("FirstName")
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.HasColumnType("nvarchar(max)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("bit");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetimeoffset");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("nvarchar(max)");
b.Property<string>("PhoneNumber")
.HasColumnType("nvarchar(max)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("bit");
b.Property<string>("SecurityStamp")
.HasColumnType("nvarchar(max)");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("bit");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Model.Banner", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ImageUrl")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("LinkUrl")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Banners");
});
modelBuilder.Entity("Model.Footer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("CreatedBy")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ImageUlr")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("LastUpdated")
.HasColumnType("datetime2");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Owner")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Sitecopyright")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("UpdatedBy")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Footers");
});
modelBuilder.Entity("Model.FooterSocialMedia", b =>
{
b.Property<int>("FooterId")
.HasColumnType("int");
b.Property<int>("SocialId")
.HasColumnType("int");
b.HasKey("FooterId", "SocialId");
b.HasIndex("SocialId");
b.ToTable("FooterSocialMedias");
});
modelBuilder.Entity("Model.Page", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("BannerId")
.HasColumnType("int");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("FooterId")
.HasColumnType("int");
b.Property<string>("Slug")
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("BannerId");
b.HasIndex("FooterId");
b.ToTable("Pages");
});
modelBuilder.Entity("Model.Question", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("QuestionnaireId")
.HasColumnType("int");
b.Property<string>("Text")
.HasColumnType("nvarchar(max)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("QuestionnaireId");
b.ToTable("Questions");
});
modelBuilder.Entity("Model.Questionnaire", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Questionnaires");
});
modelBuilder.Entity("Model.Response", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("QuestionnaireId")
.HasColumnType("int");
b.Property<DateTime>("SubmissionDate")
.HasColumnType("datetime2");
b.Property<string>("UserEmail")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserName")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("QuestionnaireId");
b.ToTable("Responses");
});
modelBuilder.Entity("Model.ResponseAnswer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("AnswerId")
.HasColumnType("int");
b.Property<int?>("NextQuestionId")
.HasColumnType("int");
b.Property<int>("ResponseDetailId")
.HasColumnType("int");
b.Property<bool>("SkipToEnd")
.HasColumnType("bit");
b.HasKey("Id");
b.HasIndex("ResponseDetailId");
b.ToTable("ResponseAnswers");
});
modelBuilder.Entity("Model.ResponseDetail", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("QuestionId")
.HasColumnType("int");
b.Property<int>("QuestionType")
.HasColumnType("int");
b.Property<int>("ResponseId")
.HasColumnType("int");
b.Property<string>("TextResponse")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.HasIndex("ResponseId");
b.ToTable("ResponseDetails");
});
modelBuilder.Entity("Model.SentNewsletterEamil", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Body")
.HasColumnType("nvarchar(max)");
b.Property<string>("Geo")
.HasColumnType("nvarchar(max)");
b.Property<string>("IpAddress")
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsBlocked")
.HasColumnType("bit");
b.Property<bool>("IsBounced")
.HasColumnType("bit");
b.Property<bool>("IsClicked")
.HasColumnType("bit");
b.Property<bool>("IsDelivered")
.HasColumnType("bit");
b.Property<bool>("IsOpened")
.HasColumnType("bit");
b.Property<bool>("IsSent")
.HasColumnType("bit");
b.Property<bool>("IsSpam")
.HasColumnType("bit");
b.Property<bool>("IsUnsubscribed")
.HasColumnType("bit");
b.Property<DateTime>("ReceivedActivity")
.HasColumnType("datetime2");
b.Property<string>("RecipientEmail")
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("SentDate")
.HasColumnType("datetime2");
b.Property<string>("Subject")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("SentNewsletterEamils");
});
modelBuilder.Entity("Model.SocialMedia", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("SocialMedia");
});
modelBuilder.Entity("Model.Subscription", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsSubscribed")
.HasColumnType("bit");
b.Property<string>("Name")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Subscriptions");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Model.Answer", b =>
{
b.HasOne("Model.Question", "Question")
.WithMany("Answers")
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Question");
});
modelBuilder.Entity("Model.FooterSocialMedia", b =>
{
b.HasOne("Model.Footer", "Footer")
.WithMany("FooterSocialMedias")
.HasForeignKey("FooterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Model.SocialMedia", "SocialMedia")
.WithMany("FooterSocialMedias")
.HasForeignKey("SocialId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Footer");
b.Navigation("SocialMedia");
});
modelBuilder.Entity("Model.Page", b =>
{
b.HasOne("Model.Banner", "banner")
.WithMany()
.HasForeignKey("BannerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Model.Footer", "footer")
.WithMany()
.HasForeignKey("FooterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("banner");
b.Navigation("footer");
});
modelBuilder.Entity("Model.Question", b =>
{
b.HasOne("Model.Questionnaire", "Questionnaire")
.WithMany("Questions")
.HasForeignKey("QuestionnaireId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Questionnaire");
});
modelBuilder.Entity("Model.Response", b =>
{
b.HasOne("Model.Questionnaire", "Questionnaire")
.WithMany()
.HasForeignKey("QuestionnaireId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Questionnaire");
});
modelBuilder.Entity("Model.ResponseAnswer", b =>
{
b.HasOne("Model.ResponseDetail", "ResponseDetail")
.WithMany("ResponseAnswers")
.HasForeignKey("ResponseDetailId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ResponseDetail");
});
modelBuilder.Entity("Model.ResponseDetail", b =>
{
b.HasOne("Model.Question", "Question")
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Model.Response", "Response")
.WithMany("ResponseDetails")
.HasForeignKey("ResponseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Question");
b.Navigation("Response");
});
modelBuilder.Entity("Model.Footer", b =>
{
b.Navigation("FooterSocialMedias");
});
modelBuilder.Entity("Model.Question", b =>
{
b.Navigation("Answers");
});
modelBuilder.Entity("Model.Questionnaire", b =>
{
b.Navigation("Questions");
});
modelBuilder.Entity("Model.Response", b =>
{
b.Navigation("ResponseDetails");
});
modelBuilder.Entity("Model.ResponseDetail", b =>
{
b.Navigation("ResponseAnswers");
});
modelBuilder.Entity("Model.SocialMedia", b =>
{
b.Navigation("FooterSocialMedias");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,60 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Web.Migrations
{
/// <inheritdoc />
public partial class AddConditionalLogicToAnswers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "NextQuestionId",
table: "ResponseAnswers",
type: "int",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "SkipToEnd",
table: "ResponseAnswers",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<int>(
name: "NextQuestionId",
table: "Answers",
type: "int",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "SkipToEnd",
table: "Answers",
type: "bit",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "NextQuestionId",
table: "ResponseAnswers");
migrationBuilder.DropColumn(
name: "SkipToEnd",
table: "ResponseAnswers");
migrationBuilder.DropColumn(
name: "NextQuestionId",
table: "Answers");
migrationBuilder.DropColumn(
name: "SkipToEnd",
table: "Answers");
}
}
}

View file

@ -0,0 +1,835 @@
// <auto-generated />
using System;
using Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Web.Migrations
{
[DbContext(typeof(SurveyContext))]
[Migration("20250808101628_AddConditionJsonToAnswers")]
partial class AddConditionJsonToAnswers
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderKey")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("RoleId")
.HasColumnType("nvarchar(450)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("Name")
.HasColumnType("nvarchar(450)");
b.Property<string>("Value")
.HasColumnType("nvarchar(max)");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Model.Address", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("CVR")
.HasColumnType("nvarchar(max)");
b.Property<string>("City")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Country")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Mobile")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("PostalCode")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("State")
.HasColumnType("nvarchar(max)");
b.Property<string>("Street")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Addresss");
});
modelBuilder.Entity("Model.Answer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ConditionJson")
.HasColumnType("nvarchar(max)");
b.Property<int>("QuestionId")
.HasColumnType("int");
b.Property<string>("Text")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.ToTable("Answers");
});
modelBuilder.Entity("Model.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("bit");
b.Property<string>("FirstName")
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.HasColumnType("nvarchar(max)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("bit");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetimeoffset");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("nvarchar(max)");
b.Property<string>("PhoneNumber")
.HasColumnType("nvarchar(max)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("bit");
b.Property<string>("SecurityStamp")
.HasColumnType("nvarchar(max)");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("bit");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Model.Banner", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ImageUrl")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("LinkUrl")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Banners");
});
modelBuilder.Entity("Model.Footer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("CreatedBy")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ImageUlr")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("LastUpdated")
.HasColumnType("datetime2");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Owner")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Sitecopyright")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("UpdatedBy")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Footers");
});
modelBuilder.Entity("Model.FooterSocialMedia", b =>
{
b.Property<int>("FooterId")
.HasColumnType("int");
b.Property<int>("SocialId")
.HasColumnType("int");
b.HasKey("FooterId", "SocialId");
b.HasIndex("SocialId");
b.ToTable("FooterSocialMedias");
});
modelBuilder.Entity("Model.Page", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("BannerId")
.HasColumnType("int");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("FooterId")
.HasColumnType("int");
b.Property<string>("Slug")
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("BannerId");
b.HasIndex("FooterId");
b.ToTable("Pages");
});
modelBuilder.Entity("Model.Question", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("QuestionnaireId")
.HasColumnType("int");
b.Property<string>("Text")
.HasColumnType("nvarchar(max)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("QuestionnaireId");
b.ToTable("Questions");
});
modelBuilder.Entity("Model.Questionnaire", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.HasColumnType("nvarchar(max)");
b.Property<string>("Title")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Questionnaires");
});
modelBuilder.Entity("Model.Response", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("QuestionnaireId")
.HasColumnType("int");
b.Property<DateTime>("SubmissionDate")
.HasColumnType("datetime2");
b.Property<string>("UserEmail")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserName")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("QuestionnaireId");
b.ToTable("Responses");
});
modelBuilder.Entity("Model.ResponseAnswer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("AnswerId")
.HasColumnType("int");
b.Property<int>("ResponseDetailId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ResponseDetailId");
b.ToTable("ResponseAnswers");
});
modelBuilder.Entity("Model.ResponseDetail", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("QuestionId")
.HasColumnType("int");
b.Property<int>("QuestionType")
.HasColumnType("int");
b.Property<int>("ResponseId")
.HasColumnType("int");
b.Property<string>("TextResponse")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.HasIndex("ResponseId");
b.ToTable("ResponseDetails");
});
modelBuilder.Entity("Model.SentNewsletterEamil", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Body")
.HasColumnType("nvarchar(max)");
b.Property<string>("Geo")
.HasColumnType("nvarchar(max)");
b.Property<string>("IpAddress")
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsBlocked")
.HasColumnType("bit");
b.Property<bool>("IsBounced")
.HasColumnType("bit");
b.Property<bool>("IsClicked")
.HasColumnType("bit");
b.Property<bool>("IsDelivered")
.HasColumnType("bit");
b.Property<bool>("IsOpened")
.HasColumnType("bit");
b.Property<bool>("IsSent")
.HasColumnType("bit");
b.Property<bool>("IsSpam")
.HasColumnType("bit");
b.Property<bool>("IsUnsubscribed")
.HasColumnType("bit");
b.Property<DateTime>("ReceivedActivity")
.HasColumnType("datetime2");
b.Property<string>("RecipientEmail")
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("SentDate")
.HasColumnType("datetime2");
b.Property<string>("Subject")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("SentNewsletterEamils");
});
modelBuilder.Entity("Model.SocialMedia", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("SocialMedia");
});
modelBuilder.Entity("Model.Subscription", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsSubscribed")
.HasColumnType("bit");
b.Property<string>("Name")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Subscriptions");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Model.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Model.Answer", b =>
{
b.HasOne("Model.Question", "Question")
.WithMany("Answers")
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Question");
});
modelBuilder.Entity("Model.FooterSocialMedia", b =>
{
b.HasOne("Model.Footer", "Footer")
.WithMany("FooterSocialMedias")
.HasForeignKey("FooterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Model.SocialMedia", "SocialMedia")
.WithMany("FooterSocialMedias")
.HasForeignKey("SocialId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Footer");
b.Navigation("SocialMedia");
});
modelBuilder.Entity("Model.Page", b =>
{
b.HasOne("Model.Banner", "banner")
.WithMany()
.HasForeignKey("BannerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Model.Footer", "footer")
.WithMany()
.HasForeignKey("FooterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("banner");
b.Navigation("footer");
});
modelBuilder.Entity("Model.Question", b =>
{
b.HasOne("Model.Questionnaire", "Questionnaire")
.WithMany("Questions")
.HasForeignKey("QuestionnaireId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Questionnaire");
});
modelBuilder.Entity("Model.Response", b =>
{
b.HasOne("Model.Questionnaire", "Questionnaire")
.WithMany()
.HasForeignKey("QuestionnaireId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Questionnaire");
});
modelBuilder.Entity("Model.ResponseAnswer", b =>
{
b.HasOne("Model.ResponseDetail", "ResponseDetail")
.WithMany("ResponseAnswers")
.HasForeignKey("ResponseDetailId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ResponseDetail");
});
modelBuilder.Entity("Model.ResponseDetail", b =>
{
b.HasOne("Model.Question", "Question")
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Model.Response", "Response")
.WithMany("ResponseDetails")
.HasForeignKey("ResponseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Question");
b.Navigation("Response");
});
modelBuilder.Entity("Model.Footer", b =>
{
b.Navigation("FooterSocialMedias");
});
modelBuilder.Entity("Model.Question", b =>
{
b.Navigation("Answers");
});
modelBuilder.Entity("Model.Questionnaire", b =>
{
b.Navigation("Questions");
});
modelBuilder.Entity("Model.Response", b =>
{
b.Navigation("ResponseDetails");
});
modelBuilder.Entity("Model.ResponseDetail", b =>
{
b.Navigation("ResponseAnswers");
});
modelBuilder.Entity("Model.SocialMedia", b =>
{
b.Navigation("FooterSocialMedias");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,70 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Web.Migrations
{
/// <inheritdoc />
public partial class AddConditionJsonToAnswers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "NextQuestionId",
table: "ResponseAnswers");
migrationBuilder.DropColumn(
name: "SkipToEnd",
table: "ResponseAnswers");
migrationBuilder.DropColumn(
name: "NextQuestionId",
table: "Answers");
migrationBuilder.DropColumn(
name: "SkipToEnd",
table: "Answers");
migrationBuilder.AddColumn<string>(
name: "ConditionJson",
table: "Answers",
type: "nvarchar(max)",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ConditionJson",
table: "Answers");
migrationBuilder.AddColumn<int>(
name: "NextQuestionId",
table: "ResponseAnswers",
type: "int",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "SkipToEnd",
table: "ResponseAnswers",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<int>(
name: "NextQuestionId",
table: "Answers",
type: "int",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "SkipToEnd",
table: "Answers",
type: "bit",
nullable: false,
defaultValue: false);
}
}
}

View file

@ -206,6 +206,9 @@ namespace Web.Migrations
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ConditionJson")
.HasColumnType("nvarchar(max)");
b.Property<int>("QuestionId") b.Property<int>("QuestionId")
.HasColumnType("int"); .HasColumnType("int");

View file

@ -0,0 +1,54 @@
using Model;
namespace Web.ViewModel.QuestionnaireVM
{
public class SetLogicViewModel
{
public int QuestionnaireId { get; set; }
public string QuestionnaireName { get; set; } = string.Empty;
public List<QuestionLogicViewModel> Questions { get; set; } = new List<QuestionLogicViewModel>();
}
// ViewModel for each question in the logic setup
public class QuestionLogicViewModel
{
public int QuestionId { get; set; }
public string QuestionText { get; set; } = string.Empty;
public QuestionType QuestionType { get; set; }
public int QuestionNumber { get; set; }
public List<AnswerConditionViewModel> Answers { get; set; } = new List<AnswerConditionViewModel>();
}
// ViewModel for each answer's condition
public class AnswerConditionViewModel
{
public int AnswerId { get; set; }
public string AnswerText { get; set; } = string.Empty;
public ConditionActionType ActionType { get; set; } = ConditionActionType.Continue;
public int? TargetQuestionNumber { get; set; }
public int? SkipCount { get; set; }
public string? EndMessage { get; set; }
}
// Enum for condition action types
public enum ConditionActionType
{
Continue = 0,
SkipToQuestion = 1,
SkipCount = 2,
EndSurvey = 3
}
// ViewModel for saving conditions
public class SaveConditionsViewModel
{
public int QuestionnaireId { get; set; }
public List<AnswerConditionSaveViewModel> Conditions { get; set; } = new List<AnswerConditionSaveViewModel>();
}
public class AnswerConditionSaveViewModel
{
public int AnswerId { get; set; }
public string ConditionJson { get; set; } = string.Empty;
}
}