UI, landingPage, login, register, reset password, dashboard page

This commit is contained in:
ElenitaMLG
2024-04-08 03:46:05 +03:00
parent b4eca98e0a
commit 9334fa50cb
20 changed files with 468 additions and 41 deletions
@@ -1,6 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthcareManagerUI", "HealthcareManagerUI\HealthcareManagerUI.csproj", "{641DCB44-0CC9-43D0-AE58-5A722261F1E1}"
# Visual Studio Version 17
VisualStudioVersion = 17.9.34616.47
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthcareManagerUI", "HealthcareManagerUI\HealthcareManagerUI.csproj", "{641DCB44-0CC9-43D0-AE58-5A722261F1E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,4 +16,10 @@ Global
{641DCB44-0CC9-43D0-AE58-5A722261F1E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{641DCB44-0CC9-43D0-AE58-5A722261F1E1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55598450-70ED-4D22-913B-0C99AB8F3F7D}
EndGlobalSection
EndGlobal
@@ -5,7 +5,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="AuthLayout.css"/>
<link rel="stylesheet" href="/AuthLayout.css"/>
</head>
<body>
<div class="background"></div>
@@ -0,0 +1,12 @@
@if (!string.IsNullOrEmpty(ErrorMessage))
{
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Error:</strong> @ErrorMessage
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
}
@code {
[Parameter]
public string ErrorMessage { get; set; }
}
@@ -0,0 +1,15 @@
@page "/"
@using HealthcareManagerUI.Components.Layout
@layout AuthLayout
<head>
<title>Choose Role</title>
</head>
<link rel="stylesheet" href="bootstrap/dist/css/bootstrap.min.css"/>
<div class="text-center mt-5 centered-menu">
<h1 class="landingTitle">Welcome to Healthcare Manager</h1>
<p class="landingSubtitle">Please select your role:</p>
<div class="button-container">
<NavLink class="btn btn-primary m-2" href="/login/doctor">I'm a Doctor</NavLink>
<NavLink class="btn btn-secondary m-2" href="/login/patient">I'm a Patient</NavLink>
</div>
</div>
@@ -0,0 +1,9 @@
@page "/dashboard"
<head>
<title>Dashboard</title>
</head>
<h3>Dashboard</h3>
<h1>login success</h1>
@code {
}
@@ -1,54 +1,77 @@
@page "/"
@page "/login/{role}"
@using HealthcareManagerUI.Models
@using HealthcareManagerUI.Services.Authentication
@using HealthcareManagerUI.Components.Layout
@layout AuthLayout
@inject AuthenticationService AuthenticationService
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
<head>
<title>Login</title>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<link rel="stylesheet" href="bootstrap/dist/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/LoginPage.css" />
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css" />
<EditForm Model="@userLoginModel" OnValidSubmit="@HandleLogin" class="container mt-5">
<EditForm Model="userLoginModel" OnValidSubmit="@HandleLogin" FormName="LoginForm" class="login-form container mt-5">
<DataAnnotationsValidator/>
<ValidationSummary/>
<div class="card shadow-lg">
<div class="card-body">
<h3 class="card-title text-center mb-3">Login</h3>
<div class="mb-3">
<InputText id="email" class="form-control" type="email" placeholder="Email" @bind-Value="@userLoginModel.Email"/>
<div class="form-group mb-3">
<InputText id="email" class="form-control" placeholder="Email" @bind-Value="userLoginModel!.Email"></InputText>
</div>
<div class="mb-3">
<InputText id="password" class="form-control" type="password" placeholder="Password" @bind-Value="@userLoginModel.Password"/>
<div class="form-group mb-3">
<InputText id="password" class="form-control" type="password" placeholder="Password" @bind-Value="userLoginModel!.Password"></InputText>
</div>
<button type="submit" class="btn btn-primary w-100 mb-3">Log In</button>
<button type="button" class="btn btn-secondary w-100" @onclick="HandleSignUp">Sign Up</button>
<div class="button-container">
<NavLink class="btn btn-secondary m-2" href="@($"/register/{Role}")">Register</NavLink>
<NavLink class="btn btn-secondary m-2" href="@($"/reset-password/{Role}")">Reset Password</NavLink>
</div>
</div>
</div>
</EditForm>
<AlertMessage ErrorMessage="@errorMessage" />
@code {
private UserLoginModel userLoginModel = new UserLoginModel();
[SupplyParameterFromForm]
public UserLoginModel? userLoginModel { get; set; }
protected override void OnInitialized()
{
userLoginModel ??= new();
}
[Parameter] public string Role { get; set; }
private string errorMessage { get; set; }
private void ClearErrorMessage()
{
errorMessage = string.Empty;
}
private async Task HandleLogin()
{
var result = await AuthenticationService.Login(userLoginModel);
if (result)
var response = Role switch
{
// Handle the successful login, e.g., navigate to another page
"doctor" => await AuthenticationService.LoginDoctor(userLoginModel),
"patient" => await AuthenticationService.LoginPatient(userLoginModel),
_ => null
};
if (response.StatusCode >= 200 && response.StatusCode <= 399)
{
NavigationManager.NavigateTo("/dashboard");
}
else
{
// Handle the failed login, e.g., show an error message
errorMessage = response.Message;
}
}
private void HandleSignUp()
{
// Logic for handling sign up
}
}
@@ -0,0 +1,84 @@
@page "/register/{role}"
@using HealthcareManagerUI.Models
@using HealthcareManagerUI.Services.Authentication
@using HealthcareManagerUI.Components.Layout
@layout AuthLayout
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
<head>
<title>Register</title>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<link rel="stylesheet" href="/LoginPage.css" />
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css" />
<EditForm Model="userRegisterModel" OnValidSubmit="@HandleRegister" FormName="RegisterForm" class="login-form container mt-5">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="card shadow-lg">
<div class="card-body">
<h3 class="card-title text-center mb-3">Register</h3>
<div class="form-group mb-3">
<InputText id="name" class="form-control" placeholder="Name" @bind-Value="userRegisterModel!.Name"></InputText>
</div>
@if (Role.Equals("doctor", StringComparison.OrdinalIgnoreCase))
{
<div class="form-group mb-3">
<InputText id="description" class="form-control" placeholder="Description" @bind-Value="userRegisterModel!.Description"></InputText>
</div>
}
<div class="form-group mb-3">
<InputText id="email" class="form-control" placeholder="Email" @bind-Value="userRegisterModel!.Email"></InputText>
</div>
<div class="form-group mb-3">
<InputText id="password" class="form-control" type="password" placeholder="Password" @bind-Value="userRegisterModel!.Password"></InputText>
</div>
<div class="button-container">
<button type="submit" class="btn btn-primary w-100 mb-3">Register</button>
</div>
</div>
</div>
</EditForm>
<AlertMessage ErrorMessage="@errorMessage" />
@code {
[SupplyParameterFromForm]
public UserRegisterModel? userRegisterModel { get; set; }
protected override void OnInitialized()
{
userRegisterModel ??= new();
}
[Parameter] public string Role { get; set; }
private string errorMessage { get; set; }
private void ClearErrorMessage()
{
errorMessage = string.Empty;
}
private async Task HandleRegister()
{
var response = Role switch
{
"doctor" => await AuthenticationService.RegisterDoctor(userRegisterModel),
"patient" => await AuthenticationService.RegisterPatient(userRegisterModel),
_ => null
};
if (response.StatusCode >=200 && response.StatusCode <= 399)
{
NavigationManager.NavigateTo($"/login/{Role}");
}
else
{
errorMessage = response.Message;
}
}
}
@@ -0,0 +1,75 @@
@page "/reset-password/{role}"
@using HealthcareManagerUI.Models
@using HealthcareManagerUI.Services.Authentication
@using HealthcareManagerUI.Components.Layout
@layout AuthLayout
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
<head>
<title>Reset your password</title>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<link rel="stylesheet" href="/LoginPage.css" />
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css" />
<EditForm Model="userResetPasswordModel" OnValidSubmit="@HandleResetPassword" FormName="ResetPasswordForm" class="login-form container mt-5">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="card shadow-lg">
<div class="card-body">
<h3 class="card-title text-center mb-3">Register</h3>
<div class="form-group mb-3">
<InputText id="email" class="form-control" placeholder="Email" @bind-Value="userResetPasswordModel!.Email"></InputText>
</div>
<div class="form-group mb-3">
<InputText id="password" class="form-control" type="password" placeholder="New Password" @bind-Value="userResetPasswordModel!.Password"></InputText>
</div>
<div class="button-container">
<button type="submit" class="btn btn-primary w-100 mb-3">Reset Password</button>
</div>
</div>
</div>
</EditForm>
<AlertMessage ErrorMessage="@errorMessage" />
@code {
[SupplyParameterFromForm]
public UserRegisterModel? userResetPasswordModel { get; set; }
protected override void OnInitialized()
{
userResetPasswordModel ??= new();
}
[Parameter] public string Role { get; set; }
private string errorMessage { get; set; }
private void ClearErrorMessage()
{
errorMessage = string.Empty;
}
private async Task HandleResetPassword()
{
var response = Role switch
{
"doctor" => await AuthenticationService.ResetDoctorPassword(userResetPasswordModel),
"patient" => await AuthenticationService.ResetPatientPassword(userResetPasswordModel),
_ => null
};
if (response.StatusCode >= 200 && response.StatusCode <= 399)
{
NavigationManager.NavigateTo($"/login/{Role}");
}
else
{
errorMessage = response.Message;
}
}
}
@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css"/>
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css.map"/>
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css" />
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css.map" />
</ItemGroup>
</Project>
@@ -0,0 +1,10 @@
namespace HealthcareManagerUI.Models
{
public class BaseResponse
{
public int StatusCode { get; set; }
public string? Message { get; set; }
public object? Data { get; set; }
}
}
@@ -0,0 +1,8 @@
namespace HealthcareManagerUI.Models;
public class PatientRegisterModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
@@ -0,0 +1,9 @@
namespace HealthcareManagerUI.Models;
public class UserRegisterModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Description { get; set; }
}
@@ -1,5 +1,6 @@
using HealthcareManagerUI.Components;
using HealthcareManagerUI.Services.Authentication;
using HealthcareManagerUI.Services.Http;
var builder = WebApplication.CreateBuilder(args);
@@ -7,7 +8,12 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddTransient<AuthenticationService, AuthenticationService>();
builder.Services.AddScoped<IHttpService>(provider =>
{
var configuration = provider.GetRequiredService<IConfiguration>();
return new HttpService(configuration);
});
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
var app = builder.Build();
@@ -22,7 +28,6 @@ app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
@@ -2,17 +2,128 @@
using HealthcareManagerUI.Services.Http;
namespace HealthcareManagerUI.Services.Authentication;
// In AuthenticationService.cs
public class AuthenticationService : IAuthenticationService
{
public async Task<bool> Register(UserLoginModel userLoginModel)
private readonly IHttpService _httpService;
private readonly string _apiUrl = "http://localhost:5151/api";
public AuthenticationService(IHttpService httpService)
{
var requestHandler = new HttpService();
await requestHandler.PostAsync<>()
return true;
_httpService = httpService;
}
public async Task<bool> Login(UserLoginModel userLoginModel)
public async Task<BaseResponse> LoginDoctor(UserLoginModel userLoginModel)
{
return true;
try
{
var response = await _httpService.PostAsync<BaseResponse>($"{_apiUrl}/Doctors/login", userLoginModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = 400,
Data = null,
Message = ex.Message
};
}
}
}
public async Task<BaseResponse> LoginPatient(UserLoginModel userLoginModel)
{
try
{
var response = await _httpService.PostAsync<BaseResponse>($"{_apiUrl}/Patients/login", userLoginModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse {
StatusCode = 400,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> RegisterDoctor(UserRegisterModel userRegistrationModel)
{
try
{
var response = await _httpService.PostAsync<BaseResponse>($"{_apiUrl}/Doctors/register", userRegistrationModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = 400,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> RegisterPatient(UserRegisterModel userRegisterModel)
{
var patientRegisterDto = new PatientRegisterModel
{
Name = userRegisterModel.Name,
Email = userRegisterModel.Email,
Password = userRegisterModel.Password
};
try
{
var response = await _httpService.PostAsync<BaseResponse>($"{_apiUrl}/Patients/register", userRegisterModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = 400,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> ResetDoctorPassword(UserRegisterModel userResetPasswordModel)
{
try
{
var response = await _httpService.PostAsync<BaseResponse>($"{_apiUrl}/Doctors/reset_password", userResetPasswordModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = 400,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> ResetPatientPassword(UserRegisterModel userResetPasswordModel)
{
try
{
var response = await _httpService.PostAsync<BaseResponse>($"{_apiUrl}/Patients/reset_password", userResetPasswordModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = 400,
Data = null,
Message = ex.Message
};
}
}
}
@@ -4,6 +4,15 @@ namespace HealthcareManagerUI.Services.Authentication;
public interface IAuthenticationService
{
Task<bool> Register(UserLoginModel userLoginModel);
Task<bool> Login(UserLoginModel userLoginModel);
Task<BaseResponse> LoginDoctor(UserLoginModel userLoginModel);
Task<BaseResponse> LoginPatient(UserLoginModel userLoginModel);
Task<BaseResponse> RegisterDoctor(UserRegisterModel userRegistrationModel);
Task<BaseResponse> RegisterPatient(UserRegisterModel userRegistrationModel);
Task<BaseResponse> ResetDoctorPassword(UserRegisterModel userResetPasswordModel);
Task<BaseResponse> ResetPatientPassword(UserRegisterModel userResetPasswordModel);
}
@@ -5,6 +5,13 @@ namespace HealthcareManagerUI.Services.Http;
public class HttpService : IHttpService
{
private readonly string _apiKey;
public HttpService(IConfiguration configuration)
{
_apiKey = configuration.GetValue<string>("ApiKey") ?? "NoKey";
}
public async Task<T> GetAsync<T>(string uri, IDictionary<string, string> headers = null)
{
using var httpClient = new HttpClient();
@@ -12,7 +19,6 @@ public class HttpService : IHttpService
AddHeaders(request, headers);
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(
@@ -32,7 +38,6 @@ public class HttpService : IHttpService
request.Content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(
@@ -47,7 +52,6 @@ public class HttpService : IHttpService
request.Content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(
@@ -61,13 +65,19 @@ public class HttpService : IHttpService
AddHeaders(request, headers);
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
}
private void AddHeaders(HttpRequestMessage request, IDictionary<string, string> headers)
{
// Add the API key header to every request
request.Headers.Add("ApiKey", _apiKey);
if (headers != null)
{
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
}
}
}
@@ -5,5 +5,6 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"ApiKey": "testapikey"
}
@@ -29,5 +29,43 @@ body {
}
.container {
z-index: 1; /* Above the background */
z-index: 1;
}
/* New styles for title and subtitle */
.landingTitle {
color: #ffffff;
text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.7);
font-size: 3.5rem;
font-weight: bold;
background: rgba(255, 255, 255, 0.2);
padding: 0.5rem;
border-radius: 0.5rem;
display: inline-block; /* Wrap the background to the text */
margin-top: 2rem; /* Give some space from the top */
}
.landingSubtitle {
color: #dcdcdc;
text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.5);
font-size: 2rem;
padding: 0.25rem;
border-radius: 0.5rem;
display: block; /* Wrap the background to the text */
margin-bottom: 2rem; /* Give some space before the buttons */
}
.centered-menu {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
text-align: center;
}
.button-container {
display: flex;
flex-direction: row; /* This will align the buttons side by side */
justify-content: center; /* Center the buttons within the container */
}
@@ -61,7 +61,6 @@ input {
width: 70%;
padding: 1rem;
margin: 0.7rem;
background-color: #1B1A55;
border-radius: 10px;
}