participant registration

This commit is contained in:
jojo aquino 2025-01-12 18:09:05 +00:00
parent 3e7663bbbe
commit 7c54dd5a69
12 changed files with 357 additions and 119 deletions

View File

@ -0,0 +1,32 @@
using EnotaryoPH.Data;
using EnotaryoPH.Web.Common.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace EnotaryoPH.Web.Pages
{
public abstract class BaseIdentificationDocumentPageModel : PageModel
{
protected readonly NotaryoDBContext _notaryoDBContext;
protected BaseIdentificationDocumentPageModel(NotaryoDBContext notaryoDBContext) => _notaryoDBContext = notaryoDBContext;
protected void CreateIdentificationDocument(Guid user_UID)
{
ArgumentOutOfRangeException.ThrowIfEqual(Guid.Empty, user_UID);
var user = _notaryoDBContext.Users.AsNoTracking().FirstOrDefault(u => u.User_UID == user_UID) ?? throw new ArgumentException("User does not exist.");
var entity = NewIdentificationDocument.ToEntity(user.UserID);
_notaryoDBContext.Add(entity);
_notaryoDBContext.SaveChanges();
}
[BindProperty(SupportsGet = true)]
public Guid IdentificationDocument_UID { get; set; }
[BindProperty]
public IdentificationDocumentModel NewIdentificationDocument { get; set; }
[BindProperty]
public bool UploadNewIdentification { get; set; }
}
}

View File

@ -9,10 +9,15 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration
public class IndexModel : PageModel
{
private readonly NotaryoDBContext _notaryoDBContext;
private readonly ISignInService _signInService;
public IndexModel(NotaryoDBContext notaryoDBContext) => _notaryoDBContext = notaryoDBContext;
public IndexModel(NotaryoDBContext notaryoDBContext, ISignInService signInService)
{
_notaryoDBContext = notaryoDBContext;
_signInService = signInService;
}
public IActionResult OnGet()
public async Task<IActionResult> OnGetAsync()
{
if (string.IsNullOrEmpty(InvitationCode))
{
@ -20,7 +25,9 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration
}
var invitationCodeGuid = InvitationCode.ToGuidFromBase64();
var signatory = _notaryoDBContext.TransactionSignatories.FirstOrDefault(e => e.InvitationCode == invitationCodeGuid.ToString() && e.Status == nameof(SignatoryStatus.New));
var signatory = _notaryoDBContext.TransactionSignatories
.Include(e => e.Transaction)
.FirstOrDefault(e => e.InvitationCode == invitationCodeGuid.ToString() && (e.Status == nameof(SignatoryStatus.New) || e.Status == nameof(SignatoryStatus.Registered)));
if (signatory == null)
{
return NotFound();
@ -33,7 +40,15 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration
signatory.UserID = existingUser.UserID;
_notaryoDBContext.Update(signatory);
_notaryoDBContext.SaveChanges();
return Redirect("Steps/UploadIdentification");
await _signInService.SignInAsync(new UserLogin
{
Email = existingUser.Email,
Role = existingUser.Role,
User_UID = existingUser.User_UID.Value
});
return Redirect($"Steps/UploadIdentification/{signatory.Transaction.Transaction_UID}");
}
TransactionSignatory_UID = signatory.TransactionSignatory_UID.GetValueOrDefault();
@ -41,7 +56,7 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration
return Page();
}
public IActionResult OnPost()
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
@ -54,7 +69,8 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration
return Page();
}
var signatory = _notaryoDBContext.TransactionSignatories.FirstOrDefault(e => e.TransactionSignatory_UID == TransactionSignatory_UID && e.Status == nameof(SignatoryStatus.New));
var signatory = _notaryoDBContext.TransactionSignatories
.FirstOrDefault(e => e.TransactionSignatory_UID == TransactionSignatory_UID && e.Status == nameof(SignatoryStatus.New));
if (signatory == null)
{
return BadRequest();
@ -81,7 +97,14 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration
_notaryoDBContext.Update(signatory);
_notaryoDBContext.SaveChanges();
return Redirect("Steps/UploadIdentification");
await _signInService.SignInAsync(new UserLogin
{
Email = newUser.Email,
Role = newUser.Role,
User_UID = newUser.User_UID.Value
});
return Redirect($"Steps/UploadIdentification/{signatory.Transaction.Transaction_UID}");
}
[BindProperty(SupportsGet = true)]

