finalizare 1.0

This commit is contained in:
andrei-mihnea-cerbu
2024-05-21 12:10:53 +03:00
parent f7795f7519
commit 1cc1d34003
11268 changed files with 2102399 additions and 10909 deletions
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="HealthcareManager@90.84.229.219" uuid="1483d760-7f0d-4e68-8949-b3bef04f73e7">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<configured-by-url>true</configured-by-url>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://90.84.229.219:5432/HealthcareManager?password=postgres&amp;user=andrei_cerbu</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{bootstrap}" />
</component>
</project>
+35 -12
View File
@@ -1,12 +1,35 @@
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(AuthLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(AuthLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<CascadingAuthenticationState>
<RoleBasedRedirect/>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<Authorizing>
<p>Loading...</p>
</Authorizing>
<NotAuthorized>
<NotAuthorizedHandler/>
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound >
<LayoutView Layout="@typeof(MainLayout)">
<PageNotFoundHandler/>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
@code {
private class RedirectToLogin : ComponentBase
{
[Inject] private NavigationManager Navigation { get; set; }
protected override void OnInitialized()
{
Navigation.NavigateTo("/login");
}
}
}
+11 -2
View File
@@ -2,6 +2,15 @@
public class ApplicationSettings
{
public string ApiKey { get; set; }
public string ApiEndpoint { get; set; }
public string ApiKey { get; set; } = string.Empty;
public JwtSettings Jwt { get; set; }
public string BaseAddress { get; set; } = string.Empty;
}
public class JwtSettings
{
public string SecretKey { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public int ExpirationTime { get; set; } = 0;
}
@@ -0,0 +1,22 @@
using System.Net.Http.Headers;
using Blazored.LocalStorage;
namespace HealthcareManagerUiWebAssem;
public class AuthenticationHttpMessageHandler(ILocalStorageService localStorageService, ApplicationSettings apiSettings)
: DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Add API key to request headers
request.Headers.Add("ApiKey", apiSettings.ApiKey);
// Retrieve JWT token from local storage
var token = await localStorageService.GetItemAsync<string>("authToken", cancellationToken);
if (!string.IsNullOrEmpty(token))
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
return await base.SendAsync(request, cancellationToken);
}
}
+40
View File
@@ -0,0 +1,40 @@
@namespace HealthcareManagerUiWebAssem.Components
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">MyApp</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/admin/dashboard">Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/users">Users</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/settings">Settings</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<button class="nav-link btn btn-link" @onclick="Logout">Logout</button>
</li>
</ul>
</div>
</nav>
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
@code {
private async Task Logout()
{
await AuthenticationService.Logout();
// Redirect the user to the login page or somewhere relevant
NavigationManager.NavigateTo("/login", true);
}
}
+18
View File
@@ -0,0 +1,18 @@
@namespace HealthcareManagerUiWebAssem.Components
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">MyApp</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/login">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/reset-password">Reset Password</a>
</li>
</ul>
</div>
</nav>
+45
View File
@@ -0,0 +1,45 @@
@namespace HealthcareManagerUiWebAssem.Components
<div class="sidebar">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">MyApp</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/doctor/dashboard">Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/doctor/profile">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/doctor/patients_medical_history">Patients' Medical History</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/doctor/ai">Sickness Software</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/doctor/chat">Chat</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<button class="nav-link btn btn-link" @onclick="Logout">Logout</button>
</li>
</ul>
</div>
</nav>
</div>
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
@code {
private async Task Logout()
{
await AuthenticationService.Logout();
// Redirect the user to the login page or somewhere relevant
NavigationManager.NavigateTo("/login", true);
}
}
@@ -1,18 +0,0 @@
@inherits LayoutComponentBase
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/AuthLayout.css"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="background"></div>
<div class="container">
@Body
</div>
</body>
</html>
@@ -1,11 +0,0 @@
@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; }
}
@@ -1,15 +0,0 @@
@page "/"
@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>
@@ -1,44 +0,0 @@
@page "/dashboard/{Role}"
<head>
<title>Dashboard</title>
</head>
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css"/>
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.22.4/dist/bootstrap-table.min.css">
<link href="https://cdn.datatables.net/2.0.4/css/dataTables.bootstrap5.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<style>
.select,
#locale {
width: 100%;
}
.like {
margin-right: 10px;
}
.modal-backdrop.show {
display: none !important;
}
</style>
<NavLink class="btn btn-primary m-2 position-absolute top-0 end-0" href="@($"/my-profile/{Role}")">My Profile</NavLink>
@switch (Role)
{
case "doctor":
<DoctorDashboard/>
break;
case "patient":
<PatientDashboard/>
break;
default:
<p>Unknown role. Please contact support.</p>
break;
}
@code {
[Parameter] public string Role { get; set; }
}
@@ -1,155 +0,0 @@
@using System.Text.Json
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Services.Profile
@using HealthcareManagerUiWebAssem.Services.Appointment
@using HealthcareManagerUiWebAssem.Services.User
@inject UserService UserService
@inject IProfileService ProfileService
@inject IAppointmentService AppointmentService
@inject IJSRuntime JS
<div class="container mt-3">
<h2 class="landingTitle">Doctor Menu</h2>
<p class="landingSubtitle">Here you can manage appointments, review your patients' medical history and chat with your patients.</p>
<div id="accordion">
<div class="card">
<div class="card-header">
<a class="btn" data-bs-toggle="collapse" href="#collapseOne">
Appointments
</a>
</div>
<div id="collapseOne" class="collapse show" data-bs-parent="#accordion">
<div class="card-body">
<table class="table">
<thead>
<tr>
<th>Patient Name</th>
<th>Appointment Time</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
@foreach (var appointment in appointments)
{
@foreach (var date in appointment.AppointmentsList)
{
<tr>
<td>@GetPatientName(new Guid(appointment.PatientId))</td>
<td>@date.ToString("yyyy-MM-dd HH:mm")</td>
<td><button class="btn btn-danger" @onclick="(() => DeleteAppointment(appointment))">Delete</button></td>
</tr>
}
}
</tbody>
</table>
<AppointmentTableComponent appointments="appointments" OnAppointmentDeleted="HandleAppointmentDeleted" />
</div>
</div>
</div>
<!-- ... other patient-specific cards ... -->
</div>
</div>
@code {
private List<Patient> patients;
private string selectedDoctorId;
private DateTime? selectedDate;
private List<Appointment> appointments;
private List<byte[]> medicalHistoryFiles;
[Parameter] public string Role { get; set; }
protected override async Task OnInitializedAsync()
{
await InitializePatients();
await LoadAppointments();
}
private async Task LoadAppointments()
{
var response = await AppointmentService.GetAppointmentsByDoctor(UserService.UserId);
var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
if (response.StatusCode == HttpStatusCodes.OK)
{
appointments = JsonSerializer.Deserialize<List<Appointment>>(response.Data, jsonOptions) ?? new List<Appointment>();
}
else
{
appointments = new List<Appointment>();
}
}
private async Task InitializePatients()
{
var response = await ProfileService.GetPatients();
var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
if (response.StatusCode == HttpStatusCodes.OK)
{
patients = JsonSerializer.Deserialize<List<Patient>>(response.Data, jsonOptions);
}
else
{
// Handle error
}
}
private void AddMedicalHistoryFile()
{
// Logic for adding a new appointment
}
private async Task DeleteAppointment(Appointment appointmentToDelete)
{
var appointmentModelToDelete = new AppointmentManagementModel
{
PatientId = new Guid(appointmentToDelete.PatientId),
DoctorId = new Guid(appointmentToDelete.DoctorId),
Appointment = appointmentToDelete.AppointmentsList.FirstOrDefault()
};
await AppointmentService.DeleteAppointment(appointmentModelToDelete);
appointments.Remove(appointmentToDelete);
}
private string GetPatientName(Guid patientId)
{
var patient = patients.Select(d => d).FirstOrDefault(d => d.Id == patientId);
return patient?.Name ?? string.Empty;
}
}
-113
View File
@@ -1,113 +0,0 @@
@page "/login/{role}"
@using System.Text.Json
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Services.Authentication
@using HealthcareManagerUiWebAssem.Services.User
@using HealthcareManagerUiWebAssem.Services.UserSessionInformation
@layout AuthLayout
@inject IAuthenticationService AuthenticationService
@inject IUserSessionInformation UserSessionInformation;
@inject NavigationManager NavigationManager
@inject UserService UserService
<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="/LoginPage.css"/>
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css"/>
<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="form-group mb-3">
<InputText id="email" class="form-control" placeholder="Email" @bind-Value="userLoginModel!.Email"></InputText>
</div>
<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>
<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 {
[SupplyParameterFromForm] public UserLoginModel? userLoginModel { get; set; }
private BaseResponse? loginResponse;
protected override void OnInitialized()
{
userLoginModel ??= new UserLoginModel();
}
[Parameter]
public string Role { get; set; }
private string errorMessage { get; set; }
private bool loginSuccesful { get; set; }
private void ClearErrorMessage()
{
errorMessage = string.Empty;
}
private async Task HandleLogin()
{
userLoginModel.UserType = Role;
loginResponse = await AuthenticationService.Login(userLoginModel); // Store response instead of immediately processing
if (loginResponse.StatusCode < 200 || loginResponse.StatusCode > 299)
{
errorMessage = loginResponse?.Message ?? "An error occurred."; // Handle error states immediately if required
}
else
{
var userId = Guid.Empty;
var authToken = "";
Console.WriteLine("Printing headers");
foreach (var (key, value) in loginResponse.Headers)
{
Console.WriteLine($"{key} => {value}");
}
if (loginResponse.Headers.TryGetValue("Authorization", out var token))
{
authToken = token;
}
if (Role.Equals("doctor", StringComparison.OrdinalIgnoreCase))
{
var doctor = JsonSerializer.Deserialize<Doctor>(
loginResponse.Data,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
await UserSessionInformation.SaveUserInformationAsync(doctor.Id, Role, doctor.Email, doctor.Name, authToken);
userId = doctor.Id;
}
else if (Role.Equals("patient", StringComparison.OrdinalIgnoreCase))
{
var patient = JsonSerializer.Deserialize<Patient>(
loginResponse.Data,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
await UserSessionInformation.SaveUserInformationAsync(patient.Id, Role, patient.Email, patient.Name, authToken);
userId = patient.Id;
}
loginResponse = null;
UserService.SetUserId(userId);
NavigationManager.NavigateTo($"/dashboard/{Role}");
}
}
}
@@ -1,123 +0,0 @@
@page "/my-profile/{Role}"
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Services.Authentication
@using HealthcareManagerUiWebAssem.Services.Profile
@using HealthcareManagerUiWebAssem.Services.User
@using HealthcareManagerUiWebAssem.Services.UserSessionInformation
@layout AuthLayout
@inject IUserSessionInformation UserSessionInformation;
@inject IAuthenticationService AuthenticationService;
@inject IProfileService ProfileService
@inject UserService UserService
@inject NavigationManager NavigationManager
<head>
<title>My Profile</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"/>
<h3>My Profile</h3>
@if (profile != null)
{
<EditForm Model="profile" OnValidSubmit="@HandleUpdateProfile" FormName="UpdateProfileForm" class="login-form container mt-5">
<DataAnnotationsValidator/>
<ValidationSummary/>
<div class="card shadow-lg">
<div class="card-body">
<div class="form-group mb-3">
<label for="name">Name:</label>
<InputText id="name" class="form-control" @bind-Value="@profile!.Name"></InputText>
</div>
@if (Role.Equals("doctor", StringComparison.OrdinalIgnoreCase))
{
<div class="form-group mb-3">
<label for="description">Description:</label>
<InputText id="description" class="form-control" @bind-Value="@profile!.Description"></InputText>
</div>
}
<div class="form-group mb-3">
<label for="email">Email:</label>
<InputText id="email" class="form-control" @bind-Value="@profile!.Email"></InputText>
</div>
<div class="form-group mb-3">
<label for="password">Password:</label>
<InputText id="password" class="form-control" type="password" @bind-Value="@profile!.Password"></InputText>
</div>
<button type="submit" class="btn btn-primary">Update</button>
<button type="button" class="btn btn-danger" @onclick="@HandleDeleteProfile">Delete</button>
</div>
</div>
</EditForm>
<AlertMessage ErrorMessage="@errorMessage"/>
}
@code {
[SupplyParameterFromForm] public UserUpdateProfileModel? profile { get; set; }
[Parameter] public string Role { get; set; }
private string errorMessage;
protected override async Task OnInitializedAsync()
{
var tokenDto = new TokenRefreshModel(await UserSessionInformation.GetTokenAsync());
var refreshResult = await AuthenticationService.RefreshToken(tokenDto);
if (refreshResult.StatusCode < HttpStatusCodes.BadRequest)
{
NavigationManager.NavigateTo("/");
}
profile ??= await UserService.InitializeProfile(Role, ProfileService);
var userId = await UserSessionInformation.GetIdAsync();
}
private async Task HandleUpdateProfile()
{
profile.Id = UserService.UserId;
var response = Role switch
{
"doctor" => await ProfileService.UpdateDoctorProfile(profile),
"patient" => await ProfileService.UpdatePatientProfile(profile),
_ => null
};
if (response.StatusCode >= 200 && response.StatusCode <= 299)
{
NavigationManager.NavigateTo($"/my-profile/{Role}");
}
else
{
errorMessage = response?.Message ?? "An error occurred.";
}
}
private async Task HandleDeleteProfile()
{
var response = Role switch
{
"doctor" => await ProfileService.DeleteDoctorProfile(UserService.UserId),
"patient" => await ProfileService.DeletePatientProfile(UserService.UserId),
_ => null
};
if (response.StatusCode >= 200 && response.StatusCode <= 299)
{
NavigationManager.NavigateTo($"/login/{Role}");
}
else
{
errorMessage = response?.Message ?? "An error occurred.";
}
}
}
@@ -1,269 +0,0 @@
@using System.Text.Json
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Services.Profile
@using HealthcareManagerUiWebAssem.Services.Appointment
@using HealthcareManagerUiWebAssem.Services.User
@inject UserService UserService
@inject IProfileService ProfileService
@inject IAppointmentService AppointmentService
@inject IJSRuntime JS
<div class="container mt-3">
<h2 class="landingTitle">Patient Menu</h2>
<p class="landingSubtitle">Here you can manage appointments, review your medical history and chat with doctors.</p>
<div id="accordion">
<div class="card">
<div class="card-header">
<a class="btn" data-bs-toggle="collapse" href="#collapseOne">
Appointments
</a>
</div>
<div id="collapseOne" class="collapse show" data-bs-parent="#accordion">
<div class="card-body">
<button @onclick="ShowAddAppointmentModal" class="btn btn-primary">Add Appointment</button>
<table class="table">
<thead>
<tr>
<th>Doctor Name</th>
<th>Appointment Time</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
@foreach (var appointment in appointments)
{
@foreach (var date in appointment.AppointmentsList)
{
<tr>
<td>@GetDoctorName(new Guid(appointment.DoctorId))</td>
<td>@date.ToString("yyyy-MM-dd HH:mm")</td>
<td><button class="btn btn-danger" @onclick="(() => DeleteAppointment(appointment))">Delete</button></td>
</tr>
}
}
</tbody>
</table>
<AppointmentTableComponent appointments="appointments" OnAppointmentDeleted="HandleAppointmentDeleted" />
</div>
</div>
</div>
<!-- ... other patient-specific cards ... -->
</div>
<div class="modal" id="addAppointmentModal" tabindex="-1" aria-labelledby="addAppointmentModalLabel" data-backdrop="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addAppointmentModalLabel">Add Appointment</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
@if (doctors != null)
{
<select @bind="selectedDoctorId" class="form-select">
<option value="">Select a doctor</option>
@foreach (var doctor in doctors)
{
<option value="@doctor.Id">@doctor.Name</option>
}
</select>
<input type="datetime-local" @bind="selectedDate" class="form-control" />
}
else
{
<p>Loading doctors...</p>
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button @onclick="CreateAppointment" type="button" class="btn btn-primary">Create Appointment</button>
</div>
</div>
</div>
</div>
</div>
@code {
private List<Doctor> doctors;
private string selectedDoctorId;
private DateTime? selectedDate;
private List<Appointment> appointments;
private List<byte[]> medicalHistoryFiles;
[Parameter] public string Role { get; set; }
protected override async Task OnInitializedAsync()
{
await InitializeDoctors();
await LoadAppointments();
}
private async Task LoadAppointments()
{
var response = await AppointmentService.GetAppointmentsByPatient(UserService.UserId);
var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
if (response.StatusCode == HttpStatusCodes.OK)
{
appointments = JsonSerializer.Deserialize<List<Appointment>>(response.Data, jsonOptions) ?? new List<Appointment>();
}
else
{
appointments = new List<Appointment>();
}
}
private async Task ShowAddAppointmentModal()
{
await JS.InvokeVoidAsync("eval", "new bootstrap.Modal(document.getElementById('addAppointmentModal')).show();");
}
private async Task InitializeDoctors()
{
var response = await ProfileService.GetDoctors();
var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
if (response.StatusCode == HttpStatusCodes.OK)
{
doctors = JsonSerializer.Deserialize<List<Doctor>>(response.Data, jsonOptions);
}
else
{
// Handle error
}
}
private async Task CreateAppointment()
{
if (string.IsNullOrEmpty(selectedDoctorId) || !selectedDate.HasValue)
{
// Handle validation
return;
}
// Call AddAppointment method, which is not shown here
var createAppointmentModel = new AppointmentManagementModel
{
PatientId = UserService.UserId,
DoctorId = new Guid(selectedDoctorId),
Appointment = (DateTime)selectedDate
};
await AppointmentService.CreateAppointment(createAppointmentModel);
// You'll need to pass UserService.UserId, selectedDoctorId, and selectedDate.Value to it
// Close the modal after creation
await JS.InvokeVoidAsync("eval", "new bootstrap.Modal(document.getElementById('addAppointmentModal')).hide();");
// Optionally, refresh the appointments list
}
private void AddMedicalHistoryFile()
{
// Logic for adding a new appointment
}
private async Task DeleteAppointment(Appointment appointmentToDelete)
{
var appointmentModelToDelete = new AppointmentManagementModel
{
PatientId = new Guid(appointmentToDelete.PatientId),
DoctorId = new Guid(appointmentToDelete.DoctorId),
Appointment = appointmentToDelete.AppointmentsList.FirstOrDefault()
};
await AppointmentService.DeleteAppointment(appointmentModelToDelete);
appointments.Remove(appointmentToDelete);
}
private string GetDoctorName(Guid doctorId)
{
var doctor = doctors.Select(d => d).FirstOrDefault(d => d.Id == doctorId);
return doctor?.Name ?? string.Empty;
}
}
@@ -1,83 +0,0 @@
@page "/register/{role}"
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Services.Authentication
@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 UserRegisterModel();
}
[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;
}
}
}
@@ -1,70 +0,0 @@
@page "/reset-password/{role}"
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Services.Authentication
@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 UserLoginModel? userResetPasswordModel { get; set; }
protected override void OnInitialized()
{
userResetPasswordModel ??= new UserLoginModel();
}
[Parameter] public string Role { get; set; }
private string errorMessage { get; set; }
private void ClearErrorMessage()
{
errorMessage = string.Empty;
}
private async Task HandleResetPassword()
{
userResetPasswordModel.UserType = Role;
var response = await AuthenticationService.ResetPassword(userResetPasswordModel);
if (response.StatusCode >= 200 && response.StatusCode <= 399)
{
NavigationManager.NavigateTo($"/login/{Role}");
}
else
{
errorMessage = response.Message;
}
}
}
+51
View File
@@ -0,0 +1,51 @@
@namespace HealthcareManagerUiWebAssem.Components
<div class="sidebar">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">MyApp</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/patient/dashboard">Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/patient/doctors">Meet Our Doctors</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/patient/profile">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/patient/appointments">Appointments</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/patient/medical_history">Medical History</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/patient/doctor_access">Doctor Access</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/patient/chat">Chat</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<button class="nav-link btn btn-link" @onclick="Logout">Logout</button>
</li>
</ul>
</div>
</nav>
</div>
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
@code {
private async Task Logout()
{
await AuthenticationService.Logout();
// Redirect the user to the login page or somewhere relevant
NavigationManager.NavigateTo("/login", true);
}
}
@@ -0,0 +1,47 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization;
namespace HealthcareManagerUiWebAssem;
public class CustomAuthenticationStateProvider(ILocalStorageService localStorageService) : AuthenticationStateProvider
{
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var token = await localStorageService.GetItemAsync<string>("authToken");
if (string.IsNullOrEmpty(token))
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
var claims = ParseClaimsFromJwt(token);
var identity = new ClaimsIdentity(claims, "jwt", null, "role");
var user = new ClaimsPrincipal(identity);
return new AuthenticationState(user);
}
public void NotifyUserAuthentication(string token)
{
var claims = ParseClaimsFromJwt(token);
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt", null, "role"));
var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
NotifyAuthenticationStateChanged(authState);
}
public void NotifyUserLogout()
{
var authState = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
NotifyAuthenticationStateChanged(authState);
}
private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
{
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadJwtToken(jwt);
return token.Claims;
}
}
+38
View File
@@ -0,0 +1,38 @@
namespace HealthcareManagerUiWebAssem.Entities;
public class Appointment
{
public string Id { get; set; } = string.Empty;
public string PatientId { get; set; } = string.Empty;
public string DoctorId { get; set; } = string.Empty;
public List<DateTime> AppointmentsList { get; set; } = [];
public void SetId(string id)
{
Id = id;
}
public void SetPatientId(string patientId)
{
PatientId = patientId;
}
public void SetDoctorIid(string doctorId)
{
DoctorId = doctorId;
}
public void AddAppointment(DateTime appointmentDate)
{
var utcAppointmentDate = new DateTime(appointmentDate.Year, appointmentDate.Month, appointmentDate.Day, 0, 0, 0,
DateTimeKind.Utc);
AppointmentsList.Add(utcAppointmentDate);
}
public void RemoveAppointment(DateTime appointmentDate)
{
var utcAppointmentDate = new DateTime(appointmentDate.Year, appointmentDate.Month, appointmentDate.Day, 0, 0, 0,
DateTimeKind.Utc);
AppointmentsList.Remove(utcAppointmentDate);
}
}
+33
View File
@@ -0,0 +1,33 @@
namespace HealthcareManagerUiWebAssem.Entities;
public class Chat
{
public string Id { get; set; } = string.Empty;
public List<Message> Messages { get; set; } = [];
public void SetId(string id)
{
Id = id;
}
public void SetMessages(List<Message> messages)
{
Messages = messages;
}
}
public class Message(Guid userId, string content)
{
public Guid UserId { get; set; } = userId;
public string Content { get; set; } = content;
public void SetUserId(Guid userId)
{
UserId = userId;
}
public void SetContent(string content)
{
Content = content;
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace HealthcareManagerUiWebAssem.Entities;
public class Doctor
{
public Guid Id { get; set; } = Guid.Empty;
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
+25
View File
@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
namespace HealthcareManagerUiWebAssem.Entities;
public class MedicalHistory
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public Guid UserId { get; set; } = Guid.Empty;
public byte[] Content { get; set; } = [];
public void SetId(Guid id)
{
Id = id;
}
public void SetUserId(Guid userId)
{
UserId = userId;
}
public void SetContent(byte[] content)
{
Content = content;
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace HealthcareManagerUiWebAssem.Entities;
public class Patient
{
public Guid Id { get; set; } = Guid.Empty;
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
+8 -7
View File
@@ -7,20 +7,21 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0"/>
<PackageReference Include="itext7" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.5"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.3" PrivateAssets="all"/>
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0-preview.2.24128.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0-preview.2.24128.5"/>
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1"/>
<PackageReference Include="UglyToad.PdfPig" Version="1.7.0-custom-5" />
</ItemGroup>
<ItemGroup>
<Folder Include="Components\" />
<Folder Include="wwwroot\css\Pages\"/>
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Layout\AuthLayout.razor" />
<_ContentIncludedByDefault Remove="Layout\MainLayout.razor" />
<_ContentIncludedByDefault Remove="Layout\NavMenu.razor" />
<_ContentIncludedByDefault Remove="wwwroot\js\DownloadFile.js"/>
</ItemGroup>
</Project>
+9
View File
@@ -0,0 +1,9 @@
@inherits LayoutComponentBase
<link href="css/Layout/AdminLayout.css" rel="stylesheet"/>
<AdminNavbar/>
<div class="page-container mt-5">
<div class="container">
@Body
</div>
</div>
+9
View File
@@ -0,0 +1,9 @@
@inherits LayoutComponentBase
<link href="css/Layout/AuthLayout.css" rel="stylesheet"/>
<AuthNavbar/>
<div class="page-container mt-5">
<div class="container">
@Body
</div>
</div>
+9
View File
@@ -0,0 +1,9 @@
@inherits LayoutComponentBase
<link href="css/Layout/DoctorLayout.css" rel="stylesheet"/>
<DoctorNavBar/>
<div class="page-container mt-5">
<div class="container">
@Body
</div>
</div>
+8
View File
@@ -0,0 +1,8 @@
@inherits LayoutComponentBase
<link href="css/Layout/MainLayout.css" rel="stylesheet"/>
<div class="page-container mt-5">
<div class="container">
@Body
</div>
</div>
+9
View File
@@ -0,0 +1,9 @@
@inherits LayoutComponentBase
<link href="css/Layout/PatientLayout.css" rel="stylesheet"/>
<PatientNavbar/>
<div class="page-container mt-5">
<div class="container">
@Body
</div>
</div>
+8
View File
@@ -0,0 +1,8 @@
namespace HealthcareManagerUiWebAssem.Models;
public class ApiResponse<T>
{
public int StatusCode { get; set; }
public string Message { get; set; } = string.Empty;
public T? Data { get; set; }
}
-9
View File
@@ -1,9 +0,0 @@
namespace HealthcareManagerUiWebAssem.Models;
public class Appointment
{
public string Id { get; set; }
public string PatientId { get; set; }
public string DoctorId { get; set; }
public List<DateTime> AppointmentsList { get; set; } = [];
}
@@ -1,6 +1,6 @@
namespace HealthcareManagerUiWebAssem.Models;
public class AppointmentManagementModel
public class AppointmentCancellationRequest
{
public Guid DoctorId { get; set; }
public Guid PatientId { get; set; }
-9
View File
@@ -1,9 +0,0 @@
namespace HealthcareManagerUiWebAssem.Models;
public class BaseResponse
{
public int StatusCode { get; set; }
public string? Message { get; set; }
public string? Data { get; set; }
public IDictionary<string, string>? Headers { get; set; } // New field to store headers
}
-12
View File
@@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace HealthcareManagerUiWebAssem.Models;
public class Doctor
{
[Key] public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Description { get; set; }
}
+8
View File
@@ -0,0 +1,8 @@
namespace HealthcareManagerUiWebAssem.Models;
public class NewAppointmentModel
{
public Guid DoctorId { get; set; } = Guid.Empty;
public Guid PatientId { get; set; } = Guid.Empty;
public DateTime Appointment { get; set; } = DateTime.Now;
}
-8
View File
@@ -1,8 +0,0 @@
namespace HealthcareManagerUiWebAssem.Models;
public class PatientRegisterModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
-9
View File
@@ -1,9 +0,0 @@
namespace HealthcareManagerUiWebAssem.Models;
public class Patient
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
+7
View File
@@ -0,0 +1,7 @@
namespace HealthcareManagerUiWebAssem.Models;
public class PredictionResult
{
public string Disease { get; set; } = string.Empty;
public double Probability { get; set; }
}
+7
View File
@@ -0,0 +1,7 @@
namespace HealthcareManagerUiWebAssem.Models;
public class ResetPasswordModel
{
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
+8
View File
@@ -0,0 +1,8 @@
namespace HealthcareManagerUiWebAssem.Models;
public class ResetPasswordResponse
{
public int StatusCode { get; set; }
public string Message { get; set; }
public string? Data { get; set; }
}
-11
View File
@@ -1,11 +0,0 @@
namespace HealthcareManagerUiWebAssem.Models;
public class TokenRefreshModel
{
public TokenRefreshModel(string token)
{
Token = token;
}
public string Token { get; private set; }
}
+8
View File
@@ -0,0 +1,8 @@
namespace HealthcareManagerUiWebAssem.Models;
public class UserInformation
{
public string Name { get; set; } = string.Empty;
public Guid Id { get; set; } = Guid.Empty;
public string Role { get; set; } = string.Empty;
}
+5 -4
View File
@@ -1,8 +1,9 @@
namespace HealthcareManagerUiWebAssem.Models;
using System.ComponentModel.DataAnnotations;
namespace HealthcareManagerUiWebAssem.Models;
public class UserLoginModel
{
public string? UserType { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[Required] public string Email { get; set; } = string.Empty;
[Required] public string Password { get; set; } = string.Empty;
}
+7 -6
View File
@@ -1,10 +1,11 @@
namespace HealthcareManagerUiWebAssem.Models;
using System.ComponentModel.DataAnnotations;
namespace HealthcareManagerUiWebAssem.Models;
public class UserRegisterModel
{
public string? UserType { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Description { get; set; }
[Required] public string Name { get; set; } = string.Empty;
[Required] public string Email { get; set; } = string.Empty;
[Required] public string Password { get; set; } = string.Empty;
[Required] public string Role { get; set; } = string.Empty;
}
-10
View File
@@ -1,10 +0,0 @@
namespace HealthcareManagerUiWebAssem.Models;
public class UserUpdateProfileModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Description { get; set; }
}
@@ -0,0 +1,6 @@
@page "/admin/dashboard"
@layout AdminLayout
@attribute [Authorize(Roles = UserRoles.Admin)]
<h3>Admin Dashboard</h3>
<p>Welcome to the doctor dashboard!</p>
+128
View File
@@ -0,0 +1,128 @@
@page "/admin/users"
@using Microsoft.JSInterop
@inject IAdminManagementService AdminManagementService
@inject IJSRuntime JsRuntime
@layout AdminLayout
@attribute [Authorize(Roles = UserRoles.Admin)]
<h3>User Management Page</h3>
@if (_doctors == null || _patients == null)
{
<p>
<em>Loading...</em>
</p>
}
else
{
<div class="row">
<div class="col">
<h4>Doctors</h4>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var doctor in _doctors)
{
<tr>
<td>@doctor.Name</td>
<td>@doctor.Email</td>
<td>
<button class="btn btn-danger" @onclick="() => DeleteDoctor(doctor.Id)">Delete</button>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="col">
<h4>Patients</h4>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var patient in _patients)
{
<tr>
<td>@patient.Name</td>
<td>@patient.Email</td>
<td>
<button class="btn btn-danger" @onclick="() => DeletePatient(patient.Id)">Delete</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
@code {
private List<Doctor> _doctors = [];
private List<Patient> _patients = [];
private string _errorMessage = string.Empty;
protected override async Task OnInitializedAsync()
{
try
{
var doctorsResult = await AdminManagementService.GetDoctors();
var patientsResult = await AdminManagementService.GetPatients();
_doctors = doctorsResult.Data;
_patients = patientsResult.Data;
}
catch (Exception ex)
{
_errorMessage = $"Error loading data: {ex.Message}";
}
}
private async Task DeleteDoctor(Guid id)
{
var confirmed = await JsRuntime.InvokeAsync<bool>("confirm", $"Are you sure you want to delete this doctor?");
if (confirmed)
{
var success = await AdminManagementService.DeleteDoctor(id);
if (success)
{
var doctorsResult = await AdminManagementService.GetDoctors();
_doctors = doctorsResult.Data;
}
else
{
_errorMessage = "Error deleting doctor.";
}
}
}
private async Task DeletePatient(Guid id)
{
var confirmed = await JsRuntime.InvokeAsync<bool>("confirm", $"Are you sure you want to delete this patient?");
if (confirmed)
{
var success = await AdminManagementService.DeletePatient(id);
if (success)
{
var patientsResult = await AdminManagementService.GetPatients();
_patients = patientsResult.Data;
}
else
{
_errorMessage = "Error deleting patient.";
}
}
}
}
@@ -0,0 +1,21 @@
@page "/goodbye"
@layout AuthLayout
@inject NavigationManager NavigationManager
<h3>Goodbye</h3>
<div class="card mt-4">
<div class="card-body">
<p>Thank you for using our service. We're sorry to see you go.</p>
<button class="btn btn-primary" @onclick="RedirectToHome">Go to Home Page</button>
</div>
</div>
@code {
private void RedirectToHome()
{
NavigationManager.NavigateTo("/");
}
}
+13
View File
@@ -0,0 +1,13 @@
@page "/"
@layout AuthLayout
<h1>Welcome to HealthcareManagerApp</h1>
<p>Your Health, Our Priority.</p>
<p>At HealthcareManagerApp, we believe in providing the best care for our patients and ensuring seamless operations for our healthcare providers.</p>
<p>Join us in our mission to make healthcare accessible and efficient for everyone.</p>
<p>
<a class="btn btn-primary" href="/login">Login</a>
<a class="btn btn-secondary" href="/register">Register</a>
</p>
+81
View File
@@ -0,0 +1,81 @@
@page "/login"
@inject IAuthenticationService AuthenticationService
@inject NavigationManager Navigation
@layout AuthLayout
<h3>Login</h3>
@if (!string.IsNullOrEmpty(_errorMessage))
{
<div class="alert alert-danger mt-2">@_errorMessage</div>
}
<EditForm Model="_loginModel" OnValidSubmit="HandleLogin">
<div class="form-group">
<label>Email:</label>
<InputText class="form-control" @bind-Value="_loginModel.Email"/>
</div>
<div class="form-group">
<label>Password:</label>
<InputText class="form-control" @bind-Value="_loginModel.Password" type="password"/>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</EditForm>
@code {
private readonly UserLoginModel _loginModel = new();
private string _errorMessage = string.Empty;
private async Task HandleLogin()
{
_errorMessage = string.Empty;
var response = await AuthenticationService.Login(_loginModel);
if (response.StatusCode == 200)
{
var token = await AuthenticationService.GetAuthToken();
var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(token);
var role = jwtToken.Claims.FirstOrDefault(c => c.Type == "role")?.Value;
switch (role)
{
case UserRoles.Admin:
Navigation.NavigateTo("/admin/dashboard", true);
break;
case UserRoles.Doctor:
Navigation.NavigateTo("/doctor/dashboard", true);
break;
case UserRoles.Patient:
Navigation.NavigateTo("/patient/dashboard", true);
break;
}
}
else
{
_errorMessage = response.Message; // Display error message
}
}
protected override async Task OnInitializedAsync()
{
var token = await AuthenticationService.GetAuthToken();
var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(token);
var role = jwtToken.Claims.FirstOrDefault(c => c.Type == "role")?.Value;
switch (role)
{
case UserRoles.Admin:
Navigation.NavigateTo("/admin/dashboard", true);
break;
case UserRoles.Doctor:
Navigation.NavigateTo("/doctor/dashboard", true);
break;
case UserRoles.Patient:
Navigation.NavigateTo("/patient/dashboard", true);
break;
}
}
}
+79
View File
@@ -0,0 +1,79 @@
@page "/register"
@inject NavigationManager Navigation
@inject IAuthenticationService AuthenticationService
@layout AuthLayout
<h3>Register</h3>
@if (!string.IsNullOrEmpty(_errorMessage))
{
<div class="alert alert-danger mt-2">@_errorMessage</div>
}
<EditForm Model="_registerModel" OnValidSubmit="HandleRegister">
<div class="form-group">
<label>Name:</label>
<InputText class="form-control" @bind-Value="_registerModel.Name"/>
</div>
<div class="form-group">
<label>Email:</label>
<InputText class="form-control" @bind-Value="_registerModel.Email"/>
</div>
<div class="form-group">
<label>Password:</label>
<InputText class="form-control" @bind-Value="_registerModel.Password" type="password"/>
</div>
<div class="form-group">
<label>Role:</label>
<InputSelect class="form-control" @bind-Value="_registerModel.Role">
<option value="">Select a role</option>
<option value="Doctor">Doctor</option>
<option value="Patient">Patient</option>
</InputSelect>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</EditForm>
@code {
private readonly UserRegisterModel _registerModel = new();
private string _errorMessage = string.Empty;
private async Task HandleRegister()
{
_errorMessage = string.Empty;
var response = await AuthenticationService.Register(_registerModel);
if (response.StatusCode == 201)
{
// Registration successful, navigate to login page
Navigation.NavigateTo("/login", true);
}
else
{
_errorMessage = response.Message; // Display error message
}
}
protected override async Task OnInitializedAsync()
{
var token = await AuthenticationService.GetAuthToken();
var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(token);
var role = jwtToken.Claims.FirstOrDefault(c => c.Type == "role")?.Value;
switch (role)
{
case UserRoles.Admin:
Navigation.NavigateTo("/admin/dashboard", true);
break;
case UserRoles.Doctor:
Navigation.NavigateTo("/doctor/dashboard", true);
break;
case UserRoles.Patient:
Navigation.NavigateTo("/patient/dashboard", true);
break;
}
}
}
@@ -0,0 +1,44 @@
@page "/reset-password"
@inject IAuthenticationService AuthenticationService
@inject NavigationManager Navigation
@layout AuthLayout
<h3>Reset Password</h3>
@if (!string.IsNullOrEmpty(_errorMessage))
{
<div class="alert alert-danger mt-2">@_errorMessage</div>
}
<EditForm Model="_resetPasswordModel" OnValidSubmit="HandleResetPassword">
<div class="form-group">
<label>Email:</label>
<InputText class="form-control" @bind-Value="_resetPasswordModel.Email"/>
</div>
<div class="form-group">
<label>New Password:</label>
<InputText class="form-control" @bind-Value="_resetPasswordModel.Password" type="password"/>
</div>
<button type="submit" class="btn btn-primary">Reset Password</button>
</EditForm>
@code {
private readonly ResetPasswordModel _resetPasswordModel = new();
private string _errorMessage = string.Empty;
private async Task HandleResetPassword()
{
_errorMessage = string.Empty;
var response = await AuthenticationService.ResetPassword(_resetPasswordModel);
if (response.StatusCode == 200)
{
Navigation.NavigateTo("/login", true);
}
else
{
_errorMessage = response.Message; // Display error message
}
}
}
+103
View File
@@ -0,0 +1,103 @@
@page "/doctor/ai"
@attribute [Authorize(Roles = UserRoles.Doctor)]
@layout DoctorLayout
@inject IDoctorManagementService DoctorManagementService
<h3>AI Sickness Prediction</h3>
@if (!string.IsNullOrEmpty(statusMessage))
{
<div class="alert @(isSuccess ? "alert-success" : "alert-danger")" role="alert">
@statusMessage
</div>
}
<div class="card mt-4">
<div class="card-header">
Upload PDF Document
</div>
<div class="card-body">
<InputFile OnChange="HandleFileSelected"/>
</div>
</div>
@if (predictions != null && predictions.Count > 0)
{
<div class="mt-4">
<h4>Predictions:</h4>
<ul>
@foreach (var prediction in predictions)
{
<li>@prediction.Disease - Probability: @prediction.Probability%</li>
}
</ul>
</div>
}
@code {
private string statusMessage = string.Empty;
private bool isSuccess = false;
private List<PredictionResult> predictions;
private async Task HandleFileSelected(InputFileChangeEventArgs e)
{
try
{
var file = e.File;
await using var stream = file.OpenReadStream();
using var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
var fileContent = memoryStream.ToArray();
var text = await ExtractTextFromPdf(fileContent);
Console.WriteLine(text);
if (!string.IsNullOrEmpty(text))
{
var result = await DoctorManagementService.GetSicknessPrediction(text);
if (result != null)
{
predictions = result.Data;
statusMessage = result.Message;
isSuccess = true;
}
else
{
statusMessage = "Failed to get predictions from the AI service.";
isSuccess = false;
}
}
else
{
statusMessage = "Failed to extract text from PDF.";
isSuccess = false;
}
}
catch (Exception ex)
{
statusMessage = $"Error: {ex.Message}";
isSuccess = false;
}
}
private async Task<string> ExtractTextFromPdf(byte[] pdfBytes)
{
using var reader = new MemoryStream(pdfBytes);
using var pdfReader = new PdfReader(reader);
using var pdfDoc = new PdfDocument(pdfReader);
var text = new StringBuilder();
for (int i = 1; i <= pdfDoc.GetNumberOfPages(); i++)
{
var strategy = new SimpleTextExtractionStrategy();
var pageText = PdfTextExtractor.GetTextFromPage(pdfDoc.GetPage(i), strategy);
text.AppendLine(pageText);
}
return text.ToString();
}
}
+129
View File
@@ -0,0 +1,129 @@
@page "/doctor/chat"
@attribute [Authorize(Roles = UserRoles.Doctor)]
@layout DoctorLayout
@inject IDoctorManagementService DoctorManagementService
@inject IAuthenticationService AuthenticationService
<h3>Chat with Patients</h3>
@if (!string.IsNullOrEmpty(statusMessage))
{
<div class="alert @(isSuccess ? "alert-success" : "alert-danger")" role="alert">
@statusMessage
</div>
}
<div class="row">
<div class="col-md-4">
<div class="list-group">
@foreach (var patient in patients)
{
<button class="list-group-item list-group-item-action" @onclick="() => OpenChat(patient.Id, patient.Name)">
@patient.Name
</button>
}
</div>
</div>
<div class="col-md-8">
@if (selectedPatient != null)
{
<div class="card">
<div class="card-header">
Chat with @selectedPatient.Name
<button class="btn btn-sm btn-danger float-right" @onclick="CloseChat">Close</button>
</div>
<div class="card-body chat-body">
@foreach (var message in messages)
{
<div class="chat-message @(message.UserId == userInfo.Id ? "chat-message-sender" : "chat-message-receiver")">
<strong>@(message.UserId == userInfo.Id ? "You" : selectedPatient.Name):</strong> @message.Content
</div>
}
</div>
<div class="card-footer">
<input type="text" class="form-control" @bind="newMessage" @onkeydown="HandleKeyDown" placeholder="Type your message..."/>
<button class="btn btn-primary mt-2" @onclick="SendMessage">Send</button>
</div>
</div>
}
</div>
</div>
<style>
.chat-body {
height: 300px;
overflow-y: scroll;
}
.chat-message {
margin-bottom: 10px;
}
.chat-message-sender {
text-align: right;
}
.chat-message-receiver {
text-align: left;
}
</style>
@code {
private string statusMessage = string.Empty;
private bool isSuccess = false;
private List<Patient> patients = new();
private Patient selectedPatient;
private List<Message> messages = new();
private string newMessage = string.Empty;
private UserInformation userInfo;
protected override async Task OnInitializedAsync()
{
userInfo = await AuthenticationService.GetUserInformation();
patients = await DoctorManagementService.GetAllPatientsAsync();
}
private async Task OpenChat(Guid patientId, string patientName)
{
selectedPatient = new Patient { Id = patientId, Name = patientName };
var chat = await DoctorManagementService.GetConversationAsync(userInfo.Id, patientId);
messages = chat?.Messages ?? new List<Message>();
StateHasChanged();
}
private void CloseChat()
{
selectedPatient = null;
messages.Clear();
}
private async Task SendMessage()
{
if (!string.IsNullOrWhiteSpace(newMessage) && selectedPatient != null)
{
var success = await DoctorManagementService.SendMessageAsync(userInfo.Id, selectedPatient.Id, newMessage);
if (success)
{
messages.Add(new Message(userInfo.Id, newMessage));
newMessage = string.Empty;
StateHasChanged();
}
else
{
statusMessage = "Failed to send message.";
isSuccess = false;
}
}
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
SendMessage().GetAwaiter().GetResult();
}
}
}
+122
View File
@@ -0,0 +1,122 @@
@page "/doctor/dashboard"
@attribute [Authorize(Roles = UserRoles.Doctor)]
@layout DoctorLayout
@inject IAuthenticationService AuthenticationService
@inject IDoctorManagementService DoctorManagementService
@inject NavigationManager NavigationManager
<h3>Dashboard</h3>
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="alert alert-danger" role="alert">
@errorMessage
</div>
}
@if (!string.IsNullOrEmpty(username))
{
<p>Welcome, Dr. @username!</p>
<p>Here you have listed your active appointments with patients.</p>
}
@if (appointments != null && appointments.Count > 0)
{
<table class="table">
<thead>
<tr>
<th>Patient</th>
<th>Time</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var appointment in appointments)
{
foreach (var appointmentTime in appointment.AppointmentsList)
{
<tr>
<td>@patients[Guid.Parse(appointment.PatientId)]</td>
<td>@appointmentTime.ToString("g")</td>
<td>
<button class="btn btn-danger" @onclick="() => DeleteAppointment(appointment, appointmentTime)">Delete</button>
</td>
</tr>
}
}
</tbody>
</table>
}
else if (string.IsNullOrEmpty(errorMessage))
{
<p>No appointments exist.</p>
}
@code {
private string username;
private List<Appointment> appointments = new();
private Dictionary<Guid, string> patients = new();
private string errorMessage = string.Empty;
protected override async Task OnInitializedAsync()
{
try
{
var userInfo = await AuthenticationService.GetUserInformation();
username = userInfo.Name;
appointments = await DoctorManagementService.GetAppointmentsAsync(userInfo.Id);
var allPatients = await DoctorManagementService.GetAllPatientsAsync();
patients = allPatients.ToDictionary(pat => pat.Id, pat => pat.Name);
if (!appointments.Any())
{
errorMessage = "No appointments exist.";
}
}
catch (Exception ex)
{
errorMessage = $"Failed to load data: {ex.Message}";
}
}
private async Task DeleteAppointment(Appointment appointment, DateTime appointmentTime)
{
try
{
var success = await DoctorManagementService.CancelAppointmentAsync(
Guid.Parse(appointment.DoctorId),
Guid.Parse(appointment.PatientId),
appointmentTime
);
if (success)
{
var appList = appointments.FirstOrDefault(a => a.Id == appointment.Id)?.AppointmentsList;
if (appList != null)
{
appList.Remove(appointmentTime);
if (!appList.Any())
{
appointments.Remove(appointment);
}
}
if (!appointments.Any())
{
errorMessage = "No appointments exist.";
}
}
else
{
errorMessage = "Failed to delete the appointment.";
}
StateHasChanged();
}
catch (Exception ex)
{
errorMessage = $"Error deleting appointment: {ex.Message}";
}
}
}
@@ -0,0 +1,101 @@
@page "/doctor/patients_medical_history"
@attribute [Authorize(Roles = UserRoles.Doctor)]
@layout DoctorLayout
@inject IDoctorManagementService DoctorManagementService
@inject IAuthenticationService AuthenticationService
@inject IJSRuntime JSRuntime
<script src="fileHelper.js"></script>
<script src="downloadFile.js"></script>
<h3>Patient Medical Histories</h3>
@if (!string.IsNullOrEmpty(statusMessage))
{
<div class="alert @(isSuccess ? "alert-success" : "alert-danger")" role="alert">
@statusMessage
</div>
}
<div class="row mt-4">
@foreach (var patient in patients)
{
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-body text-center">
<div>
<strong>Status: </strong>
@if (patientHasAccess(patient.Id))
{
<span class="text-success">Granted</span>
}
else
{
<span class="text-danger">Revoked</span>
}
</div>
<img src="user.png" style="width: 70px" alt="Patient" class="img-fluid mt-3"/>
<h5 class="mt-3">@patient.Name</h5>
<button class="btn btn-info mt-2" @onclick="() => DownloadMedicalHistory(patient.Id)" disabled="@(patientHasAccess(patient.Id) ? false : true)">Download Medical History</button>
</div>
</div>
</div>
}
</div>
@code {
private string statusMessage;
private bool isSuccess;
private List<Patient> patients = new();
private List<Guid> grantedAccessPatients = new();
protected override async Task OnInitializedAsync()
{
await LoadPatientsAndAccessStatus();
}
private async Task LoadPatientsAndAccessStatus()
{
var userInfo = await AuthenticationService.GetUserInformation();
patients = await DoctorManagementService.GetAllPatientsAsync();
await UpdatePatientAccessStatuses(userInfo.Id);
}
private async Task UpdatePatientAccessStatuses(Guid doctorId)
{
foreach (var patient in patients)
{
var medicalHistory = await DoctorManagementService.GetMedicalHistoryAsync(patient.Id);
if (medicalHistory == null) continue;
if (await DoctorManagementService.CheckForAccessAsync(medicalHistory.Id, doctorId))
{
grantedAccessPatients.Add(patient.Id);
}
}
StateHasChanged();
}
private bool patientHasAccess(Guid patientId)
{
return grantedAccessPatients.Contains(patientId);
}
private async Task DownloadMedicalHistory(Guid patientId)
{
var medicalHistory = await DoctorManagementService.DownloadMedicalHistoryAsync(patientId);
if (medicalHistory != null)
{
var base64 = Convert.ToBase64String(medicalHistory);
var href = $"data:application/octet-stream;base64,{base64}";
await JSRuntime.InvokeVoidAsync("downloadFile", "MedicalHistory.pdf", href);
}
else
{
statusMessage = "Failed to download medical history.";
isSuccess = false;
}
}
}
+107
View File
@@ -0,0 +1,107 @@
@page "/doctor/profile"
@attribute [Authorize(Roles = UserRoles.Doctor)]
@layout DoctorLayout
@inject NavigationManager Navigation
@inject IDoctorManagementService DoctorManagementService
@inject IAuthenticationService AuthenticationService
<h3>Profile</h3>
@if (!string.IsNullOrEmpty(updateMessage))
{
<div class="alert @(updateSuccess ? "alert-success" : "alert-danger") mt-3">@updateMessage</div>
}
<div class="card mt-4">
<div class="card-header">
Update Profile
</div>
<div class="card-body">
<EditForm Model="profileModel" OnValidSubmit="UpdateProfile">
<div class="form-row">
<div class="form-group col-md-6">
<label for="name">Name</label>
<InputText id="name" class="form-control" @bind-Value="profileModel.Name"/>
</div>
<div class="form-group col-md-6">
<label for="email">Email</label>
<InputText id="email" class="form-control" @bind-Value="profileModel.Email"/>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="password">Password</label>
<InputText id="password" type="password" class="form-control" @bind-Value="profileModel.Password"/>
</div>
<div class="form-group col-md-6">
<label for="description">Description</label>
<InputTextArea id="description" class="form-control" @bind-Value="profileModel.Description" rows="5"/>
</div>
</div>
<button type="submit" class="btn btn-primary">Save Changes</button>
</EditForm>
</div>
</div>
<div class="mt-4">
<button class="btn btn-danger" @onclick="DeleteAccount">Delete Account</button>
@if (!string.IsNullOrEmpty(deleteMessage))
{
<div class="alert @(deleteSuccess ? "alert-success" : "alert-danger") mt-3">@deleteMessage</div>
}
</div>
@code {
private Doctor profileModel = new();
private string updateMessage = string.Empty;
private string deleteMessage = string.Empty;
private bool updateSuccess = false;
private bool deleteSuccess = false;
protected override async Task OnInitializedAsync()
{
var userInfo = await AuthenticationService.GetUserInformation();
if (userInfo != null)
{
profileModel = await DoctorManagementService.GetDoctorProfileAsync(userInfo.Id);
}
}
private async Task UpdateProfile()
{
updateMessage = string.Empty;
updateSuccess = false;
var success = await DoctorManagementService.UpdateDoctorProfileAsync(profileModel);
if (success)
{
updateMessage = "Profile updated successfully.";
updateSuccess = true;
}
else
{
updateMessage = "An error occurred while updating your profile. Please try again.";
updateSuccess = false;
}
}
private async Task DeleteAccount()
{
deleteMessage = string.Empty;
deleteSuccess = false;
var success = await DoctorManagementService.DeleteDoctorProfileAsync(profileModel.Id);
if (success)
{
await AuthenticationService.RemoveAuthToken();
Navigation.NavigateTo("/goodbye");
}
else
{
deleteMessage = "An error occurred while deleting your account. Please try again.";
deleteSuccess = false;
}
}
}
@@ -0,0 +1,23 @@
@inject NavigationManager Navigation
@layout MainLayout;
<link href="css/Components/NotAuthorizedHandler.css" rel="stylesheet"/>
<div class="not-authorized-container">
<h1>Access Denied</h1>
<p>You do not have permission to view this page. This might be due to one of several reasons:</p>
<ul>
<li>You are not logged in. <a href="/login">Login</a> to continue.</li>
<li>You do not have the necessary permissions to access this resource.</li>
</ul>
<p>If you think this is a mistake, please contact your administrator.</p>
<button class="btn btn-primary" @onclick="GoHome">Return to Home Page</button>
</div>
@code {
void GoHome()
{
Navigation.NavigateTo("/", true);
}
}
@@ -0,0 +1,22 @@
@inject NavigationManager Navigation
@layout MainLayout;
<link href="css/Components/PageNotFoundHandler.css" rel="stylesheet"/>
<div class="page-not-found-container">
<h1>Page Not Found</h1>
<p>The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.</p>
<ul>
<li>Check the URL for typos.</li>
<li>Return to the <a href="/">Homepage</a>.</li>
</ul>
<button class="btn btn-primary" @onclick="GoHome">Return to Home Page</button>
</div>
@code {
void GoHome()
{
Navigation.NavigateTo("/", true);
}
}
@@ -0,0 +1,183 @@
@page "/patient/appointments"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject IPatientManagementService PatientManagementService;
@inject IAuthenticationService AuthenticationService;
<h3>Doctors</h3>
@if (!string.IsNullOrEmpty(_statusMessage))
{
<div class="alert @(_isError ? "alert-danger" : "alert-success")" role="alert">
@_statusMessage
</div>
}
<div class="card-deck">
@if (_doctors == null || !_doctors.Any())
{
<div class="alert alert-info center-content" style="width: 100%; height: 200px;">No doctors available.</div>
}
else
{
@foreach (var doctor in _doctors)
{
<div class="card doctor-card">
<div class="doctor-card-content">
<div class="user-icon"></div>
<div class="doctor-info">
<h5 class="card-title">Dr. @doctor.Name</h5>
<p class="card-text">@doctor.Email</p>
<button class="btn btn-primary" @onclick="() => ShowAppointmentOverlay(doctor)">Book Appointment</button>
</div>
</div>
</div>
}
}
</div>
@if (_showAppointmentOverlay)
{
<div class="overlay">
<div class="overlay-content">
<h5>Book Appointment with Dr. @_selectedDoctor.Name</h5>
<EditForm Model="@_dateAndTimeAppointment" OnValidSubmit="BookAppointment">
<div class="form-group">
<label for="date">Date</label>
<InputDate id="date" class="form-control" @bind-Value="_dateAndTimeAppointment.AppointmentDate" TValue="DateTime"/>
</div>
<div class="form-group">
<label for="time">Time</label>
<InputText id="time" class="form-control" @bind-Value="_dateAndTimeAppointment.FormattedAppointmentTime"/>
</div>
<button type="submit" class="btn btn-primary">Book</button>
<button type="button" class="btn btn-secondary" @onclick="HideAppointmentOverlay">Cancel</button>
</EditForm>
</div>
</div>
}
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.overlay-content {
background: white;
padding: 20px;
border-radius: 10px;
width: 400px;
text-align: center;
}
.doctor-card {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
margin-bottom: 20px;
}
.doctor-card-content {
display: flex;
align-items: center;
padding: 20px;
}
.user-icon {
background-image: url('user.png'); /* Ensure the path is correct */
background-size: cover;
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 20px;
}
.doctor-info {
display: flex;
flex-direction: column;
align-items: flex-start;
}
</style>
@code {
private List<Doctor> _doctors;
private Doctor _selectedDoctor;
private bool _showAppointmentOverlay = false;
private NewAppointmentModel _newAppointmentModel = new();
private DateAndTimeAppointment _dateAndTimeAppointment = new();
private string _statusMessage = string.Empty;
private bool _isError = false;
protected override async Task OnInitializedAsync()
{
await LoadDoctors();
}
private async Task LoadDoctors()
{
_doctors = await PatientManagementService.GetAllDoctorsAsync();
}
private void ShowAppointmentOverlay(Doctor doctor)
{
_selectedDoctor = doctor;
_newAppointmentModel = new NewAppointmentModel
{
DoctorId = doctor.Id
};
_showAppointmentOverlay = true;
}
private void HideAppointmentOverlay()
{
_showAppointmentOverlay = false;
}
private async Task BookAppointment()
{
var userInfo = await AuthenticationService.GetUserInformation();
_newAppointmentModel.PatientId = userInfo.Id;
_newAppointmentModel.Appointment = _dateAndTimeAppointment.GetAppointment();
var appointment = await PatientManagementService.BookAppointmentAsync(_newAppointmentModel);
_statusMessage = appointment.Message;
_isError = appointment.StatusCode != 201;
if (!_isError)
{
_showAppointmentOverlay = false;
}
}
class DateAndTimeAppointment
{
public DateTime AppointmentDate { get; set; } = DateTime.Now.Date;
public string FormattedAppointmentTime = DateTime.Now.ToString("HH:mm");
public DateTime GetAppointment()
{
// Parse FormattedAppointmentTime to a TimeSpan
if (TimeSpan.TryParse(FormattedAppointmentTime, out var appointmentTime))
{
// Combine AppointmentDate with appointmentTime
return AppointmentDate.Add(appointmentTime);
}
throw new FormatException("FormattedAppointmentTime is not in the correct format.");
}
}
}
+128
View File
@@ -0,0 +1,128 @@
@page "/patient/chat"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject IPatientManagementService PatientManagementService
@inject IAuthenticationService AuthenticationService
<h3>Chat with Doctors</h3>
@if (!string.IsNullOrEmpty(statusMessage))
{
<div class="alert @(isSuccess ? "alert-success" : "alert-danger")" role="alert">
@statusMessage
</div>
}
<div class="row">
<div class="col-md-4">
<div class="list-group">
@foreach (var doctor in doctors)
{
<button class="list-group-item list-group-item-action" @onclick="() => OpenChat(doctor.Id, doctor.Name)">
Dr. @doctor.Name
</button>
}
</div>
</div>
<div class="col-md-8">
@if (selectedDoctor != null)
{
<div class="card">
<div class="card-header">
Chat with Dr. @selectedDoctor.Name
<button class="btn btn-sm btn-danger float-right" @onclick="CloseChat">Close</button>
</div>
<div class="card-body chat-body">
@foreach (var message in messages)
{
<div class="chat-message @(message.UserId == userInfo.Id ? "chat-message-sender" : "chat-message-receiver")">
<strong>@(message.UserId == userInfo.Id ? "You" : selectedDoctor.Name):</strong> @message.Content
</div>
}
</div>
<div class="card-footer">
<input type="text" class="form-control" @bind="newMessage" @onkeydown="HandleKeyDown" placeholder="Type your message..."/>
<button class="btn btn-primary mt-2" @onclick="SendMessage">Send</button>
</div>
</div>
}
</div>
</div>
<style>
.chat-body {
height: 300px;
overflow-y: scroll;
}
.chat-message {
margin-bottom: 10px;
}
.chat-message-sender {
text-align: right;
}
.chat-message-receiver {
text-align: left;
}
</style>
@code {
private string statusMessage = string.Empty;
private bool isSuccess = false;
private List<Doctor> doctors = new();
private Doctor selectedDoctor;
private List<Message> messages = new();
private string newMessage = string.Empty;
private UserInformation userInfo;
protected override async Task OnInitializedAsync()
{
userInfo = await AuthenticationService.GetUserInformation();
doctors = await PatientManagementService.GetAllDoctorsAsync();
}
private async Task OpenChat(Guid doctorId, string doctorName)
{
selectedDoctor = new Doctor { Id = doctorId, Name = doctorName };
var chat = await PatientManagementService.GetConversationAsync(userInfo.Id, doctorId);
messages = chat?.Messages ?? new List<Message>();
StateHasChanged();
}
private void CloseChat()
{
selectedDoctor = null;
messages.Clear();
}
private async Task SendMessage()
{
if (!string.IsNullOrWhiteSpace(newMessage) && selectedDoctor != null)
{
var success = await PatientManagementService.SendMessageAsync(userInfo.Id, selectedDoctor.Id, newMessage);
if (success)
{
messages.Add(new Message(userInfo.Id, newMessage));
newMessage = string.Empty;
StateHasChanged();
}
else
{
statusMessage = "Failed to send message.";
isSuccess = false;
}
}
}
private void HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
SendMessage().GetAwaiter().GetResult();
}
}
}
@@ -0,0 +1,122 @@
@page "/patient/dashboard"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject IAuthenticationService AuthenticationService
@inject IPatientManagementService PatientManagementService
@inject NavigationManager NavigationManager
<h3>Dashboard</h3>
@if (errorMessage != string.Empty)
{
<div class="alert alert-danger" role="alert">
@errorMessage
</div>
}
@if (username != null)
{
<p>Welcome, @username!</p>
<p>Here you have listed your active appointments.</p>
}
@if (appointments != null && appointments.Count > 0)
{
<table class="table">
<thead>
<tr>
<th>Doctor</th>
<th>Time</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var appointment in appointments)
{
foreach (var appointmentTime in appointment.AppointmentsList)
{
<tr>
<td>Dr. @doctors[Guid.Parse(appointment.DoctorId)]</td>
<td>@appointmentTime.ToString("g")</td>
<td>
<button class="btn btn-danger" @onclick="() => DeleteAppointment(appointment, appointmentTime)">Delete</button>
</td>
</tr>
}
}
</tbody>
</table>
}
else if (errorMessage == string.Empty)
{
<p>No appointments exist.</p>
}
@code {
private string username;
private List<Appointment> appointments = new();
private Dictionary<Guid, string> doctors = new();
private string errorMessage = string.Empty;
protected override async Task OnInitializedAsync()
{
try
{
var userInfo = await AuthenticationService.GetUserInformation();
username = userInfo.Name;
appointments = await PatientManagementService.GetAppointmentsAsync(userInfo.Id);
var allDoctors = await PatientManagementService.GetAllDoctorsAsync();
doctors = allDoctors.ToDictionary(doc => doc.Id, doc => doc.Name);
if (!appointments.Any())
{
errorMessage = "No appointments exist.";
}
}
catch (Exception ex)
{
errorMessage = $"Failed to load data: {ex.Message}";
}
}
private async Task DeleteAppointment(Appointment appointment, DateTime appointmentTime)
{
try
{
var success = await PatientManagementService.CancelAppointmentAsync(
Guid.Parse(appointment.DoctorId),
Guid.Parse(appointment.PatientId),
appointmentTime
);
if (success)
{
var appList = appointments.FirstOrDefault(a => a.Id == appointment.Id)?.AppointmentsList;
if (appList != null)
{
appList.Remove(appointmentTime);
if (!appList.Any())
{
appointments.Remove(appointment);
}
}
if (!appointments.Any())
{
errorMessage = "No appointments exist.";
}
}
else
{
errorMessage = "Failed to delete the appointment.";
}
StateHasChanged();
}
catch (Exception ex)
{
errorMessage = $"Error deleting appointment: {ex.Message}";
}
}
}
@@ -0,0 +1,137 @@
@page "/patient/doctor_access"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject IPatientManagementService PatientManagementService
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
<h3>Manage Access to Medical History</h3>
@if (!string.IsNullOrEmpty(statusMessage))
{
<div class="alert @(isSuccess ? "alert-success" : "alert-danger")" role="alert">
@statusMessage
</div>
}
<div class="row mt-4">
@foreach (var doctor in doctors)
{
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-body text-center">
<div>
<strong>Status: </strong>
@if (doctorHasAccess(doctor.Id))
{
<span class="text-success">Granted</span>
}
else
{
<span class="text-danger">Revoked</span>
}
</div>
<img src="user.png" style="width: 70px" alt="Doctor" class="img-fluid mt-3"/>
<h5 class="mt-3">Dr. @doctor.Name</h5>
<button class="btn btn-success mt-2" @onclick="() => GrantAccess(doctor.Id)">Grant Access</button>
<button class="btn btn-warning mt-2" @onclick="() => RevokeAccess(doctor.Id)">Revoke Access</button>
</div>
</div>
</div>
}
</div>
@code {
private string statusMessage;
private bool isSuccess;
private List<Doctor> doctors = new();
private List<Guid> grantedAccessDoctors = new();
private Guid medicalRecordId;
protected override async Task OnInitializedAsync()
{
await LoadDoctorsAndAccessStatus();
}
private async Task LoadDoctorsAndAccessStatus()
{
var userInfo = await AuthenticationService.GetUserInformation();
var medicalHistory = await PatientManagementService.GetMedicalHistoryAsync(userInfo.Id);
if (medicalHistory != null)
{
medicalRecordId = medicalHistory.Id;
doctors = await PatientManagementService.GetAllDoctorsAsync();
await UpdateDoctorAccessStatuses(userInfo.Id);
}
else
{
statusMessage = "Failed to load medical history.";
isSuccess = false;
}
}
private async Task UpdateDoctorAccessStatuses(Guid patientId)
{
if (medicalRecordId != Guid.Empty)
{
foreach (var doctor in doctors)
{
if (await PatientManagementService.CheckForAccessAsync(medicalRecordId, doctor.Id))
{
grantedAccessDoctors.Add(doctor.Id);
}
}
StateHasChanged();
}
}
private bool doctorHasAccess(Guid doctorId)
{
return grantedAccessDoctors.Contains(doctorId);
}
private async Task GrantAccess(Guid doctorId)
{
if (medicalRecordId != Guid.Empty)
{
var success = await PatientManagementService.GrantAccessAsync(medicalRecordId, doctorId);
if (success)
{
grantedAccessDoctors.Add(doctorId);
statusMessage = "Access granted successfully.";
isSuccess = true;
}
else
{
statusMessage = "Failed to grant access.";
isSuccess = false;
}
StateHasChanged();
}
}
private async Task RevokeAccess(Guid doctorId)
{
if (medicalRecordId != Guid.Empty)
{
var success = await PatientManagementService.RevokeAccessAsync(medicalRecordId, doctorId);
if (success)
{
grantedAccessDoctors.Remove(doctorId);
statusMessage = "Access revoked successfully.";
isSuccess = true;
}
else
{
statusMessage = "Failed to revoke access.";
isSuccess = false;
}
StateHasChanged();
}
}
}
@@ -0,0 +1,74 @@
@page "/patient/doctors"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject IPatientManagementService PatientManagementService
<h3 class="text-center mb-4">Meet Our Doctors</h3>
@if (doctors is null)
{
<p class="text-center"><em>Loading doctors...</em></p>
}
else if (doctors.Count == 0)
{
<p class="text-center">No doctors are available at the moment.</p>
}
else
{
<div class="row">
@foreach (var doctor in doctors)
{
<div class="col-md-4 mb-4">
<div class="card h-100" @onclick="() => ToggleOverlay(doctor)">
<div class="card-body text-center">
<img src="user.png" alt="Doctor Image" class="img-fluid rounded-circle mb-2" style="width: 70px; height: 70px;">
<h5 class="card-title">@doctor.Name</h5>
<p class="card-text"><small class="text-muted">@doctor.Email</small></p>
</div>
</div>
</div>
}
</div>
@if (selectedDoctor != null)
{
<div class="modal" tabindex="-1" style="display:block; background-color: rgba(0,0,0,0.5);">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Doctor Details</h5>
<button type="button" class="close" @onclick="() => ToggleOverlay(null)">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Name: @selectedDoctor.Name</p>
<p>Email: @selectedDoctor.Email</p>
<p>Description: @((MarkupString)FormatDescription(selectedDoctor.Description))</p>
</div>
</div>
</div>
</div>
}
}
@code {
private List<Doctor> doctors;
private Doctor selectedDoctor;
protected override async Task OnInitializedAsync()
{
doctors = await PatientManagementService.GetAllDoctorsAsync();
}
private void ToggleOverlay(Doctor doctor)
{
selectedDoctor = doctor;
}
private string FormatDescription(string description)
{
// This is now handled directly in the modal body with MarkupString
return description?.Replace(Environment.NewLine, "<br />") ?? string.Empty;
}
}
@@ -0,0 +1,143 @@
@page "/patient/medical_history"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject IPatientManagementService PatientManagementService
@inject IAuthenticationService AuthenticationService
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<script src="fileHelper.js"></script>
<script src="downloadFile.js"></script>
<h3>Medical History</h3>
@if (!string.IsNullOrEmpty(statusMessage))
{
<div class="alert @(isSuccess ? "alert-success" : "alert-danger")" role="alert">
@statusMessage
</div>
}
@if (uploadedFile != null)
{
<div class="card mt-4">
<div class="card-header">
Medical History
</div>
<div class="card-body">
<img src="pngtree-pdf-file-icon-png-png-image_4899509.png" style="width:100px" alt="Medical Document" id="medicalDocument"/>
<div class="mt-4">
<button class="btn btn-primary" @onclick="PromptFileUpdate">Update</button>
<button class="btn btn-danger" @onclick="DeleteFile">Delete</button>
<button class="btn btn-secondary" @onclick="DownloadFile">Download</button>
</div>
</div>
</div>
}
else
{
<div class="card mt-4">
<div class="card-header">
Upload Medical History
</div>
<div class="card-body">
<InputFile OnChange="HandleFileSelected"/>
</div>
</div>
}
@code {
private MedicalHistory uploadedFile;
private string statusMessage;
private bool isSuccess;
protected override async Task OnInitializedAsync()
{
await CheckMedicalHistory();
}
private async Task CheckMedicalHistory()
{
var userInfo = await AuthenticationService.GetUserInformation();
uploadedFile = await PatientManagementService.GetMedicalHistoryAsync(userInfo.Id);
StateHasChanged();
}
private async Task HandleFileSelected(InputFileChangeEventArgs e)
{
var file = e.File;
if (file == null)
{
statusMessage = "No file selected.";
isSuccess = false;
StateHasChanged();
return;
}
// Check if the file MIME type is 'application/pdf'
if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase))
{
statusMessage = "Only PDF files are allowed.";
isSuccess = false;
StateHasChanged();
return;
}
using var memoryStream = new MemoryStream();
await file.OpenReadStream().CopyToAsync(memoryStream);
var fileContent = memoryStream.ToArray();
var userInfo = await AuthenticationService.GetUserInformation();
var response = await PatientManagementService.UploadMedicalHistoryAsync(userInfo.Id, fileContent);
statusMessage = response.Message;
isSuccess = response.StatusCode == HttpStatusCodes.Created; // Assume HttpStatusCodes.Created represents successful upload
await CheckMedicalHistory();
StateHasChanged();
}
private void PromptFileUpdate()
{
JSRuntime.InvokeVoidAsync("document.getElementById", "hiddenFileInput");
}
private async Task DeleteFile()
{
if (uploadedFile != null)
{
var success = await PatientManagementService.DeleteMedicalHistoryAsync(uploadedFile.Id);
if (success)
{
uploadedFile = null;
statusMessage = "File deleted successfully.";
isSuccess = true;
StateHasChanged();
}
else
{
statusMessage = "Failed to delete file.";
isSuccess = false;
}
}
}
private async Task DownloadFile()
{
if (uploadedFile != null)
{
var fileContent = await PatientManagementService.DownloadMedicalHistoryAsync(uploadedFile.Id);
if (fileContent != null)
{
var base64 = Convert.ToBase64String(fileContent);
var href = $"data:application/octet-stream;base64,{base64}";
await JSRuntime.InvokeVoidAsync("downloadFile", "MedicalHistory.pdf", href);
}
}
}
}
@@ -0,0 +1,92 @@
@page "/patient/profile"
@attribute [Authorize(Roles = UserRoles.Patient)]
@layout PatientLayout
@inject NavigationManager Navigation
@inject IPatientManagementService PatientManagementService
@inject IAuthenticationService AuthenticationService
<h3>Profile</h3>
@if (!string.IsNullOrEmpty(updateMessage))
{
<div class="alert alert-danger mt-3">@updateMessage</div>
}
<div class="card mt-4">
<div class="card-header">
Update Profile
</div>
<div class="card-body">
<EditForm Model="profileModel" OnValidSubmit="UpdateProfile">
<div class="form-group">
<label for="name">Name</label>
<InputText id="name" class="form-control" @bind-Value="profileModel.Name"/>
</div>
<div class="form-group">
<label for="email">Email</label>
<InputText id="email" class="form-control" @bind-Value="profileModel.Email"/>
</div>
<div class="form-group">
<label for="password">Password</label>
<InputText id="password" type="password" class="form-control" @bind-Value="profileModel.Password"/>
</div>
<button type="submit" class="btn btn-primary">Save Changes</button>
</EditForm>
</div>
</div>
<div class="mt-4">
<button class="btn btn-danger" @onclick="DeleteAccount">Delete Account</button>
@if (!string.IsNullOrEmpty(deleteMessage))
{
<div class="alert alert-danger mt-3">@deleteMessage</div>
}
</div>
@code {
private Patient profileModel = new();
private string updateMessage = string.Empty;
private string deleteMessage = string.Empty;
protected override async Task OnInitializedAsync()
{
var userInfo = await AuthenticationService.GetUserInformation();
if (userInfo != null)
{
profileModel = await PatientManagementService.GetPatientProfileAsync(userInfo.Id);
}
}
private async Task UpdateProfile()
{
updateMessage = string.Empty;
var success = await PatientManagementService.UpdatePatientProfileAsync(profileModel);
if (success)
{
Navigation.NavigateTo("/dashboard/patient", true);
}
else
{
updateMessage = "An error occurred while updating your profile. Please try again.";
}
}
private async Task DeleteAccount()
{
deleteMessage = string.Empty;
var success = await PatientManagementService.DeletePatientProfileAsync(profileModel.Id);
if (success)
{
await AuthenticationService.RemoveAuthToken();
Navigation.NavigateTo("/goodbye");
}
else
{
deleteMessage = "An error occurred while deleting your account. Please try again.";
}
}
}
+31 -15
View File
@@ -1,28 +1,44 @@
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization;
using HealthcareManagerUiWebAssem;
using HealthcareManagerUiWebAssem.Services.Appointment;
using HealthcareManagerUiWebAssem.Services.AdminUserManagement;
using HealthcareManagerUiWebAssem.Services.Authentication;
using HealthcareManagerUiWebAssem.Services.Http;
using HealthcareManagerUiWebAssem.Services.Profile;
using HealthcareManagerUiWebAssem.Services.User;
using HealthcareManagerUiWebAssem.Services.UserSessionInformation;
using HealthcareManagerUiWebAssem.Services.DoctorManagement;
using HealthcareManagerUiWebAssem.Services.PatientManagement;
using HealthcareManagerUiWebAssem.Services.RequestHttp;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.Configure<ApplicationSettings>(builder.Configuration.GetSection("ApiSettings"));
builder.Services.AddHttpClient();
// Configure API settings
var apiSettings = builder.Configuration.GetSection("ApiSettings").Get<ApplicationSettings>();
builder.Services.AddSingleton(apiSettings);
// Configure custom HttpClient handler
builder.Services.AddTransient<AuthenticationHttpMessageHandler>();
builder.Services.AddHttpClient<IRequestHttpService, RequestHttpService>((sp, httpClient) =>
{
var settings = sp.GetRequiredService<ApplicationSettings>();
httpClient.BaseAddress = new Uri(settings.BaseAddress);
}).AddHttpMessageHandler<AuthenticationHttpMessageHandler>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddScoped<IUserSessionInformation, UserSessionInformation>();
builder.Services.AddScoped<IRequestHttpService, RequestHttpService>();
builder.Services.AddScoped<UserService>();
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
builder.Services.AddScoped<IProfileService, ProfileService>();
builder.Services.AddScoped<IAppointmentService, AppointmentService>();
builder.Services.AddScoped<IAdminManagementService, AdminManagementService>();
builder.Services.AddScoped<IPatientManagementService, PatientManagementService>();
builder.Services.AddScoped<IDoctorManagementService, DoctorManagementService>();
await builder.Build().RunAsync();
// Register CustomAuthenticationStateProvider as the AuthenticationStateProvider
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
builder.Services.AddAuthorizationCore(config =>
{
config.AddPolicy("AdminOnly", policy => policy.RequireRole(UserRoles.Admin));
config.AddPolicy("DoctorOnly", policy => policy.RequireRole(UserRoles.Doctor));
config.AddPolicy("PatientOnly", policy => policy.RequireRole(UserRoles.Patient));
});
await builder.Build().RunAsync();
+27
View File
@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
namespace HealthcareManagerUiWebAssem;
public class RoleBasedRedirect : ComponentBase
{
[CascadingParameter] private Task<AuthenticationState> authenticationStateTask { get; set; }
[Inject] private NavigationManager NavigationManager { get; set; }
protected override async Task OnInitializedAsync()
{
var authState = await authenticationStateTask;
var user = authState.User;
if (NavigationManager.Uri == NavigationManager.BaseUri)
if (user.Identity.IsAuthenticated)
{
// Perform redirection based on the user's role
if (user.IsInRole(UserRoles.Admin))
NavigationManager.NavigateTo("/admin/dashboard");
else if (user.IsInRole(UserRoles.Doctor))
NavigationManager.NavigateTo("/doctor/dashboard");
else if (user.IsInRole(UserRoles.Patient)) NavigationManager.NavigateTo("/patient/dashboard");
}
}
}
@@ -0,0 +1,38 @@
using System.Net.Http.Json;
using System.Text.Json;
using HealthcareManagerUiWebAssem.Entities;
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.RequestHttp;
namespace HealthcareManagerUiWebAssem.Services.AdminUserManagement;
public class AdminManagementService(IRequestHttpService requestHttpService) : IAdminManagementService
{
public async Task<ApiResponse<List<Doctor>>> GetDoctors()
{
var response = await requestHttpService.GetAsync("/api/Doctors");
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<ApiResponse<List<Doctor>>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
public async Task<ApiResponse<List<Patient>>> GetPatients()
{
var response = await requestHttpService.GetAsync("/api/Patients");
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<ApiResponse<List<Patient>>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
public async Task<bool> DeleteDoctor(Guid id)
{
var response = await requestHttpService.DeleteAsync($"/api/Doctors/{id}");
return response.IsSuccessStatusCode;
}
public async Task<bool> DeletePatient(Guid id)
{
var response = await requestHttpService.DeleteAsync($"/api/Patients/{id}");
return response.IsSuccessStatusCode;
}
}
@@ -0,0 +1,12 @@
using HealthcareManagerUiWebAssem.Entities;
using HealthcareManagerUiWebAssem.Models;
namespace HealthcareManagerUiWebAssem.Services.AdminUserManagement;
public interface IAdminManagementService
{
Task<ApiResponse<List<Doctor>>> GetDoctors();
Task<ApiResponse<List<Patient>>> GetPatients();
Task<bool> DeleteDoctor(Guid id);
Task<bool> DeletePatient(Guid id);
}
@@ -1,88 +0,0 @@
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.Http;
namespace HealthcareManagerUiWebAssem.Services.Appointment;
public class AppointmentService : IAppointmentService
{
private readonly IRequestHttpService _requestHttpService;
public AppointmentService(IRequestHttpService requestHttpService)
{
_requestHttpService = requestHttpService;
}
public async Task<BaseResponse> GetAppointmentsByPatient(Guid patientId)
{
try
{
var response = await _requestHttpService.GetByIdAsync("/Appointments/patient", patientId);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> GetAppointmentsByDoctor(Guid doctorId)
{
try
{
var response = await _requestHttpService.GetByIdAsync("/Appointments/doctor", doctorId);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> CreateAppointment(
AppointmentManagementModel model)
{
try
{
var response = await _requestHttpService.PostAsync("/Appointments", model);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> DeleteAppointment(AppointmentManagementModel model)
{
try
{
var response = await _requestHttpService.DeleteByFilterAsync("/Appointments", model);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
}
@@ -1,14 +0,0 @@
using HealthcareManagerUiWebAssem.Models;
namespace HealthcareManagerUiWebAssem.Services.Appointment;
public interface IAppointmentService
{
Task<BaseResponse> GetAppointmentsByPatient(Guid patientId);
Task<BaseResponse> GetAppointmentsByDoctor(Guid doctorId);
Task<BaseResponse> CreateAppointment(AppointmentManagementModel model);
Task<BaseResponse> DeleteAppointment(AppointmentManagementModel model);
}
@@ -1,104 +1,98 @@
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.Http;
using System.IdentityModel.Tokens.Jwt;
using HealthcareManagerUiWebAssem.Models;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Text.Json;
using Blazored.LocalStorage;
using HealthcareManagerUiWebAssem.Services.RequestHttp;
using Microsoft.AspNetCore.Components.Authorization;
namespace HealthcareManagerUiWebAssem.Services.Authentication;
public class AuthenticationService : IAuthenticationService
public class AuthenticationService(
IRequestHttpService requestHttpService,
ILocalStorageService localStorageService,
AuthenticationStateProvider authenticationStateProvider)
: IAuthenticationService
{
private readonly IRequestHttpService _requestHttpService;
public AuthenticationService(IRequestHttpService requestHttpService)
public async Task<ApiResponse<string>> Login(UserLoginModel loginModel)
{
_requestHttpService = requestHttpService;
var response = await requestHttpService.PostAsync("/api/Authorization/login", loginModel);
var responseContent = await response.Content.ReadAsStringAsync();
var loginResponse = JsonSerializer.Deserialize<ApiResponse<string>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (response.IsSuccessStatusCode) await localStorageService.SetItemAsync("authToken", loginResponse.Data);
return loginResponse;
}
public async Task<BaseResponse> Login(UserLoginModel userLoginModel)
public async Task<ApiResponse<string>> Register(UserRegisterModel registerModel)
{
try
{
var response = await _requestHttpService.PostAsync("/Authorization/login", userLoginModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
var response = await requestHttpService.PostAsync("/api/Authorization/register", registerModel);
var responseContent = await response.Content.ReadAsStringAsync();
var registerResponse = JsonSerializer.Deserialize<ApiResponse<string>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
return registerResponse;
}
public async Task<BaseResponse> RegisterDoctor(UserRegisterModel userRegistrationModel)
public async Task<ApiResponse<string>> ResetJwt(string token)
{
try
{
var response = await _requestHttpService.PostAsync("/Doctors/register", userRegistrationModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> RegisterPatient(UserRegisterModel userRegistrationModel)
{
try
{
var response = await _requestHttpService.PostAsync("/Patients/register", userRegistrationModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
var requestBody = new { token = token };
var response = await requestHttpService.PostAsync("/api/Authorization/refresh_token", requestBody);
var responseContent = await response.Content.ReadAsStringAsync();
var resetJwtResponse = JsonSerializer.Deserialize<ApiResponse<string>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (response.IsSuccessStatusCode) await localStorageService.SetItemAsync("authToken", resetJwtResponse.Data);
return resetJwtResponse;
}
public async Task<BaseResponse> ResetPassword(UserLoginModel dto)
public async Task<ApiResponse<object>> ResetPassword(ResetPasswordModel resetPasswordModel)
{
try
{
var response = await _requestHttpService.PostAsync("/Authorization/reset_password", dto);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
var requestBody = new { email = resetPasswordModel.Email, password = resetPasswordModel.Password };
var response = await requestHttpService.PostAsync("/api/Authorization/reset_password", requestBody);
var responseContent = await response.Content.ReadAsStringAsync();
var resetPasswordResponse = JsonSerializer.Deserialize<ApiResponse<object>>(responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
return resetPasswordResponse;
}
public async Task<BaseResponse> RefreshToken(TokenRefreshModel dto)
public async Task<UserInformation?> GetUserInformation()
{
try
var token = await GetAuthToken();
if (string.IsNullOrEmpty(token)) return null;
var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(token);
var name = jwtToken.Claims.FirstOrDefault(c => c.Type == "unique_name")?.Value;
var id = jwtToken.Claims.FirstOrDefault(c => c.Type == "nameid")?.Value;
var role = jwtToken.Claims.FirstOrDefault(c => c.Type == "role")?.Value;
return new UserInformation
{
var response = await _requestHttpService.PostAsync("/Authorization/refresh_token", dto);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
Name = name,
Id = Guid.Parse(id),
Role = role
};
}
public async Task Logout()
{
await localStorageService.RemoveItemAsync("authToken");
((CustomAuthenticationStateProvider)authenticationStateProvider).NotifyUserLogout();
}
public async Task<string> GetAuthToken()
{
return await localStorageService.GetItemAsync<string>("authToken");
}
public async Task RemoveAuthToken()
{
await localStorageService.RemoveItemAsync("authToken");
}
}
@@ -4,9 +4,12 @@ namespace HealthcareManagerUiWebAssem.Services.Authentication;
public interface IAuthenticationService
{
Task<BaseResponse> Login(UserLoginModel userLoginModel);
Task<BaseResponse> RegisterPatient(UserRegisterModel userRegistrationModel);
Task<BaseResponse> RegisterDoctor(UserRegisterModel userRegistrationModel);
Task<BaseResponse> ResetPassword(UserLoginModel userResetPasswordModel);
Task<BaseResponse> RefreshToken(TokenRefreshModel dto);
Task<ApiResponse<string>> Login(UserLoginModel loginModel);
Task<ApiResponse<string>> Register(UserRegisterModel registerModel);
Task<ApiResponse<object>> ResetPassword(ResetPasswordModel resetPasswordModel);
Task<ApiResponse<string>> ResetJwt(string token);
Task Logout();
Task<string> GetAuthToken();
Task RemoveAuthToken();
Task<UserInformation?> GetUserInformation();
}
@@ -0,0 +1,108 @@
using System.Net.Http.Json;
using HealthcareManagerUiWebAssem.Entities;
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.RequestHttp;
namespace HealthcareManagerUiWebAssem.Services.DoctorManagement;
public class DoctorManagementService(IRequestHttpService requestHttpService) : IDoctorManagementService
{
public async Task<Doctor> GetDoctorProfileAsync(Guid doctorId)
{
var response = await requestHttpService.GetAsync($"/api/Doctors/{doctorId}");
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<Doctor>>();
return apiResponse?.Data;
}
public async Task<bool> UpdateDoctorProfileAsync(Doctor doctor)
{
var response = await requestHttpService.PutAsync("/api/Doctors", doctor);
return response.IsSuccessStatusCode;
}
public async Task<bool> DeleteDoctorProfileAsync(Guid doctorId)
{
var response = await requestHttpService.DeleteAsync($"/api/Doctors/{doctorId}");
return response.IsSuccessStatusCode;
}
public async Task<MedicalHistory?> GetMedicalHistoryAsync(Guid userId)
{
var response = await requestHttpService.GetAsync($"/api/MedicalHistory/user/{userId}");
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<MedicalHistory>>();
return apiResponse.Data;
}
public async Task<List<Patient>> GetAllPatientsAsync()
{
var response = await requestHttpService.GetAsync("/api/Patients");
if (!response.IsSuccessStatusCode) return [];
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<List<Patient>>>();
return apiResponse?.Data ?? [];
}
public async Task<List<Appointment>> GetAppointmentsAsync(Guid doctorId)
{
var response = await requestHttpService.GetAsync($"/api/Appointments/doctor/{doctorId}");
if (!response.IsSuccessStatusCode) return [];
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<List<Appointment>>>();
return apiResponse?.Data ?? [];
}
public async Task<bool> SendMessageAsync(Guid senderId, Guid receiverId, string message)
{
var requestBody = new { sender = senderId, receiver = receiverId, message = message };
var response = await requestHttpService.PostAsync("/api/Chat/send_message", requestBody);
return response.IsSuccessStatusCode;
}
public async Task<bool> CancelAppointmentAsync(Guid doctorId, Guid patientId, DateTime appointmentDate)
{
var cancellationRequest = new AppointmentCancellationRequest
{
DoctorId = doctorId,
PatientId = patientId,
Appointment = appointmentDate
};
var response = await requestHttpService.PutAsync("/api/Appointments", cancellationRequest);
return response.IsSuccessStatusCode;
}
public async Task<Chat> GetConversationAsync(Guid userId1, Guid userId2)
{
var requestBody = new { idUser1 = userId1, idUser2 = userId2 };
var response = await requestHttpService.PostAsync("/api/Chat/get_conversation", requestBody);
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<Chat>>();
return apiResponse?.Data;
}
public async Task<byte[]> DownloadMedicalHistoryAsync(Guid patientId)
{
var response = await requestHttpService.GetAsync($"/api/MedicalHistory/user/{patientId}");
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<MedicalHistory>>();
return apiResponse.Data.Content;
}
public async Task<bool> CheckForAccessAsync(Guid medicalRecordId, Guid doctorId)
{
var requestBody = new { MedicalRecordId = medicalRecordId, DoctorId = doctorId };
var response = await requestHttpService.PostAsync("/api/MedicalHistory/check_access", requestBody);
return response.IsSuccessStatusCode;
}
public async Task<ApiResponse<List<PredictionResult>>> GetSicknessPrediction(string text)
{
var requestBody = new { text };
var response = await requestHttpService.PostAsync("/api/SicknessPrediction", requestBody);
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<List<PredictionResult>>>();
return apiResponse;
}
}
@@ -0,0 +1,22 @@
using HealthcareManagerUiWebAssem.Entities;
using HealthcareManagerUiWebAssem.Models;
namespace HealthcareManagerUiWebAssem.Services.DoctorManagement;
public interface IDoctorManagementService
{
Task<Doctor> GetDoctorProfileAsync(Guid doctorId);
Task<bool> UpdateDoctorProfileAsync(Doctor doctor);
Task<bool> DeleteDoctorProfileAsync(Guid doctorId);
Task<List<Appointment>> GetAppointmentsAsync(Guid doctorId);
Task<bool> CancelAppointmentAsync(Guid doctorId, Guid patientId, DateTime appointmentDate);
Task<MedicalHistory?> GetMedicalHistoryAsync(Guid userId);
Task<List<Patient>> GetAllPatientsAsync();
Task<bool> SendMessageAsync(Guid senderId, Guid receiverId, string message);
Task<Chat> GetConversationAsync(Guid userId1, Guid userId2);
Task<byte[]> DownloadMedicalHistoryAsync(Guid patientId);
Task<bool> CheckForAccessAsync(Guid medicalRecordId, Guid doctorId);
Task<ApiResponse<List<PredictionResult>>> GetSicknessPrediction(string text);
}
@@ -1,17 +0,0 @@
using HealthcareManagerUiWebAssem.Models;
namespace HealthcareManagerUiWebAssem.Services.Http;
public interface IRequestHttpService
{
Task<BaseResponse> GetAsync(string uri, IDictionary<string, string> headers = null);
Task<BaseResponse> GetByIdAsync(string uri, Guid id, IDictionary<string, string> headers = null);
Task<BaseResponse> PostAsync(string uri, object data, IDictionary<string, string> headers = null);
Task<BaseResponse> PutAsync(string uri, object data, IDictionary<string, string> headers = null);
Task<BaseResponse> DeleteAsync(string uri, Guid id, IDictionary<string, string> headers = null);
Task<BaseResponse> DeleteByFilterAsync(string uri, object data, IDictionary<string, string> headers = null);
}
@@ -1,144 +0,0 @@
using System.Text;
using System.Text.Json;
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.UserSessionInformation;
using Microsoft.Extensions.Options;
namespace HealthcareManagerUiWebAssem.Services.Http;
public class RequestHttpService : IRequestHttpService
{
private readonly string _apiEndpoint;
private readonly string _apiKey;
private readonly HttpClient _httpClient;
private readonly IUserSessionInformation _userSessionInformation;
public RequestHttpService(IHttpClientFactory httpClientFactory, IUserSessionInformation userSessionInformation,
IOptions<ApplicationSettings> settings)
{
_httpClient = httpClientFactory.CreateClient();
_apiKey = settings.Value.ApiKey ?? "NoKey";
_apiEndpoint = settings.Value.ApiEndpoint;
_userSessionInformation = userSessionInformation;
}
public async Task<BaseResponse> GetByIdAsync(string uri, Guid id, IDictionary<string, string>? headers = null)
{
headers ??= new Dictionary<string, string>();
var request = new HttpRequestMessage(HttpMethod.Get, $"{_apiEndpoint}{uri}/{id}");
AddHeaders(request, headers);
var response = await _httpClient.SendAsync(request);
Thread.Sleep(1000);
return await HandleResponse(response, uri);
}
public async Task<BaseResponse> GetAsync(string uri, IDictionary<string, string>? headers = null)
{
headers ??= new Dictionary<string, string>();
var request = new HttpRequestMessage(HttpMethod.Get, $"{_apiEndpoint}{uri}");
AddHeaders(request, headers);
var response = await _httpClient.SendAsync(request);
Thread.Sleep(1000);
return await HandleResponse(response, uri);
}
public async Task<BaseResponse> PostAsync(string uri, object data, IDictionary<string, string>? headers = null)
{
headers ??= new Dictionary<string, string>();
var request = new HttpRequestMessage(HttpMethod.Post, $"{_apiEndpoint}{uri}"); // Prepend _apiEndpoint
AddHeaders(request, headers);
request.Content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
Thread.Sleep(1000);
return await HandleResponse(response, uri);
}
public async Task<BaseResponse> PutAsync(string uri, object data, IDictionary<string, string>? headers = null)
{
headers ??= new Dictionary<string, string>();
var request = new HttpRequestMessage(HttpMethod.Put, $"{_apiEndpoint}{uri}");
AddHeaders(request, headers);
request.Content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
Thread.Sleep(1000);
return await HandleResponse(response, uri);
}
public async Task<BaseResponse> DeleteAsync(string uri, Guid id, IDictionary<string, string>? headers = null)
{
headers ??= new Dictionary<string, string>();
var request = new HttpRequestMessage(HttpMethod.Delete, $"{_apiEndpoint}{uri}/{id}");
AddHeaders(request, headers);
var response = await _httpClient.SendAsync(request);
Thread.Sleep(1000);
return await HandleResponse(response, uri);
}
public async Task<BaseResponse> DeleteByFilterAsync(string uri, object data, IDictionary<string, string>? headers = null)
{
headers ??= new Dictionary<string, string>();
var request = new HttpRequestMessage(HttpMethod.Delete, $"{_apiEndpoint}{uri}");
AddHeaders(request, headers);
request.Content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
Thread.Sleep(1000);
return await HandleResponse(response, uri);
}
private async void AddHeaders(HttpRequestMessage request, IDictionary<string, string>? headers)
{
request.Headers.Add("ApiKey", _apiKey);
request.Headers.Add("Authorization", "Bearer " + await _userSessionInformation.GetTokenAsync());
if (headers == null) return;
foreach (var header in headers) request.Headers.Add(header.Key, header.Value);
}
private async Task<BaseResponse> HandleResponse(HttpResponseMessage? response, string uri)
{
var responseContent = await response.Content.ReadAsStringAsync();
var responseJson = JsonSerializer.Deserialize<JsonResponse>(
responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
var baseResponse = new BaseResponse();
if (responseJson != null)
{
baseResponse.StatusCode = responseJson.StatusCode;
baseResponse.Message = responseJson.Message;
baseResponse.Data = responseJson.Data.ToString();
baseResponse.Headers = new Dictionary<string, string>();
}
foreach (var header in response.Headers.Concat(response.Content.Headers))
{
Console.WriteLine(header.Key);
if (baseResponse.Headers.ContainsKey(header.Key))
{
baseResponse.Headers[header.Key] += ", " + string.Join(", ", header.Value);
}
else
{
baseResponse.Headers.Add(header.Key, string.Join(", ", header.Value));
}
}
return baseResponse;
}
class JsonResponse
{
public int StatusCode { get; set; }
public string Message { get; set; }
public JsonElement Data { get; set; }
}
}
@@ -0,0 +1,30 @@
using HealthcareManagerUiWebAssem.Entities;
using HealthcareManagerUiWebAssem.Models;
namespace HealthcareManagerUiWebAssem.Services.PatientManagement;
public interface IPatientManagementService
{
Task<Patient> GetPatientProfileAsync(Guid patientId);
Task<bool> UpdatePatientProfileAsync(Patient patient);
Task<bool> DeletePatientProfileAsync(Guid patientId);
Task<List<Appointment>> GetAppointmentsAsync(Guid patientId);
Task<ApiResponse<object>> BookAppointmentAsync(NewAppointmentModel newAppointment);
Task<bool> CancelAppointmentAsync(Guid doctorId, Guid patientId, DateTime appointmentDate);
Task<MedicalHistory?> GetMedicalHistoryAsync(Guid userId);
Task<ApiResponse<object>> UploadMedicalHistoryAsync(Guid userId, byte[] content);
Task<bool> DeleteMedicalHistoryAsync(Guid fileId);
Task<byte[]> DownloadMedicalHistoryAsync(Guid fileId);
Task<List<Doctor>> GetAllDoctorsAsync();
Task<bool> CheckForAccessAsync(Guid medicalRecordId, Guid doctorId);
Task<bool> GrantAccessAsync(Guid medicalRecordId, Guid doctorId);
Task<bool> RevokeAccessAsync(Guid medicalRecordId, Guid doctorId);
Task<bool> SendMessageAsync(Guid senderId, Guid receiverId, string message);
Task<Chat> GetConversationAsync(Guid userId1, Guid userId2);
}
@@ -0,0 +1,139 @@
using System.Net.Http.Json;
using HealthcareManagerUiWebAssem.Entities;
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.RequestHttp;
namespace HealthcareManagerUiWebAssem.Services.PatientManagement;
public class PatientManagementService(IRequestHttpService requestHttpService) : IPatientManagementService
{
public async Task<Patient> GetPatientProfileAsync(Guid patientId)
{
var response = await requestHttpService.GetAsync($"/api/Patients/{patientId}");
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<Patient>>();
return apiResponse?.Data;
}
public async Task<bool> UpdatePatientProfileAsync(Patient patient)
{
var response = await requestHttpService.PutAsync("/api/Patients", patient);
return response.IsSuccessStatusCode;
}
public async Task<bool> DeletePatientProfileAsync(Guid patientId)
{
var response = await requestHttpService.DeleteAsync($"/api/Patients/{patientId}");
return response.IsSuccessStatusCode;
}
public async Task<List<Appointment>> GetAppointmentsAsync(Guid patientId)
{
var response = await requestHttpService.GetAsync($"/api/Appointments/patient/{patientId}");
if (!response.IsSuccessStatusCode) return new List<Appointment>();
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<List<Appointment>>>();
return apiResponse?.Data ?? [];
}
public async Task<ApiResponse<object>> BookAppointmentAsync(NewAppointmentModel newAppointment)
{
var response = await requestHttpService.PostAsync("/api/Appointments", newAppointment);
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<object>>();
return apiResponse;
}
public async Task<bool> CancelAppointmentAsync(Guid doctorId, Guid patientId, DateTime appointmentDate)
{
var cancellationRequest = new AppointmentCancellationRequest
{
DoctorId = doctorId,
PatientId = patientId,
Appointment = appointmentDate
};
var response = await requestHttpService.PutAsync("/api/Appointments", cancellationRequest);
return response.IsSuccessStatusCode;
}
// Medical history methods
public async Task<MedicalHistory?> GetMedicalHistoryAsync(Guid userId)
{
var response = await requestHttpService.GetAsync($"/api/MedicalHistory/user/{userId}");
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<MedicalHistory>>();
return apiResponse.Data;
}
public async Task<ApiResponse<object>> UploadMedicalHistoryAsync(Guid userId, byte[] content)
{
var requestBody = new { UserId = userId, Content = content };
var response = await requestHttpService.PostAsync("/api/MedicalHistory", requestBody);
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<object>>();
return apiResponse;
}
public async Task<bool> DeleteMedicalHistoryAsync(Guid fileId)
{
var response = await requestHttpService.DeleteAsync($"/api/MedicalHistory/{fileId}");
return response.IsSuccessStatusCode;
}
public async Task<byte[]> DownloadMedicalHistoryAsync(Guid fileId)
{
var response = await requestHttpService.GetAsync($"/api/MedicalHistory/{fileId}");
if (response.IsSuccessStatusCode) return await response.Content.ReadAsByteArrayAsync();
return null;
}
public async Task<List<Doctor>> GetAllDoctorsAsync()
{
var response = await requestHttpService.GetAsync("/api/Doctors");
if (!response.IsSuccessStatusCode) return [];
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<List<Doctor>>>();
return apiResponse?.Data ?? [];
}
public async Task<bool> CheckForAccessAsync(Guid medicalRecordId, Guid doctorId)
{
var requestBody = new { MedicalRecordId = medicalRecordId, DoctorId = doctorId };
var response = await requestHttpService.PostAsync("/api/MedicalHistory/check_access", requestBody);
return response.IsSuccessStatusCode;
}
public async Task<bool> GrantAccessAsync(Guid medicalRecordId, Guid doctorId)
{
var requestBody = new { MedicalRecordId = medicalRecordId, DoctorId = doctorId };
var response = await requestHttpService.PutAsync("/api/MedicalHistory/grant_access", requestBody);
if (!response.IsSuccessStatusCode) return false;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<object>>();
return apiResponse.StatusCode == HttpStatusCodes.OK;
}
public async Task<bool> RevokeAccessAsync(Guid medicalRecordId, Guid doctorId)
{
var requestBody = new { MedicalRecordId = medicalRecordId, DoctorId = doctorId };
var response = await requestHttpService.PutAsync("/api/MedicalHistory/revoke_access", requestBody);
if (!response.IsSuccessStatusCode) return false;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<object>>();
return apiResponse.StatusCode == HttpStatusCodes.OK;
}
public async Task<bool> SendMessageAsync(Guid senderId, Guid receiverId, string message)
{
var requestBody = new { sender = senderId, receiver = receiverId, message = message };
var response = await requestHttpService.PostAsync("/api/Chat/send_message", requestBody);
return response.IsSuccessStatusCode;
}
public async Task<Chat> GetConversationAsync(Guid userId1, Guid userId2)
{
var requestBody = new { idUser1 = userId1, idUser2 = userId2 };
var response = await requestHttpService.PostAsync("/api/Chat/get_conversation", requestBody);
if (!response.IsSuccessStatusCode) return null;
var apiResponse = await response.Content.ReadFromJsonAsync<ApiResponse<Chat>>();
return apiResponse?.Data;
}
}
@@ -1,22 +0,0 @@
using HealthcareManagerUiWebAssem.Models;
namespace HealthcareManagerUiWebAssem.Services.Profile;
public interface IProfileService
{
Task<BaseResponse> GetDoctors();
Task<BaseResponse> GetPatients();
Task<BaseResponse> GetDoctorById(Guid id);
Task<BaseResponse> GetPatientById(Guid id);
Task<BaseResponse> UpdateDoctorProfile(UserUpdateProfileModel userUpdateProfileModel);
Task<BaseResponse> UpdatePatientProfile(UserUpdateProfileModel userUpdateProfileModel);
Task<BaseResponse> DeleteDoctorProfile(Guid id);
Task<BaseResponse> DeletePatientProfile(Guid id);
}
-161
View File
@@ -1,161 +0,0 @@
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.Http;
namespace HealthcareManagerUiWebAssem.Services.Profile;
public class ProfileService : IProfileService
{
private readonly IRequestHttpService _requestHttpService;
public ProfileService(IRequestHttpService requestHttpService)
{
_requestHttpService = requestHttpService;
}
public async Task<BaseResponse> GetDoctors()
{
try
{
var response = await _requestHttpService.GetAsync("/Doctors");
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> GetPatients()
{
try
{
var response = await _requestHttpService.GetAsync("/Patients");
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> GetDoctorById(Guid id)
{
try
{
var response = await _requestHttpService.GetByIdAsync("/Doctors", id);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> GetPatientById(Guid id)
{
try
{
var response = await _requestHttpService.GetByIdAsync("/Patients", id);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> UpdateDoctorProfile(
UserUpdateProfileModel userUpdateProfileModel)
{
try
{
var response = await _requestHttpService.PutAsync("/Doctors", userUpdateProfileModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> UpdatePatientProfile(
UserUpdateProfileModel userUpdateProfileModel)
{
try
{
var response = await _requestHttpService.PutAsync("/Patients", userUpdateProfileModel);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> DeleteDoctorProfile(Guid id)
{
try
{
var response = await _requestHttpService.DeleteAsync("/Doctors", id);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
public async Task<BaseResponse> DeletePatientProfile(Guid id)
{
try
{
var response = await _requestHttpService.DeleteAsync("/Patients", id);
return response;
}
catch (Exception ex)
{
return new BaseResponse
{
StatusCode = HttpStatusCodes.InternalServerError,
Data = null,
Message = ex.Message
};
}
}
}
@@ -0,0 +1,9 @@
namespace HealthcareManagerUiWebAssem.Services.RequestHttp;
public interface IRequestHttpService
{
Task<HttpResponseMessage> GetAsync(string requestUri);
Task<HttpResponseMessage> PostAsync<T>(string requestUri, T value);
Task<HttpResponseMessage> PutAsync<T>(string requestUri, T value);
Task<HttpResponseMessage> DeleteAsync(string requestUri);
}
@@ -0,0 +1,34 @@
using System.Net.Http.Json;
namespace HealthcareManagerUiWebAssem.Services.RequestHttp;
public class RequestHttpService : IRequestHttpService
{
private readonly HttpClient _httpClient;
public RequestHttpService(HttpClient httpClient, ApplicationSettings apiSettings)
{
httpClient.BaseAddress = new Uri(apiSettings.BaseAddress);
_httpClient = httpClient;
}
public async Task<HttpResponseMessage> GetAsync(string requestUri)
{
return await _httpClient.GetAsync(requestUri);
}
public async Task<HttpResponseMessage> PostAsync<T>(string requestUri, T value)
{
return await _httpClient.PostAsJsonAsync(requestUri, value);
}
public async Task<HttpResponseMessage> PutAsync<T>(string requestUri, T value)
{
return await _httpClient.PutAsJsonAsync(requestUri, value);
}
public async Task<HttpResponseMessage> DeleteAsync(string requestUri)
{
return await _httpClient.DeleteAsync(requestUri);
}
}
-56
View File
@@ -1,56 +0,0 @@
using System.Text.Json;
using HealthcareManagerUiWebAssem.Models;
using HealthcareManagerUiWebAssem.Services.Profile;
namespace HealthcareManagerUiWebAssem.Services.User;
public class UserService
{
public Guid UserId { get; private set; }
public void SetUserId(Guid id)
{
UserId = id;
}
public async Task<UserUpdateProfileModel?> InitializeProfile(string role, IProfileService profileService)
{
var response = role switch
{
"doctor" => await profileService.GetDoctorById(UserId),
"patient" => await profileService.GetPatientById(UserId),
_ => null
};
if (response.Data != null)
{
var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
if (role.Equals("doctor", StringComparison.OrdinalIgnoreCase))
{
var doctor = JsonSerializer.Deserialize<Doctor>(response.Data.ToString(), jsonOptions);
return new UserUpdateProfileModel
{
Id = doctor.Id,
Name = doctor.Name,
Email = doctor.Email,
Password = doctor.Password,
Description = doctor.Description
};
}
if (role.Equals("patient", StringComparison.OrdinalIgnoreCase))
{
var patient = JsonSerializer.Deserialize<Patient>(response.Data.ToString(), jsonOptions);
return new UserUpdateProfileModel
{
Id = patient.Id,
Name = patient.Name,
Email = patient.Email,
Password = patient.Password
};
}
}
return new UserUpdateProfileModel();
}
}
@@ -1,20 +0,0 @@
namespace HealthcareManagerUiWebAssem.Services.UserSessionInformation;
public interface IUserSessionInformation
{
Task SaveUserInformationAsync(Guid id, string role, string username, string email, string token);
Task SetIdAsync(Guid id);
Task SetRoleAsync(string role);
Task SetUsernameAsync(string username);
Task SetEmailAsync(string email);
Task SetTokenAsync(string token);
Task<Guid> GetIdAsync();
Task<string> GetRoleAsync();
Task<string> GetUsernameAsync();
Task<string> GetEmailAsync();
Task<string> GetTokenAsync();
Task RefreshTokenAsync();
}
@@ -1,114 +0,0 @@
using System.Net.Http.Json;
using System.Text.Json;
using Blazored.LocalStorage;
using HealthcareManagerUiWebAssem.Models;
using Microsoft.Extensions.Options;
namespace HealthcareManagerUiWebAssem.Services.UserSessionInformation;
public class UserSessionInformation : IUserSessionInformation
{
private readonly ILocalStorageService _localStorageService;
private readonly HttpClient _httpClient;
private readonly string _apiEndpoint;
private readonly string _apiKey;
public UserSessionInformation(ILocalStorageService localStorageService, IHttpClientFactory httpClientFactory, IOptions<ApplicationSettings> settings)
{
_localStorageService = localStorageService;
_httpClient = httpClientFactory.CreateClient();
_apiEndpoint = settings.Value.ApiEndpoint;
_apiKey = settings.Value.ApiKey ?? "NoKey";
}
public async Task SaveUserInformationAsync(Guid id, string role, string username, string email, string token)
{
await SetIdAsync(id);
await SetRoleAsync(role);
await SetUsernameAsync(username);
await SetEmailAsync(email);
await SetTokenAsync(token);
}
public async Task SetIdAsync(Guid id)
{
await _localStorageService.SetItemAsync("id", id);
}
public async Task SetRoleAsync(string role)
{
await _localStorageService.SetItemAsync("role", role);
}
public async Task SetUsernameAsync(string username)
{
await _localStorageService.SetItemAsync("username", username);
}
public async Task SetEmailAsync(string email)
{
await _localStorageService.SetItemAsync("email", email);
}
public async Task SetTokenAsync(string token)
{
await _localStorageService.SetItemAsync("jwtToken", token);
}
public async Task<Guid> GetIdAsync()
{
return await _localStorageService.GetItemAsync<Guid>("id");
}
public async Task<string> GetRoleAsync()
{
return await _localStorageService.GetItemAsync<string>("role");
}
public async Task<string> GetUsernameAsync()
{
return await _localStorageService.GetItemAsync<string>("username");
}
public async Task<string> GetEmailAsync()
{
return await _localStorageService.GetItemAsync<string>("email");
}
public async Task<string> GetTokenAsync()
{
return await _localStorageService.GetItemAsync<string>("jwtToken");
}
public async Task RefreshTokenAsync()
{
var currentToken = await GetTokenAsync();
if (string.IsNullOrWhiteSpace(currentToken)) return;
var tokenRequestModel = new TokenRefreshModel(currentToken);
var requestUri = $"{_apiEndpoint}/refresh_token";
var jsonContent = JsonContent.Create(tokenRequestModel);
var request = new HttpRequestMessage(HttpMethod.Post, requestUri)
{
Content = jsonContent
};
request.Headers.Add("ApiKey", _apiKey);
var response = await _httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode) return;
var responseContent = await response.Content.ReadAsStringAsync();
var baseResponse = JsonSerializer.Deserialize<BaseResponse>(
responseContent,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (baseResponse == null || baseResponse.StatusCode < HttpStatusCodes.BadRequest) return;
var tokenObj = JsonSerializer.Deserialize<TokenRefreshModel>(baseResponse.Data.ToString(),
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (tokenObj != null) await SetTokenAsync(tokenObj.Token);
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace HealthcareManagerUiWebAssem;
public static class UserRoles
{
public const string Admin = "Admin";
public const string Doctor = "Doctor";
public const string Patient = "Patient";
}
+22 -2
View File
@@ -1,10 +1,30 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.AspNetCore.Components.Authorization
@using HealthcareManagerUiWebAssem.Layout
@using HealthcareManagerUiWebAssem.Components
@using HealthcareManagerUiWebAssem.Models
@using HealthcareManagerUiWebAssem.Pages
@using HealthcareManagerUiWebAssem.Entities
@using HealthcareManagerUiWebAssem.Pages.Errors
@using System.Security.Claims
@using System.ComponentModel.DataAnnotations;
@using System.IdentityModel.Tokens.Jwt
@using Microsoft.JSInterop
@using HealthcareManagerUiWebAssem
@using HealthcareManagerUiWebAssem.Components.Layout
@using iText.Kernel.Pdf
@using iText.Kernel.Pdf.Canvas.Parser
@using iText.Kernel.Pdf.Canvas.Parser.Listener
@using System.Text
@using HealthcareManagerUiWebAssem.Services.AdminUserManagement
@using HealthcareManagerUiWebAssem.Services.Authentication
@using HealthcareManagerUiWebAssem.Services.PatientManagement
@using HealthcareManagerUiWebAssem.Services.DoctorManagement
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More