Вытащил солюшен на уровень выше, чтобы прощё было дотнетить
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is failing
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	continuous-integration/drone/push Build is failing
				
			This commit is contained in:
		
							
								
								
									
										60
									
								
								BlazorWebAssemblyVisaApiClient/Pages/AddAuthority.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								BlazorWebAssemblyVisaApiClient/Pages/AddAuthority.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| @page "/authorities/add" | ||||
| @using AutoMapper | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.Applicants.Models | ||||
| @using FluentValidation | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <EditForm Model="requestModel" class="with-centered-content"> | ||||
|     <ObjectGraphDataAnnotationsValidator/> | ||||
|     <div > | ||||
|         <label> | ||||
|             Email:<br/> | ||||
|             <InputText class="rounded" @bind-Value="requestModel.AuthData.Email"/> | ||||
|             <ValidationMessage For="() => requestModel.AuthData.Email"/> | ||||
|         </label><br/> | ||||
|         <p/> | ||||
|  | ||||
|         <label> | ||||
|             Password:<br/> | ||||
|             <InputText type="password" class="rounded" @bind-Value="requestModel.AuthData.Password"/> | ||||
|             <ValidationMessage For="() => requestModel.AuthData.Password"/> | ||||
|         </label><br/> | ||||
|         <p/> | ||||
|  | ||||
|         <button class="btn-primary rounded" @onclick="Add">Add</button><br/> | ||||
|         <Status @ref="status"/> | ||||
|     </div> | ||||
| </EditForm> | ||||
|  | ||||
| @code | ||||
| { | ||||
|     private RegisterRequestModel requestModel = new(); | ||||
|     private Status status = new(); | ||||
|  | ||||
|     [Inject] private IValidator<RegisterRequestModel> RegisterRequestModelValidator { get; set; } = null!; | ||||
|     [Inject] private IMapper Mapper { get; set; } = null!; | ||||
|  | ||||
|     private async Task Add() | ||||
|     { | ||||
|         var validationResult = await RegisterRequestModelValidator.ValidateAsync(requestModel); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             status.SetError(validationResult.ToErrorsString()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             status.SetMessage("Wait..."); | ||||
|             await Client.RegisterAuthorityAsync(Mapper.Map<RegisterRequest>(requestModel)); | ||||
|             status.SetSuccess("Success"); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										261
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Application.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Application.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,261 @@ | ||||
| @page "/applications/{ApplicationId}" | ||||
| @using System.Net | ||||
| @using BlazorWebAssemblyVisaApiClient.Common.Exceptions | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.Applicants.Models | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <PageTitle>Application</PageTitle> | ||||
|  | ||||
| <table class="table table-bordered table-hover table-sm"> | ||||
|     <tbody> | ||||
|     <tr> | ||||
|         <td > | ||||
|             Applicant's fullname:<br/> | ||||
|             <em>@NameToString(application.Applicant.Name)</em> | ||||
|         </td> | ||||
|         <td colspan="2"> | ||||
|             Date of birth:<br/> | ||||
|             <em>@application.Applicant.BirthDate.ToString("d")</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Country and city of birth:<br/> | ||||
|             <em>@application.Applicant.CountryOfBirth, @application.Applicant.CityOfBirth</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="2"> | ||||
|             Citizenship:<br/> | ||||
|             <em>@application.Applicant.Citizenship</em> | ||||
|         </td> | ||||
|         <td> | ||||
|             Citizenship by birth:<br/> | ||||
|             <em>@application.Applicant.CitizenshipByBirth</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td > | ||||
|             Gender:<br/> | ||||
|             <em>@application.Applicant.Gender.GetDisplayName()</em> | ||||
|         </td> | ||||
|         <td colspan="2"> | ||||
|             Marital status:<br/> | ||||
|             <em>@(((MaritalStatusModel)application.Applicant.MaritalStatus).GetDisplayName())</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td > | ||||
|             Father's fullname:<br/> | ||||
|             <em>@NameToString(application.Applicant.FatherName)</em> | ||||
|         </td> | ||||
|         <td colspan="2"> | ||||
|             Mother's fullname:<br/> | ||||
|             <em>@NameToString(application.Applicant.MotherName)</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td > | ||||
|             Passport number:<br/> | ||||
|             <em>@application.Applicant.Passport.Number</em> | ||||
|         </td> | ||||
|         <td > | ||||
|             Issue date:<br/> | ||||
|             <em>@application.Applicant.Passport.IssueDate.ToString("d")</em> | ||||
|         </td> | ||||
|         <td > | ||||
|             Expiration date:<br/> | ||||
|             <em>@application.Applicant.Passport.ExpirationDate.ToString("d")</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Passport issuer:<br/> | ||||
|             <em>@application.Applicant.Passport.Issuer</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Re-entry permission (for non-residents):<br/> | ||||
|             @if (application.Applicant.IsNonResident) | ||||
|             { | ||||
|                 <em>@(application.ReentryPermit is null ? "None" : $"{application.ReentryPermit.Number}, expires at {application.ReentryPermit.ExpirationDate:d}")</em> | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 <em>Not non-resident</em> | ||||
|             } | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Job title:<br/> | ||||
|             <em>@application.Applicant.JobTitle</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Place of work, address, hirer's phone number:<br/> | ||||
|             <em> | ||||
|                 @((MarkupString)$"{application.Applicant.PlaceOfWork.Name}<br>Address: {AddressToString(application.Applicant.PlaceOfWork.Address)}<br>Phone num: {application.Applicant.PlaceOfWork.PhoneNum}") | ||||
|             </em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td > | ||||
|             Destination Country:<br/> | ||||
|             <em>@application.DestinationCountry</em> | ||||
|         </td> | ||||
|         <td > | ||||
|             Visa category:<br/> | ||||
|             <em>@(((VisaCategoryModel)application.VisaCategory).GetDisplayName())</em> | ||||
|         </td> | ||||
|         <td > | ||||
|             Visa:<br/> | ||||
|             <em>@(application.ForGroup ? "For group" : "Individual")</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td > | ||||
|             Requested number of entries:<br/> | ||||
|             <em>@application.RequestedNumberOfEntries.GetDisplayName()</em> | ||||
|         </td> | ||||
|         <td colspan="2"> | ||||
|             Valid for:<br/> | ||||
|             <em>@($"{application.ValidDaysRequested} days")</em> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Past visas:<br/> | ||||
|             @if (application.PastVisas.Any()) | ||||
|             { | ||||
|                 foreach (var visa in application.PastVisas) | ||||
|                 { | ||||
|                     <em>@($"{visa.Name} issued at {visa.IssueDate:d} and was valid until {visa.ExpirationDate:d}")</em> | ||||
|                     <br/> | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 <em>None</em> | ||||
|             } | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Permission to destination Country, if transit:<br/> | ||||
|             @if (application.VisaCategory is VisaCategory.Transit) | ||||
|             { | ||||
|                 <em>@(application.PermissionToDestCountry is null ? "None" : $"Expires at {application.PermissionToDestCountry.ExpirationDate}, issued by: {application.PermissionToDestCountry.Issuer}")</em> | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 <em>Non-transit</em> | ||||
|             } | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td colspan="3"> | ||||
|             Past visits:<br/> | ||||
|             @if (application.PastVisas.Any()) | ||||
|             { | ||||
|                 foreach (var visit in application.PastVisits) | ||||
|                 { | ||||
|                     <em>@($"Visit to {visit.DestinationCountry}, entered at {visit.StartDate:d} and lasts until {visit.EndDate:d}")</em> | ||||
|                     <br/> | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 <em>None</em> | ||||
|             } | ||||
|         </td> | ||||
|     </tr> | ||||
|     </tbody> | ||||
| </table> | ||||
| @if (currentRole == Constants.ApprovingAuthorityRole) | ||||
| { | ||||
|     <button class="btn-outline-primary" @onclick="Approve">Approve</button> | ||||
|     <button class="btn-outline-danger" @onclick="Reject">Reject</button> | ||||
|     <Status @ref="status"/> | ||||
| } | ||||
|  | ||||
| @code { | ||||
|     private VisaApplicationModel application = new(); | ||||
|     private string currentRole = null!; | ||||
|     private Status status = null!; | ||||
|  | ||||
|     [Parameter] public string ApplicationId { get; set; } = null!; | ||||
|  | ||||
|     [Inject] private IUserDataProvider UserDataProvider { get; set; } = null!; | ||||
|  | ||||
|     [Inject] private NavigationManager Nav { get; set; } = null!; | ||||
|  | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var applicationId = Guid.Parse(ApplicationId); | ||||
|             currentRole = UserDataProvider.CurrentRole ?? throw new NotLoggedInException(); | ||||
|  | ||||
|                 application = currentRole switch | ||||
|                 { | ||||
|                     Constants.ApplicantRole => await Client.GetApplicationForApplicantAsync(applicationId), | ||||
|                     Constants.ApprovingAuthorityRole => await Client.GetApplicationForAuthorityAsync(applicationId), | ||||
|                     _ => throw new NotLoggedInException() | ||||
|                 }; | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|  | ||||
|             if (e is ApiException<ProblemDetails> { Result.Status: (int)HttpStatusCode.Conflict }) | ||||
|             { | ||||
|                 Nav.NavigateTo("/applications"); | ||||
|             } | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static string NameToString(NameModel name) | ||||
|         => $"{name.FirstName} {name.Surname} {name.Patronymic}".TrimEnd(); | ||||
|  | ||||
|     private static string AddressToString(AddressModel address) | ||||
|         => $"{address.Country}, {address.City}, {address.Street} {address.Building}"; | ||||
|  | ||||
|     private async void Approve() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             status.SetMessage("Wait..."); | ||||
|             await Client.SetStatusFromAuthorityAsync(application.Id, AuthorityRequestStatuses.Approved); | ||||
|             Nav.NavigateTo("/applications"); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             status.SetError("Error occured."); | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async void Reject() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             status.SetMessage("Wait..."); | ||||
|             await Client.SetStatusFromAuthorityAsync(application.Id, AuthorityRequestStatuses.Rejected); | ||||
|             Nav.NavigateTo("/applications"); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             status.SetError("Error occured."); | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										143
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Applications.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Applications.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| @page "/applications" | ||||
| @using BlazorWebAssemblyVisaApiClient.Common.Exceptions | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <PageTitle>Applications</PageTitle> | ||||
|  | ||||
| <table class="table table-bordered table-hover"> | ||||
|     <thead> | ||||
|     <tr> | ||||
|         <th>Destination Country</th> | ||||
|         <th>Visa Category</th> | ||||
|         <th>Request date</th> | ||||
|         <th>Days requested</th> | ||||
|         <th>Status</th> | ||||
|         <th></th> | ||||
|     </tr> | ||||
|     </thead> | ||||
|  | ||||
|     <tbody> | ||||
|     @foreach (var application in applications) | ||||
|     { | ||||
|         var rowClass = application.Status switch | ||||
|         { | ||||
|             ApplicationStatus.Pending => "", | ||||
|             ApplicationStatus.Approved => "table-success", | ||||
|             ApplicationStatus.Rejected => "table-danger", | ||||
|             ApplicationStatus.Closed => "table-danger", | ||||
|             _ => throw new ArgumentOutOfRangeException() | ||||
|         }; | ||||
|  | ||||
|         <tr class="@rowClass"> | ||||
|             <td>@application.DestinationCountry</td> | ||||
|             <td>@(((VisaCategoryModel)application.VisaCategory).GetDisplayName())</td> | ||||
|             <td>@application.RequestDate.ToString("d")</td> | ||||
|             <td>@application.ValidDaysRequested</td> | ||||
|             <td>@application.Status.GetDisplayName()</td> | ||||
|             <td> | ||||
|                 <NavLink href="@($"/applications/{application.Id}")"> | ||||
|                     <button class="btn-primary">See</button> | ||||
|                 </NavLink> | ||||
|                 @if (currentRole == Constants.ApplicantRole) | ||||
|                 { | ||||
|                     <span> | </span> | ||||
|                     <input type="button" class="btn-outline-primary" @onclick="() => DownloadApplication(application)" value="Download"/> | ||||
|                     if (application.Status is ApplicationStatus.Pending) | ||||
|                     { | ||||
|                         <span> | </span> | ||||
|                         <input type="button" class="border-danger" @onclick="() => CloseApplication(application)" value="Close"/> | ||||
|                     } | ||||
|                 } | ||||
|             </td> | ||||
|         </tr> | ||||
|     } | ||||
|     </tbody> | ||||
| </table > | ||||
|  | ||||
| <script> | ||||
|     window.downloadFileFromStream = async (contentStreamReference) => { | ||||
|         const arrayBuffer = await contentStreamReference.arrayBuffer(); | ||||
|         const blob = new Blob([arrayBuffer]); | ||||
|         const url = URL.createObjectURL(blob); | ||||
|         const anchorElement = document.createElement('a'); | ||||
|         anchorElement.href = url; | ||||
|         anchorElement.download = 'Application.xlsx'; | ||||
|         anchorElement.click(); | ||||
|         anchorElement.remove(); | ||||
|         URL.revokeObjectURL(url); | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| @code { | ||||
|     private string currentRole = null!; | ||||
|     private List<VisaApplicationPreview> applications = []; | ||||
|  | ||||
|     [Inject] private IUserDataProvider UserDataProvider { get; set; } = null!; | ||||
|  | ||||
|     [Inject] private IJSRuntime JavaScriptInterop { get; set; } = null!; | ||||
|  | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             currentRole = UserDataProvider.CurrentRole ?? throw new NotLoggedInException(); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|  | ||||
|         await Fetch(); | ||||
|     } | ||||
|  | ||||
|     private async Task Fetch() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             applications = currentRole switch | ||||
|             { | ||||
|                 Constants.ApplicantRole => (await Client.GetApplicationsForApplicantAsync()).OrderByDescending(a => a.RequestDate).ToList(), | ||||
|                 Constants.ApprovingAuthorityRole => (await Client.GetPendingAsync()).OrderByDescending(a => a.RequestDate).ToList(), | ||||
|                 _ => throw new NotLoggedInException() | ||||
|             }; | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task CloseApplication(VisaApplicationPreview application) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await Client.CloseApplicationAsync(application.Id); | ||||
|             application.Status = ApplicationStatus.Closed; | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task DownloadApplication(VisaApplicationPreview application) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var response = await Client.DownloadApplicationForApplicantAsync(application.Id); | ||||
|             using var streamRef = new DotNetStreamReference(stream: response.Stream); | ||||
|  | ||||
|             await JavaScriptInterop.InvokeVoidAsync("downloadFileFromStream", streamRef); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										32
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Auth.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Auth.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| @page "/" | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Components.Auth | ||||
| @using BlazorWebAssemblyVisaApiClient.Components.FormComponents.Applicants | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <PageTitle>Authentication</PageTitle> | ||||
|  | ||||
| <div class="with-centered-content"> | ||||
|     <EditForm class="form" Model="loginData" OnValidSubmit="TryLogin"> | ||||
|         <DataAnnotationsValidator/> | ||||
|  | ||||
|         <AuthDataInput AuthData="loginData"/><br/> | ||||
|  | ||||
|         <input class="btn-outline-primary rounded" type="submit" value="Login"/> | ||||
|         or | ||||
|         <NavLink href="register">Register</NavLink > | ||||
|         <Status><AuthComponent @ref="auth"/></Status> | ||||
|     </EditForm> | ||||
| </div> | ||||
|  | ||||
| @code | ||||
| { | ||||
|     private AuthData loginData = new(); | ||||
|     private AuthComponent auth = null!; | ||||
|  | ||||
|     private async Task TryLogin() | ||||
|     { | ||||
|         await auth.TryAuthorize(loginData); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										58
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Authorities.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Authorities.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| @page "/authorities" | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <table class="table table-bordered table-hover"> | ||||
|     <thead> | ||||
|     <tr> | ||||
|         <th>Email</th><th></th> | ||||
|     </tr> | ||||
|     </thead> | ||||
|     <tbody> | ||||
|     @foreach (var authority in authorities) | ||||
|     { | ||||
|         var path = $"authorities/{authority.Id}/{authority.Email}"; | ||||
|         <tr> | ||||
|             <td>@authority.Email</td> | ||||
|             <td> | ||||
|                 <NavLink href="@path"> | ||||
|                     <button class="btn-outline-primary">Change</button> | ||||
|                 </NavLink> | ||||
|                 | | ||||
|                     <button class="btn-outline-danger" @onclick="() => Delete(authority)">Delete</button> | ||||
|             </td> | ||||
|         </tr> | ||||
|     } | ||||
|     </tbody> | ||||
| </table> | ||||
|  | ||||
| @code { | ||||
|     private List<UserModel> authorities = []; | ||||
|  | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             authorities = (await Client.GetAuthorityAccountsAsync()).ToList(); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task Delete(UserModel authority) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await Client.RemoveAuthorityAccountAsync(authority.Id); | ||||
|             authorities.Remove(authority); | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										83
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Authority.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Authority.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| @page "/authorities/{authorityId}/{oldEmail}" | ||||
| @using BlazorWebAssemblyVisaApiClient.Common.Exceptions | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider | ||||
| @using FluentValidation | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <EditForm Model="model" class="with-centered-content"> | ||||
|     <div > | ||||
|         <label> | ||||
|             New email:<br/> | ||||
|             <InputText class="rounded" @bind-Value="model.Email"/> | ||||
|         </label><br/><p/> | ||||
|  | ||||
|         <label> | ||||
|             New password (leave blank if shouldn't be changed):<br/> | ||||
|             <InputText type="password" class="rounded" @bind-Value="model.Password"/> | ||||
|         </label><br/><p/> | ||||
|  | ||||
|         <button class="btn-primary rounded" @onclick="Save">Save</button><br/> | ||||
|         <Status @ref="status"/> | ||||
|     </div> | ||||
| </EditForm> | ||||
|  | ||||
| @code | ||||
| { | ||||
|     private Status status = null!; | ||||
|     private ChangeAuthData model = new(); | ||||
|  | ||||
|     [Parameter] public string AuthorityId { get; set; } = null!; | ||||
|  | ||||
|     [Parameter] public string OldEmail { get; set; } = null!; | ||||
|  | ||||
|     [Inject] private IUserDataProvider UserDataProvider { get; set; } = null!; | ||||
|  | ||||
|     [Inject] private IValidator<ChangeUserAuthDataRequest> ChangeUserAuthDataRequestValidator { get; set; } = null!; | ||||
|  | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             if (UserDataProvider.CurrentRole is not Constants.AdminRole) | ||||
|             { | ||||
|                 throw new NotLoggedInException(); | ||||
|             } | ||||
|  | ||||
|             model.Email = OldEmail; | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task Save() | ||||
|     { | ||||
|         var request = new ChangeUserAuthDataRequest | ||||
|         { | ||||
|             UserId = Guid.Parse(AuthorityId), | ||||
|             NewAuthData = model | ||||
|         }; | ||||
|  | ||||
|         var validationResult = await ChangeUserAuthDataRequestValidator.ValidateAsync(request); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             status.SetError(validationResult.ToErrorsString()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             status.SetMessage("Wait..."); | ||||
|             await Client.ChangeAuthorityAuthDataAsync(request); | ||||
|             status.SetSuccess("Success"); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										360
									
								
								BlazorWebAssemblyVisaApiClient/Pages/CreateApplication.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								BlazorWebAssemblyVisaApiClient/Pages/CreateApplication.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,360 @@ | ||||
| @page "/applications/new" | ||||
| @using System.Net | ||||
| @using AutoMapper | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Components.FormComponents | ||||
| @using BlazorWebAssemblyVisaApiClient.Components.FormComponents.VisaApplications | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.DateTimeProvider | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Services.UserDataProvider | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.VisaApplications.Models | ||||
| @using FluentValidation | ||||
| @using Newtonsoft.Json.Linq | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <PageTitle>New Application</PageTitle> | ||||
|  | ||||
| <div class="horizontal-centered-content"> | ||||
|     <h3>New application</h3> | ||||
|     <EditForm class="form" Model="requestModel" OnValidSubmit="TryCreate"> | ||||
|         <ObjectGraphDataAnnotationsValidator/> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Visa@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <label> | ||||
|                 Destination Country:<br/> | ||||
|                 <InputText DisplayName="Destination Country" class="rounded" @bind-Value="requestModel.DestinationCountry"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.DestinationCountry"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Category: | ||||
|                 <EnumInputList Model="requestModel" | ||||
|                                EnumProperty="r => r.VisaCategory" | ||||
|                                OnChanged="StateHasChanged"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.VisaCategory"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Number of entries: <EnumInputList Model="requestModel" EnumProperty="r => r.RequestedNumberOfEntries"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.RequestedNumberOfEntries"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 For group: <InputCheckbox @bind-Value="requestModel.IsForGroup"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => requestModel.IsForGroup"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Valid for days:<br/> | ||||
|                 <InputNumber DisplayName="Valid days" class="rounded" @bind-Value="requestModel.ValidDaysRequested"/> | ||||
|             </label> | ||||
|             <ValidationMessage For="() => requestModel.ValidDaysRequested"></ValidationMessage><br/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Past visas</h5> | ||||
|             @if (requestModel.PastVisas.Count > 0) | ||||
|             { | ||||
|                 <table class="table table-bordered table-hover"> | ||||
|                     <thead> | ||||
|                     <tr> | ||||
|                         <th>Name</th><th>Issue date</th><th>Expiration date</th><th></th> | ||||
|                     </tr> | ||||
|                     </thead> | ||||
|                     <tbody> | ||||
|                     @foreach (var visa in requestModel.PastVisas) | ||||
|                     { | ||||
|                         <tr> | ||||
|                             <td>@visa.Name</td> | ||||
|                             <td>@visa.IssueDate.ToString("d.MM.yyyy")</td> | ||||
|                             <td>@visa.ExpirationDate.ToString("d.MM.yyyy")</td> | ||||
|                             <td> | ||||
|                                 <input type="button" class="border-danger" @onclick="() => RemovePastVisa(visa)" value="X"/> | ||||
|                             </td> | ||||
|                         </tr> | ||||
|                     } | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             } | ||||
|             <label> | ||||
|                 Name:<br/> | ||||
|                 <InputText DisplayName="Past visa name" class="rounded" @bind-Value="editableVisa.Name"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisa.Name"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Issue date:<br/> | ||||
|                 <InputDate DisplayName="Past visa issue date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="editableVisa.IssueDate" | ||||
|                            max="@formattedNow"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisa.IssueDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Expiration date:<br/> | ||||
|                 <InputDate DisplayName="Past visa expiration date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="editableVisa.ExpirationDate"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisa.ExpirationDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <input type="button" class="btn-outline-primary rounded" | ||||
|                    disabled="@(requestModel.PastVisas.Count == ConfigurationConstraints.MaxPastVisas)" | ||||
|                    @onclick="AddPastVisa" value="Add"/> | ||||
|             <Status @ref="pastVisaStatus"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Past visits</h5> | ||||
|             @if (requestModel.PastVisits.Count > 0) | ||||
|             { | ||||
|                 <table class="table table-bordered table-hover"> | ||||
|                     <thead> | ||||
|                     <tr> | ||||
|                         <th>Destination Country</th><th>Start date</th><th>End date</th><th></th> | ||||
|                     </tr> | ||||
|                     </thead> | ||||
|                     <tbody> | ||||
|                     @foreach (var visit in requestModel.PastVisits) | ||||
|                     { | ||||
|                         <tr> | ||||
|                             <td>@visit.DestinationCountry</td> | ||||
|                             <td>@visit.StartDate.ToString("d.MM.yyyy")</td> | ||||
|                             <td>@visit.EndDate.ToString("d.MM.yyyy")</td> | ||||
|                             <td> | ||||
|                                 <input type="button" class="border-danger" @onclick="() => RemovePastVisit(visit)" value="X"/> | ||||
|                             </td> | ||||
|                         </tr> | ||||
|                     } | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             } | ||||
|             <label> | ||||
|                 Destination Country:<br/> | ||||
|                 <InputText DisplayName="Past visit destination Country" class="rounded" @bind-Value="editableVisit.DestinationCountry"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisit.DestinationCountry"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 Start date:<br/> | ||||
|                 <InputDate DisplayName="Past visit start date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="editableVisit.StartDate" | ||||
|                            max="@formattedNow"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisit.StartDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <label> | ||||
|                 End date:<br/> | ||||
|                 <InputDate DisplayName="Past visit end date" | ||||
|                            class="rounded" | ||||
|                            @bind-Value="editableVisit.EndDate" | ||||
|                            max="@formattedNow"/> | ||||
|             </label><br/> | ||||
|             <ValidationMessage For="() => editableVisit.EndDate"></ValidationMessage><br/> | ||||
|  | ||||
|             <input type="button" class="btn-outline-primary rounded" | ||||
|                    disabled="@(requestModel.PastVisits.Count == ConfigurationConstraints.MaxPastVisits)" | ||||
|                    @onclick="AddPastVisit" value="Add"/> | ||||
|             <Status @ref="pastVisitStatus"/> | ||||
|         </div> | ||||
|  | ||||
|         @if (requestModel.VisaCategory is VisaCategoryModel.Transit) | ||||
|         { | ||||
|             requestModel.PermissionToDestCountry ??= NewPermissionToDestCountry(); | ||||
|             <div class="form-block"> | ||||
|                 <h5>Permission to destination Country@(Constants.RequiredFieldMarkup)</h5> | ||||
|                 <PermissionToDestCountryInput PermissionToDestCountry="requestModel.PermissionToDestCountry"/> | ||||
|             </div> | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             requestModel.PermissionToDestCountry = null; | ||||
|         } | ||||
|  | ||||
|         @if (isNonResident) | ||||
|         { | ||||
|             requestModel.ReentryPermit ??= NewReentryPermit(); | ||||
|             <div class="form-block"> | ||||
|                 <h5>Re-entry permission@(Constants.RequiredFieldMarkup)</h5> | ||||
|                 <ReentryPermitInput ReentryPermit="requestModel.ReentryPermit"/> | ||||
|             </div> | ||||
|         } | ||||
|  | ||||
|         <br/><input type="submit" class="btn-outline-primary rounded" value="Register"/> | ||||
|         <ValidationSummary/> | ||||
|         <Status @ref="status"/> | ||||
|     </EditForm> | ||||
| </div> | ||||
|  | ||||
| @code { | ||||
|     private VisaApplicationCreateRequestModel requestModel = new(); | ||||
|     private Status status = null!; | ||||
|     private Status pastVisaStatus = null!; | ||||
|     private Status pastVisitStatus = null!; | ||||
|     private bool isNonResident; | ||||
|     private string formattedNow = null!; | ||||
|     private PastVisaModel editableVisa = null!; | ||||
|     private PastVisitModel editableVisit = null!; | ||||
|  | ||||
|     [Inject] IDateTimeProvider DateTimeProvider { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IUserDataProvider UserDataProvider { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IValidator<VisaApplicationCreateRequestModel> VisaApplicationCreateRequestValidator { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IValidator<PastVisaModel> PastVisaModelValidator { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IValidator<PastVisitModel> PastVisitModelValidator { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IMapper Mapper { get; set; } = null!; | ||||
|  | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         editableVisa = NewPastVisa(); | ||||
|         editableVisit = NewPastVisit(); | ||||
|         requestModel.PermissionToDestCountry = NewPermissionToDestCountry(); | ||||
|         formattedNow = DateTimeProvider.FormattedNow(); | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             isNonResident = (await UserDataProvider.GetApplicant()).IsNonResident; | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task TryCreate() | ||||
|     { | ||||
|         var validationResult = await VisaApplicationCreateRequestValidator.ValidateAsync(requestModel); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             var errorsString = validationResult.ToErrorsString(); | ||||
|             status.SetError(errorsString); | ||||
|         } | ||||
|  | ||||
|         status.SetMessage("Wait..."); | ||||
|  | ||||
|         var request = Mapper.Map<VisaApplicationCreateRequest>(requestModel); | ||||
|         try | ||||
|         { | ||||
|             await Client.CreateApplicationAsync(request); | ||||
|             status.SetSuccess("Application created successfully."); | ||||
|         } | ||||
|         catch (ApiException<ProblemDetails> e) | ||||
|         { | ||||
|             if (e.StatusCode == (int)HttpStatusCode.BadRequest | ||||
|                 && e.Result.AdditionalProperties.TryGetValue("errors", out var errors)) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var errorsList = ((JArray)errors).ToObject<List<string>>(); | ||||
|                     status.SetError(string.Join("<br/>", errorsList!)); | ||||
|                 } | ||||
|                 catch (Exception inner) | ||||
|                 { | ||||
|                     ErrorHandler.Handle(inner); | ||||
|                     status.SetError("Error occured"); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 throw; | ||||
|             } | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private PastVisaModel NewPastVisa() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             ExpirationDate = DateTimeProvider.Now(), | ||||
|             IssueDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private ReentryPermitModel NewReentryPermit() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             ExpirationDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private PermissionToDestCountryModel NewPermissionToDestCountry() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             ExpirationDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private PastVisitModel NewPastVisit() | ||||
|     { | ||||
|         return new() | ||||
|         { | ||||
|             StartDate = DateTimeProvider.Now(), | ||||
|             EndDate = DateTimeProvider.Now() | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     private void AddPastVisa() | ||||
|     { | ||||
|         if (requestModel.PastVisas.Count >= ConfigurationConstraints.MaxPastVisas) | ||||
|         { | ||||
|             pastVisaStatus.SetError($"{ConfigurationConstraints.MaxPastVisas} past visas is maximum"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var validationResult = PastVisaModelValidator.Validate(editableVisa); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             pastVisaStatus.SetError(validationResult.ToErrorsString()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         requestModel.PastVisas.Add(editableVisa); | ||||
|         editableVisa = NewPastVisa(); | ||||
|         pastVisaStatus.SetSuccess("Added successfully"); | ||||
|     } | ||||
|  | ||||
|     private void RemovePastVisa(PastVisaModel visa) | ||||
|     { | ||||
|         requestModel.PastVisas.Remove(visa); | ||||
|     } | ||||
|  | ||||
|     private void AddPastVisit() | ||||
|     { | ||||
|         if (requestModel.PastVisits.Count >= ConfigurationConstraints.MaxPastVisits) | ||||
|         { | ||||
|             pastVisitStatus.SetError($"{ConfigurationConstraints.MaxPastVisits} past visits is maximum"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var validationResult = PastVisitModelValidator.Validate(editableVisit); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             pastVisitStatus.SetError(validationResult.ToErrorsString()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         requestModel.PastVisits.Add(editableVisit); | ||||
|         editableVisit = NewPastVisit(); | ||||
|         pastVisitStatus.SetSuccess("Added successfully"); | ||||
|     } | ||||
|  | ||||
|     private void RemovePastVisit(PastVisitModel visit) | ||||
|     { | ||||
|         requestModel.PastVisits.Remove(visit); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										192
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Register.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								BlazorWebAssemblyVisaApiClient/Pages/Register.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| @page "/register" | ||||
| @using System.Net | ||||
| @using AutoMapper | ||||
| @using BlazorWebAssemblyVisaApiClient.Components | ||||
| @using BlazorWebAssemblyVisaApiClient.Components.FormComponents | ||||
| @using BlazorWebAssemblyVisaApiClient.Components.FormComponents.Applicants | ||||
| @using BlazorWebAssemblyVisaApiClient.Infrastructure.Helpers | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation | ||||
| @using BlazorWebAssemblyVisaApiClient.Validation.Applicants.Models | ||||
| @using FluentValidation | ||||
| @using Newtonsoft.Json | ||||
| @using Newtonsoft.Json.Linq | ||||
| @using VisaApiClient | ||||
| @inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase | ||||
|  | ||||
| <PageTitle>Registration</PageTitle> | ||||
|  | ||||
| <div class="horizontal-centered-content"> | ||||
|     <h3>Registration data</h3> | ||||
|     <EditForm class="form" Model="requestModel" OnValidSubmit="TryRegisterApplicant"> | ||||
|         <ObjectGraphDataAnnotationsValidator/> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Authentication data@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <AuthDataInput AuthData="requestModel.RegisterRequest.AuthData"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Your Fullname</h5> | ||||
|             <NameInput Name="requestModel.ApplicantName"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Fullname of your mother</h5> | ||||
|             <NameInput Name="requestModel.MotherName"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Fullname of your father</h5> | ||||
|             <NameInput Name="requestModel.FatherName"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Your passport@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <PassportInput Passport="requestModel.Passport"/> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Birth data@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Country of birth:<br/> | ||||
|                     <InputText DisplayName="Country of birth" class="rounded" @bind-Value="requestModel.CountryOfBirth"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.CountryOfBirth"></ValidationMessage><br/> | ||||
|                 <label> | ||||
|                     City of birth:<br/> | ||||
|                     <InputText DisplayName="City of birth" class="rounded" @bind-Value="requestModel.CityOfBirth"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.CityOfBirth"></ValidationMessage><br/> | ||||
|                 <label> | ||||
|                     Birth date:<br/> | ||||
|                     <InputDate DisplayName="Birth date" class="rounded" @bind-Value="requestModel.BirthDate" max="@formattedMaxBirthdayDate"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.BirthDate"></ValidationMessage> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Citizenship@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Citizenship:<br/> | ||||
|                     <InputText class="rounded" @bind-Value="requestModel.Citizenship"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.Citizenship"></ValidationMessage><br/> | ||||
|                 <label> | ||||
|                     Citizenship by birth:<br/> | ||||
|                     <InputText DisplayName="Citizenship by birth" class="rounded" @bind-Value="requestModel.CitizenshipByBirth"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.CitizenshipByBirth"></ValidationMessage> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Address of your place of work@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <AddressInput Address="requestModel.PlaceOfWork.Address"/> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Place of work data@(Constants.RequiredFieldMarkup)</h5> | ||||
|             <div > | ||||
|                 <PlaceOfWorkInput PlaceOfWork="requestModel.PlaceOfWork"/><br/> | ||||
|  | ||||
|                 <label> | ||||
|                     Job title:<br/> | ||||
|                     <InputText DisplayName="Job title" class="rounded" @bind-Value="requestModel.JobTitle"/> | ||||
|                 </label><br/> | ||||
|                 <ValidationMessage For="() => requestModel.JobTitle"></ValidationMessage> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="form-block"> | ||||
|             <h5>Other</h5> | ||||
|  | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Gender: <EnumInputList Model="requestModel" EnumProperty="r => r.Gender"/> | ||||
|                 </label> | ||||
|             </div><br/> | ||||
|  | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Marital status: <EnumInputList Model="requestModel" EnumProperty="r => r.MaritalStatus"/> | ||||
|                 </label> | ||||
|             </div><br/> | ||||
|  | ||||
|             <div > | ||||
|                 <label> | ||||
|                     Non-resident: <InputCheckbox @bind-Value="requestModel.IsNonResident"/> | ||||
|                 </label> | ||||
|             </div> | ||||
|         </div><br/> | ||||
|  | ||||
|         <input type="submit" class="btn-outline-primary" value="Register"/> | ||||
|         <Status @ref="status"/> | ||||
|     </EditForm> | ||||
| </div> | ||||
|  | ||||
| @code | ||||
| { | ||||
|     private RegisterApplicantRequestModel requestModel = new(); | ||||
|     private Status status = null!; | ||||
|     private string formattedMaxBirthdayDate = null!; | ||||
|  | ||||
|     [Inject] IValidator<RegisterApplicantRequestModel> RegisterApplicantRequestValidator { get; set; } = null!; | ||||
|  | ||||
|     [Inject] IMapper Mapper { get; set; } = null!; | ||||
|  | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         requestModel.BirthDate = DateTime.Now.AddYears(-ConfigurationConstraints.ApplicantMinAge); | ||||
|         formattedMaxBirthdayDate = requestModel.BirthDate.ToString("yyyy-MM-dd"); | ||||
|     } | ||||
|  | ||||
|     private async void TryRegisterApplicant() | ||||
|     { | ||||
|         var validationResult = await RegisterApplicantRequestValidator.ValidateAsync(requestModel); | ||||
|         if (!validationResult.IsValid) | ||||
|         { | ||||
|             var errorsString = validationResult.ToErrorsString(); | ||||
|             status.SetError(errorsString); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         status.SetMessage("Wait..."); | ||||
|  | ||||
|         var request = Mapper.Map<RegisterApplicantRequest>(requestModel); | ||||
|         try | ||||
|         { | ||||
|             await Client.RegisterAsync(request); | ||||
|             status.SetSuccess("Register successful. Now log in."); | ||||
|         } | ||||
|         catch (ApiException<ProblemDetails> e) | ||||
|         { | ||||
|             if (e.StatusCode == (int)HttpStatusCode.BadRequest | ||||
|                 && e.Result.AdditionalProperties.TryGetValue("errors", out var errors)) | ||||
|             { | ||||
|                 var errorsList = ((JArray)errors).ToObject<List<string>>(); | ||||
|                 if (errorsList is null) | ||||
|                 { | ||||
|                     ErrorHandler.Handle(new JsonException("Can't convert validation errors to list")); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 status.SetError(string.Join("<br/>", errorsList)); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 throw; | ||||
|             } | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             status.SetError("Error occured"); | ||||
|             ErrorHandler.Handle(e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user