View File

@ -0,0 +1,37 @@
@page "{Transaction_UID:guid}"
@model EnotaryoPH.Web.Pages.Participant.Registration.Steps.TakeSelfieModel
@{
}
<section class="my-5">
<div class="container">
<h1>Registration Steps</h1>
<div class="mt-3">
<ul id="transactionwizardnav" class="nav nav-pills nav-justified d-block d-sm-flex" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link disabled" role="tab" data-bs-toggle="pill" href="#tab-1">
<div><span class="badge rounded-pill fs-6 me-1">STEP 1</span></div><span class="text-dark step-text">Choose Identification</span>
</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link disabled active" role="tab" data-bs-toggle="pill" href="#" style="border-bottom-width: 3px;border-bottom-color: var(--bs-body-color);">
<div class="text-dark"><span class="badge rounded-pill fs-6 me-1">STEP 2</span></div><span class="text-dark step-text">Take Selfie</span>
</a>
</li>
</ul>
<div class="tab-content mt-3"></div>
</div>
<div class="row">
<div class="col">
<form class="mt-3">
<div class="ratio ratio-16x9"><iframe allowfullscreen frameborder="0" src="https://www.youtube.com/embed/d1CT5wr0I1c" width="560" height="315"></iframe></div>
</form>
<div class="d-flex mt-3">
<a class="btn btn-secondary btn-lg me-1" role="button" href="dashboard.html"><i class="fas fa-camera me-2"></i>TAKE PICTURE</a><a class="btn btn-secondary btn-lg" role="button" href="dashboard.html"><i class="fas fa-redo-alt me-2"></i>AGAIN</a>
<div class="flex-grow-1"></div><button class="btn btn-primary btn-lg" type="button" data-bs-target="#modal-message" data-bs-toggle="modal">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
</div>
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace EnotaryoPH.Web.Pages.Participant.Registration.Steps
{
public class TakeSelfieModel : PageModel
{
public void OnGet()
{
}
[BindProperty(SupportsGet = true)]
public Guid Transaction_UID { get; set; }
}
}

View File

@ -1,106 +1,46 @@
@page
@page "{Transaction_UID:guid}"
@using EnotaryoPH.Web.Pages.Shared.Components.NotaryoSteps
@using EnotaryoPH.Web.Pages.Shared.Components.UploadOrChooseIdentificationDocument
@model EnotaryoPH.Web.Pages.Participant.Registration.Steps.UploadIdentificationModel
<section class="mt-5 mb-2">
@section Head {
<link href="\lib\fontawesome-free-6.7.1-web\css\all.min.css" rel="stylesheet" />
}
<section class="my-5">
<div class="container">
<h1>Registration Steps</h1>
<div class="mt-3">
<ul id="transactionwizardnav" class="nav nav-pills nav-justified d-block d-sm-flex" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link active" role="tab" data-bs-toggle="pill" href="#tab-1">
<div><span class="badge rounded-pill fs-6 me-1">STEP 1</span></div><span class="text-dark step-text">Choose Identification</span>
</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link disabled" role="tab" data-bs-toggle="pill" href="#" style="border-bottom-width: 3px;border-bottom-color: var(--bs-body-color);">
<div class="text-dark"><span class="badge rounded-pill fs-6 me-1">STEP 2</span></div><span class="text-dark step-text">Take Selfie</span>
</a>
</li>
</ul>
<div class="tab-content mt-3"></div>
</div>
<div>
<div class="row mt-4 mb-3">
<div class="col">
<div class="d-flex">
<div class="form-check me-2"><input id="checkUpload" class="form-check-input" type="radio" checked value="UploadNew" name="NewOrOld" /><label class="form-check-label me-3" for="checkUpload">Upload a new Identification Document</label></div>
<div class="form-check"><input id="checkUseExisting" class="form-check-input" type="radio" value="UseExisting" name="NewOrOld" /><label class="form-check-label" for="checkUseExisting">Use any of the existing Identification Documents</label></div>
</div>
<div class="row">
<div class="col">
<h1>Notaryo Steps</h1>
<div class="mt-3">
@await Component.InvokeAsync("NotaryoSteps", new
{
NotaryoSteps = new List<NotaryoStep>()
{
new NotaryoStep { Name = "Upload Identification", Step = 1, IsActive = true },
new NotaryoStep { Name = "Take Selfie", Step = 2 }
}
})
<div class="tab-content mt-3"></div>
</div>
<form class="mt-4" id="UploadIdentificationForm" method="post" enctype="multipart/form-data">
@await Component.InvokeAsync("UploadOrChooseIdentificationDocument", Model.Transaction_UID)
<div class="d-flex mt-3">
<div class="flex-grow-1"></div>
<button class="btn btn-primary btn-lg wizard__nextbutton" type="submit">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
</div>
</form>
</div>
<div class="row mt-4">
<div class="col-12 col-lg-4">
<div class="card" data-bss-baguettebox>
<a href="cody passport.webp"><img class="card-img w-100 d-block fit-cover rounded-top" src="cody passport.webp" style="height: 300px;" /></a>
<div class="card-body p-2">
<p class="card-text mb-1">passport-2024-12-07__final.jpg</p>
<div><button class="btn btn-secondary btn-sm me-1" type="button">Upload Photo<i class="fas fa-upload ms-1"></i></button></div>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="col-12 col-lg-7">
<div>
<label class="form-label">Type</label><select class="form-select">
<option value="12" selected>Driver&#39;s License</option>
<option value="13">This is item 2</option>
<option value="14">This is item 3</option>
</select>
</div>
</div>
<div class="col-12 col-lg-7">
<div class="mb-3"><label class="form-label">ID Number</label><input class="form-control" type="text" /></div>
</div>
</div>
<div class="row">
<div class="col-12 col-lg-7">
<div class="mb-3"><label class="form-label">Place Issued</label><input class="form-control" type="text" /></div>
</div>
<div class="col-12 col-lg-7">
<div class="row">
<div class="col-12 col-sm-6">
<div class="mb-3"><label class="form-label">Expiration Date</label><input id="name-1" class="form-control" name="name" placeholder="Name" value="2024-11-30" type="date" /></div>
</div>
<div class="col-12 col-sm-6">
<div class="mb-3"><label class="form-label">Date Issued</label><input id="name-4" class="form-control" name="name" placeholder="Name" value="2024-11-30" type="date" /></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col">
<h4>Existing Identification Documents</h4>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Identification Document Type</th>
<th>Uploaded On</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Driver&#39;s License</td>
<td>2024-11-31</td>
<td><button class="btn btn-danger btn-sm identificationdocument__delete__button" type="button"><i class="fas fa-times me-1"></i><span class="d-none d-md-inline-block">Delete</span></button></td>
</tr>
<tr>
<td>Passport</td>
<td>2024-12-17</td>
<td><button class="btn btn-danger btn-sm" type="button"><i class="fas fa-times me-1"></i><span class="d-none d-md-inline-block">Delete</span></button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="d-flex mt-4">
<div class="flex-grow-1"></div><a class="btn btn-primary btn-lg" role="button" href="/participant/onboardingwizard2_selfie.html">NEXT<i class="fas fa-chevron-right ms-2"></i></a>
</div>
</div>
</section>
@section Scripts {
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<partial name="_ValidationScriptsPartial" />
<script src="/dist/js/jfa.min.js"></script>
<script src="/js/identification-document.js"></script>
<script src="~/Pages/Participant/Registration/Steps/UploadIdentification.cshtml.js" asp-append-version="true"></script>
}

View File

@ -1,12 +1,36 @@
using EnotaryoPH.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace EnotaryoPH.Web.Pages.Participant.Registration.Steps
{
public class UploadIdentificationModel : PageModel
public class UploadIdentificationModel : BaseIdentificationDocumentPageModel
{
private readonly ICurrentUserService _currentUserService;
public UploadIdentificationModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService)
: base(notaryoDBContext) => _currentUserService = currentUserService;
public void OnGet()
{
}
public async Task<IActionResult> OnPostAsync()
{
if (UploadNewIdentification)
{
if (!ModelState.IsValid)
{
return Page();
}
CreateIdentificationDocument(_currentUserService.GetUser_UID());
}
return Redirect($"../TakeSelfie/{Transaction_UID}");
}
[BindProperty(SupportsGet = true)]
public Guid Transaction_UID { get; set; }
}
}

View File

@ -0,0 +1,34 @@
"use strict";
(function () {
const
control_existingDocumentsContainer = document.getElementById("ExistingDocumentsContainer"),
control_newIdentificationDocumentContainer = document.getElementById("NewIdentificationDocumentContainer"),
control_uploadNewIdentificationRadios = document.getElementsByName("UploadNewIdentification");
function _bindEvents() {
control_uploadNewIdentificationRadios.forEach(radio => {
radio.addEventListener("change", _radioOptionChanged)
});
}
function _init() {
_bindEvents();
_radioOptionChanged(null);
}
function _radioOptionChanged(sender) {
let uploadNewIdentificationDocument = sender?.target?.value ?? "true";
if (uploadNewIdentificationDocument === "true") {
jfa.utilities.element.hide(control_existingDocumentsContainer);
jfa.utilities.element.show(control_newIdentificationDocumentContainer)
}
else {
jfa.utilities.element.show(control_existingDocumentsContainer);
jfa.utilities.element.hide(control_newIdentificationDocumentContainer)
}
}
_init();
})();

View File

@ -3,7 +3,6 @@ using EnotaryoPH.Web.Common.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
{
@ -37,7 +36,6 @@ namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
return Page();
}
[IgnoreAntiforgeryToken]
public async Task<IActionResult> OnPostAsync()
{
if (UploadNewIdentification)
@ -50,11 +48,6 @@ namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
};
return Page();
}
var user = _notaryoDBContext.Users.AsNoTracking().FirstOrDefault(u => u.User_UID == _currentUserService.GetUser_UID());
var entity = NewIdentificationDocument.ToEntity(user.UserID);
_notaryoDBContext.Add(entity);
_notaryoDBContext.SaveChanges();
}
return RedirectToPage("/Principal/NotaryoSteps/TakeSelfie");

View File

@ -0,0 +1,59 @@
@model UploadOrChooseIdentificationDocumentModel
@if (Model.ExistingIdentificationDocuments.Count > 0)
{
<div class="row mt-4 mb-3">
<div class="col">
<div class="d-flex">
<div class="form-check me-2"><input asp-for="UploadNewIdentification" id="UploadNewIdentificationYes" class="form-check-input" type="radio" value="true" /> <label class="form-check-label me-3" for="UploadNewIdentificationYes">Upload a new Identification Document</label></div>
<div class="form-check me-2"><input asp-for="UploadNewIdentification" id="UploadNewIdentificationNah" class="form-check-input" type="radio" value="false" /><label class="form-check-label me-3" for="UploadNewIdentificationNah">Use any of the existing Identification Documents</label></div>
</div>
</div>
</div>
}
else
{
<input type="hidden" asp-for="UploadNewIdentification" />
}
<div id="NewIdentificationDocumentContainer">
@Html.EditorFor(m => m.NewIdentificationDocument)
</div>
@if (Model.ExistingIdentificationDocuments.Count > 0)
{
<div id="ExistingDocumentsContainer">
<div class="row mt-4">
<div class="col">
<h4>Existing Identification Documents</h4>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Identification Document Type</th>
<th>Expiration</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var id in Model.ExistingIdentificationDocuments)
{
<tr class="existingdocument__row">
<td>@id.IdentificationType</td>
<td>@id.ExpirationDate.Value.ToShortDateString()</td>
<td>
<button class="btn btn-danger btn-sm identificationdocument__delete__button" type="button" data-uid="@id.IdentificationDocument_UID">
<i class="fas fa-times me-1"></i>
<span class="d-none d-md-inline-block">Delete</span>
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
}
<input type="hidden" asp-for="ExistingIdentificationDocumentCount" />

View File

@ -0,0 +1,59 @@
using EnotaryoPH.Data;
using EnotaryoPH.Web.Common.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace EnotaryoPH.Web.Pages.Shared.Components.UploadOrChooseIdentificationDocument
{
public class UploadOrChooseIdentificationDocumentViewComponent : ViewComponent
{
private readonly ICurrentUserService _currentUserService;
private readonly NotaryoDBContext _notaryoDBContext;
public UploadOrChooseIdentificationDocumentViewComponent(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService)
{
_notaryoDBContext = notaryoDBContext;
_currentUserService = currentUserService;
}
public async Task<IViewComponentResult> InvokeAsync(Guid transaction_UID)
{
var model = new UploadOrChooseIdentificationDocumentModel
{
ExistingIdentificationDocuments = [],
NewIdentificationDocument = new(),
UploadNewIdentification = true
};
var user = _notaryoDBContext.Users.AsNoTracking().FirstOrDefault(u => u.User_UID == _currentUserService.GetUser_UID());
if (user == null)
{
return View(model);
}
model.ExistingIdentificationDocuments = GetIdentityDocumentsByUserID(user.UserID);
model.NewIdentificationDocument = new IdentificationDocumentModel
{
IdentificationTypes = GetIdentificationDocumentTypes()
};
model.UploadNewIdentification = true;
return View(model);
}
private List<SelectListItem> GetIdentificationDocumentTypes()
{
var lookupIdentificationTypes = _notaryoDBContext.LookupData.AsNoTracking().Include(e => e.LookupDataValues).FirstOrDefault(e => e.Name == "Identification Types");
return lookupIdentificationTypes.LookupDataValues
.ConvertAll(m => new SelectListItem
{
Text = m.Title.DefaultIfEmpty(m.Value),
Value = m.Value
});
}
private List<IdentificationDocumentModel> GetIdentityDocumentsByUserID(int userID)
=> _notaryoDBContext.IdentificationDocuments
.AsNoTracking()
.Where(d => d.UserID == userID)
.Select(d => new IdentificationDocumentModel(d)).ToList();
}
}

View File

@ -0,0 +1,18 @@
using EnotaryoPH.Web.Common.Models;
using Microsoft.AspNetCore.Mvc;
namespace EnotaryoPH.Web.Pages.Shared.Components.UploadOrChooseIdentificationDocument
{
public class UploadOrChooseIdentificationDocumentModel
{
public int ExistingIdentificationDocumentCount => ExistingIdentificationDocuments.Count;
public List<IdentificationDocumentModel> ExistingIdentificationDocuments { get; set; } = [];
[BindProperty]
public IdentificationDocumentModel NewIdentificationDocument { get; set; }
[BindProperty]
public bool UploadNewIdentification { get; set; }
}
}

View File

@ -18,8 +18,13 @@ namespace EnotaryoPH.Web
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options => options.LoginPath = new Microsoft.AspNetCore.Http.PathString("/Login"));
builder.Services.AddAuthorization(options => options.AddPolicy("PrincipalPolicy", policy => policy.RequireRole("Principal")));
var razorBuilder = builder.Services.AddRazorPages(options => options.Conventions.AuthorizeFolder("/Principal", "PrincipalPolicy"));
builder.Services.AddAuthorization(options => options.AddPolicy("PrincipalPolicy", policy => policy.RequireRole(nameof(UserType.Principal))));
builder.Services.AddAuthorization(options => options.AddPolicy("ParticipantPolicy", policy => policy.RequireRole(nameof(UserType.Witness), nameof(UserType.Principal))));
var razorBuilder = builder.Services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/Principal", "PrincipalPolicy");
options.Conventions.AuthorizeFolder("/Participant/Registration/Steps", "ParticipantPolicy");
});
#if DEBUG
razorBuilder.AddRazorRuntimeCompilation();
#endif
@ -34,7 +39,6 @@ namespace EnotaryoPH.Web
{
BaseUrl = config.GetValue<string>("BaseUrl") ?? ""
});
builder.Services.AddTransient<ISignInService, SignInService>();
builder.Services.AddTransient<IPasswordService, PasswordService>();
builder.Services.AddTransient<ICurrentUserService, CurrentUserService>();