705 lines
23 KiB
C#
705 lines
23 KiB
C#
using System.Collections.ObjectModel;
|
|
using LSFE.MobApp.Contracts;
|
|
using LSFE.MobApp.Entities.Doctor;
|
|
using LSFE.MobApp.Entities.Location;
|
|
using LSFE.MobApp.Entities.Planning;
|
|
using LSFE.MobApp.Helpers;
|
|
using LSFE.MobApp.Services;
|
|
using LSFE.MobApp.ViewModels.Common;
|
|
using Microsoft.Extensions.Configuration;
|
|
using System.Windows.Input;
|
|
using LSFE.MobApp.Views.CoveragePlan;
|
|
using System.ComponentModel;
|
|
using LSFE.MobApp.Pages.CoveragePlan;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace LSFE.MobApp.ViewModels.Coverage;
|
|
|
|
public class DoctorsVM : BaseDoctorVM
|
|
{
|
|
#region Api client
|
|
private readonly IApiClient<Doctor> _doctorApiClient;
|
|
private readonly IApiClient<Institution> _institutionApiClient;
|
|
#endregion
|
|
|
|
#region Local repository
|
|
private readonly Repository<Institution> _institutionRepository;
|
|
private readonly Repository<MRRawPlan> _mrRawPlanRepository;
|
|
#endregion
|
|
|
|
#region ObservableCollection & List
|
|
private ObservableCollection<DoctorVM> _doctors;
|
|
private ObservableCollection<DoctorVM> _filteredDoctors;
|
|
public ObservableCollection<DoctorVM> Doctors
|
|
{
|
|
get => _doctors;
|
|
set
|
|
{
|
|
_doctors = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
public ObservableCollection<DoctorVM> FilteredDoctors
|
|
{
|
|
get => _filteredDoctors;
|
|
set
|
|
{
|
|
_filteredDoctors = value;
|
|
OnPropertyChanged();
|
|
OnPropertyChanged(nameof(IsEmpty));
|
|
OnPropertyChanged(nameof(ResultsCountText));
|
|
}
|
|
}
|
|
private CancellationTokenSource _searchCancellationTokenSource;
|
|
private List<Institution> _institutions;
|
|
#endregion
|
|
|
|
#region Service & configuration
|
|
private readonly ISyncService _syncService;
|
|
private readonly IConfiguration _configuration;
|
|
private readonly INavigationService _navigationService;
|
|
private readonly AddressService _addressService;
|
|
#endregion
|
|
public DoctorsVM(
|
|
IApiClientFactory apiClientFactory,
|
|
ISyncService syncService,
|
|
INavigationService navigationService,
|
|
Repository<Doctor> doctorRepository,
|
|
Repository<Institution> institutionRepository,
|
|
Repository<MRRawPlan> mrRawPlanRepository,
|
|
IConfiguration configuration,
|
|
AddressService addressService)
|
|
: base(doctorRepository, syncService, addressService, configuration)
|
|
{
|
|
_doctorApiClient = apiClientFactory.CreateClient<Doctor>("DoctorMgmt/GetMyDoctor");
|
|
_institutionApiClient = apiClientFactory.CreateClient<Institution>("Maintenance/institutions");
|
|
_syncService = syncService;
|
|
_configuration = configuration;
|
|
_addressService = addressService;
|
|
_navigationService = navigationService;
|
|
_institutionRepository = institutionRepository;
|
|
_mrRawPlanRepository= mrRawPlanRepository;
|
|
|
|
Doctors = new ObservableCollection<DoctorVM>();
|
|
FilteredDoctors = new ObservableCollection<DoctorVM>();
|
|
_institutions = new List<Institution>();
|
|
|
|
StatusFilterOptions = new List<string> { "All Statuses", "Pending", "Started", "Completed", "Reschedule", "Missed" };
|
|
InstitutionFilterOptions = new List<string> { "All Institutions" };
|
|
|
|
_searchText = string.Empty;
|
|
_selectedStatusFilter = "All Statuses";
|
|
_selectedInstitutionFilter = "All Institutions";
|
|
|
|
// Commands
|
|
AddDoctorCommand = new Command(async () => await AddDoctor(), () => CanInteract);
|
|
ViewDoctorCommand = new Command<DoctorVM>(async (doctor) => await ViewDoctor(doctor), (doctor) => CanInteract);
|
|
EditDoctorCommand = new Command<DoctorVM>(async (doctor) => await EditDoctor(doctor), (doctor) => CanInteract);
|
|
DeleteDoctorCommand = new Command<DoctorVM>(async (doctor) => await DeleteDoctor(doctor), (doctor) => CanInteract);
|
|
CoverageCommand = new Command<DoctorVM>(async (doctor) => await Coverage(doctor), (doctor) => CanInteract);
|
|
SignOutCommand = new Command(async (doctor) => await LogOut());
|
|
|
|
RescheduleCommand = new Command<DoctorVM>(async doctor =>
|
|
{
|
|
await ShowReason.ShowReasonModal("Reschedule Reason", async reason =>
|
|
{
|
|
await Reschedule(doctor.Doctor.DoctorId, reason);
|
|
});
|
|
}, doctor => CanInteract);
|
|
|
|
MissedCommand = new Command<DoctorVM>(async doctor =>
|
|
{
|
|
await ShowReason.ShowReasonModal("Missed Reason", async reason =>
|
|
{
|
|
await Missed(doctor.Doctor.DoctorId, reason);
|
|
});
|
|
}, doctor => CanInteract);
|
|
|
|
ClearSearchCommand = new Command(() => SearchText = string.Empty);
|
|
}
|
|
|
|
private async Task LogOut()
|
|
{
|
|
await _navigationService.NavigateToLoginPageAsync();
|
|
}
|
|
#region Properties
|
|
private bool _forAddressTranslation { get; set; }
|
|
private string _searchText;
|
|
private bool _isLoading;
|
|
private bool _isRefreshing;
|
|
private string _selectedStatusFilter = "All Statuses";
|
|
private string _selectedInstitutionFilter = "All Institutions";
|
|
private List<string> _institutionFilterOptions;
|
|
|
|
public List<string> InstitutionFilterOptions
|
|
{
|
|
get => _institutionFilterOptions;
|
|
set
|
|
{
|
|
_institutionFilterOptions = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
public string SelectedInstitutionFilter
|
|
{
|
|
get => _selectedInstitutionFilter;
|
|
set
|
|
{
|
|
_selectedInstitutionFilter = value;
|
|
OnPropertyChanged();
|
|
ApplyFilters();
|
|
}
|
|
}
|
|
|
|
private bool _isProcessing;
|
|
public bool CanInteract => !IsLoading && !IsProcessing;
|
|
public bool IsProcessing
|
|
{
|
|
get => _isProcessing;
|
|
set
|
|
{
|
|
_isProcessing = value;
|
|
OnPropertyChanged();
|
|
OnPropertyChanged(nameof(CanInteract));
|
|
}
|
|
}
|
|
|
|
private bool _isFiltering;
|
|
public bool IsFiltering
|
|
{
|
|
get => _isFiltering;
|
|
set
|
|
{
|
|
_isFiltering = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
public string SearchText
|
|
{
|
|
get => _searchText;
|
|
set
|
|
{
|
|
_searchText = value;
|
|
OnPropertyChanged();
|
|
OnPropertyChanged(nameof(HasSearchText));
|
|
|
|
_searchCancellationTokenSource?.Cancel();
|
|
_searchCancellationTokenSource = new CancellationTokenSource();
|
|
|
|
var token = _searchCancellationTokenSource.Token;
|
|
Task.Run(async () =>
|
|
{
|
|
await Task.Delay(300, token);
|
|
if (!token.IsCancellationRequested)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() => ApplyFilters());
|
|
}
|
|
}, token);
|
|
}
|
|
}
|
|
public bool HasSearchText => !string.IsNullOrWhiteSpace(SearchText);
|
|
public string SelectedStatusFilter
|
|
{
|
|
get => _selectedStatusFilter;
|
|
set
|
|
{
|
|
_selectedStatusFilter = value;
|
|
OnPropertyChanged();
|
|
ApplyFilters();
|
|
}
|
|
}
|
|
|
|
public List<string> StatusFilterOptions { get; }
|
|
|
|
public bool IsLoading
|
|
{
|
|
get => _isLoading;
|
|
set
|
|
{
|
|
_isLoading = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
public bool IsEmpty => !IsLoading && (FilteredDoctors == null || FilteredDoctors.Count == 0);
|
|
public string ResultsCountText => $"Showing {FilteredDoctors?.Count ?? 0} of {Doctors?.Count ?? 0} doctors";
|
|
#endregion
|
|
|
|
#region Status Update Handler (from Base Class)
|
|
/// <summary>
|
|
/// Automatically called when any doctor status is updated anywhere in the app
|
|
/// </summary>
|
|
protected override async void OnDoctorStatusUpdated(int doctorId)
|
|
{
|
|
var doctorVM = Doctors.FirstOrDefault(d => d.DoctorId == doctorId);
|
|
if (doctorVM != null)
|
|
{
|
|
var updated = await RefreshDoctorFromRepositoryAsync(doctorId);
|
|
if (updated != null)
|
|
{
|
|
doctorVM.Doctor.Status = updated.Status;
|
|
doctorVM.RefreshStatus();
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Commands
|
|
public ICommand RescheduleCommand { get; }
|
|
public ICommand MissedCommand { get; }
|
|
public ICommand AddDoctorCommand { get; }
|
|
public ICommand ViewDoctorCommand { get; }
|
|
public ICommand EditDoctorCommand { get; }
|
|
public ICommand DeleteDoctorCommand { get; }
|
|
public ICommand ClearSearchCommand { get; }
|
|
public ICommand CoverageCommand { get; }
|
|
public ICommand SignOutCommand { get; }
|
|
#endregion
|
|
|
|
#region Status Update Methods
|
|
private async Task UpdateDoctorAndPlanAsync(int doctorId, byte status, string reason)
|
|
{
|
|
var today = DateTime.Today;
|
|
var tomorrow = today.AddDays(1);
|
|
|
|
try
|
|
{
|
|
var (locationResult, isReadableAddress) = await _addressService.GetCurrentLocationAsync();
|
|
|
|
var doctor = await _doctorRepository.FirstOrDefaultAsync(d => d.DoctorId == doctorId);
|
|
if (doctor == null)
|
|
{
|
|
await Application.Current.MainPage.DisplayAlert("Error", "Doctor not found.", "OK");
|
|
return;
|
|
}
|
|
|
|
doctor.Status = status;
|
|
await _doctorRepository.UpdateAsync(doctor);
|
|
|
|
var plan = await _mrRawPlanRepository.FirstOrDefaultAsync(
|
|
p => p.DoctorId == doctorId &&
|
|
p.CallDate >= today &&
|
|
p.CallDate < tomorrow);
|
|
|
|
if (plan == null)
|
|
{
|
|
await Application.Current.MainPage.DisplayAlert("Error", "No plan found for today.", "OK");
|
|
return;
|
|
}
|
|
|
|
string successMessage;
|
|
|
|
if (status == 3) // Reschedule
|
|
{
|
|
plan.IsReschedule = true;
|
|
plan.IsMissed = false;
|
|
plan.RescheduleReason = reason;
|
|
plan.MissedReason = null;
|
|
successMessage = "Schedule has been successfully rescheduled.";
|
|
}
|
|
else // Missed
|
|
{
|
|
plan.IsMissed = true;
|
|
plan.IsReschedule = false;
|
|
plan.MissedReason = reason;
|
|
plan.RescheduleReason = null;
|
|
successMessage = "Schedule has been marked as missed.";
|
|
}
|
|
if (isReadableAddress)
|
|
_forAddressTranslation = false;
|
|
else
|
|
_forAddressTranslation = true;
|
|
|
|
plan.Latitude = locationResult.Latitude.ToString() ?? "0";
|
|
plan.Longitude = locationResult.Longitude.ToString() ?? "0";
|
|
plan.Location = locationResult.Address ?? "N/A";
|
|
|
|
await _mrRawPlanRepository.UpdateAsync(plan);
|
|
|
|
// BROADCAST the status update to ALL ViewModels
|
|
DoctorStatusHelper.BroadcastStatusUpdate(doctorId);
|
|
|
|
await Application.Current.MainPage.DisplayAlert("Success", successMessage, "OK");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
|
|
}
|
|
}
|
|
|
|
private async Task Reschedule(int doctorId, string reason)
|
|
{
|
|
if (await IsCompleted())
|
|
return;
|
|
await UpdateDoctorAndPlanAsync(doctorId, status: 3, reason);
|
|
}
|
|
|
|
private async Task Missed(int doctorId, string reason)
|
|
{
|
|
if (await IsCompleted())
|
|
return;
|
|
await UpdateDoctorAndPlanAsync(doctorId, status: 4, reason);
|
|
}
|
|
|
|
private async Task<bool> IsCompleted()
|
|
{
|
|
if (FilteredDoctors[0].StatusText == "Completed")
|
|
{
|
|
await UtilityVM.ShowAlert("Status Update",
|
|
$"Action failed: Dr. {Doctors[0].FullName}'s status is already marked as Completed.");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
public void RefreshData()
|
|
{
|
|
// Guard: skip if already loading or refreshing
|
|
if (IsLoading || _isRefreshing) return;
|
|
|
|
_isRefreshing = true;
|
|
_ = LoadDataAsync();
|
|
}
|
|
#endregion
|
|
|
|
#region Data Loading & Filtering
|
|
private async Task LoadDataAsync()
|
|
{
|
|
try
|
|
{
|
|
IsLoading = true;
|
|
|
|
_institutions = await _institutionRepository.GetAllAsync();
|
|
|
|
if (_institutions != null && _institutions.Any())
|
|
{
|
|
InstitutionFilterOptions = new List<string> { "All Institutions" }
|
|
.Concat(_institutions.Select(i => i.InstitutionName)
|
|
.Where(n => !string.IsNullOrEmpty(n))
|
|
.OrderBy(n => n))
|
|
.ToList();
|
|
}
|
|
else
|
|
{
|
|
InstitutionFilterOptions = new List<string> { "All Institutions" };
|
|
}
|
|
|
|
var today = DateTime.Today;
|
|
var tomorrow = today.AddDays(1);
|
|
|
|
var doctors = await _doctorRepository.GetAllAsync();
|
|
|
|
// FILTER → Only today's doctors
|
|
var todayDoctors = doctors
|
|
.Where(a => a.CreatedDate >= today && a.CreatedDate < tomorrow)
|
|
.OrderByDescending(a => a.CreatedDate)
|
|
.ToList();
|
|
|
|
Doctors.Clear();
|
|
|
|
// Load only today's doctors
|
|
foreach (var doctor in todayDoctors)
|
|
{
|
|
var institution = _institutions?.FirstOrDefault(i => i.InstitutionId == doctor.InstitutionId);
|
|
if (institution != null)
|
|
{
|
|
doctor.InstitutionName = institution.InstitutionName;
|
|
}
|
|
|
|
Doctors.Add(new DoctorVM(doctor));
|
|
}
|
|
|
|
ApplyFilters();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await UtilityVM.ShowAlert("Error", $"Failed to load doctors: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
IsLoading = false;
|
|
_isRefreshing = false;
|
|
}
|
|
}
|
|
|
|
private async void ApplyFilters()
|
|
{
|
|
try
|
|
{
|
|
IsFiltering = true;
|
|
|
|
var filtered = await Task.Run(() =>
|
|
{
|
|
var result = Doctors.AsEnumerable();
|
|
|
|
if (!string.IsNullOrWhiteSpace(SearchText))
|
|
{
|
|
var searchLower = SearchText.ToLower();
|
|
result = result.Where(d =>
|
|
d.FullName.ToLower().Contains(searchLower) ||
|
|
(d.EmailAddress?.ToLower().Contains(searchLower) ?? false) ||
|
|
(d.PhoneNo?.ToLower().Contains(searchLower) ?? false) ||
|
|
(d.LicenseNo?.ToLower().Contains(searchLower) ?? false) ||
|
|
(d.InstitutionName?.ToLower().Contains(searchLower) ?? false));
|
|
}
|
|
|
|
if (SelectedStatusFilter != "All Statuses")
|
|
{
|
|
result = result.Where(d => d.StatusText == SelectedStatusFilter);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(SelectedInstitutionFilter) && SelectedInstitutionFilter != "All Institutions")
|
|
{
|
|
result = result.Where(d => d.InstitutionName == SelectedInstitutionFilter);
|
|
}
|
|
|
|
return result.ToList();
|
|
});
|
|
|
|
FilteredDoctors = new ObservableCollection<DoctorVM>(filtered);
|
|
}
|
|
finally
|
|
{
|
|
IsFiltering = false;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region CRUD Operations
|
|
private async Task Coverage(DoctorVM doctor)
|
|
{
|
|
if (doctor == null || IsProcessing) return;
|
|
var doctorEntities = new Entities.Doctor.Doctor()
|
|
{
|
|
Status=doctor.Status,
|
|
FirstName=doctor.FullName,
|
|
DoctorId = doctor.DoctorId,
|
|
SpecializationName=doctor.Specialization,
|
|
InstitutionName = doctor.InstitutionName,
|
|
LicenseNo=doctor.LicenseNo,
|
|
MaxVisit=doctor.MaxVisit,
|
|
BirthDate=doctor.BirthDate,
|
|
MRRawPlanId=doctor.MRRawPlanId
|
|
};
|
|
try
|
|
{
|
|
IsLoading = true;
|
|
((Command<DoctorVM>)CoverageCommand).ChangeCanExecute();
|
|
|
|
var viewVm = new ActualCoverageVM(
|
|
doctorEntities,
|
|
_doctorRepository,
|
|
_mrRawPlanRepository,
|
|
_syncService,
|
|
_addressService,
|
|
_configuration);
|
|
var viewPage = new ActualCoveragePage(viewVm);
|
|
|
|
await Application.Current.MainPage.Navigation.PushAsync(viewPage);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await UtilityVM.ShowAlert("Error", $"Failed to view doctor: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
IsLoading = false;
|
|
((Command<DoctorVM>)CoverageCommand).ChangeCanExecute();
|
|
}
|
|
}
|
|
private async Task AddDoctor()
|
|
{
|
|
if (IsProcessing) return; // Prevent double-tap
|
|
|
|
try
|
|
{
|
|
IsProcessing = true;
|
|
((Command)AddDoctorCommand).ChangeCanExecute(); // Disable button
|
|
|
|
var addVm = new AddEditDoctorVM(_doctorApiClient, _institutionApiClient, _institutions);
|
|
var addPage = new AddEditDoctorPage(addVm);
|
|
|
|
MessagingCenter.Subscribe<AddEditDoctorVM>(this, "DoctorSaved", async (sender) =>
|
|
{
|
|
await LoadDataAsync();
|
|
MessagingCenter.Unsubscribe<AddEditDoctorVM>(this, "DoctorSaved");
|
|
});
|
|
|
|
//await _navigation.PushModalAsync(new NavigationPage(addPage));
|
|
await Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(addPage));
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await UtilityVM.ShowAlert("Error", $"Failed to open add page: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
IsProcessing = false;
|
|
((Command)AddDoctorCommand).ChangeCanExecute(); // Re-enable button
|
|
}
|
|
}
|
|
private async Task ViewDoctor(DoctorVM doctor)
|
|
{
|
|
if (doctor == null || IsProcessing) return;
|
|
|
|
try
|
|
{
|
|
IsProcessing = true;
|
|
((Command<DoctorVM>)ViewDoctorCommand).ChangeCanExecute();
|
|
|
|
var viewVm = new ViewDoctorVM(doctor.Doctor);
|
|
var viewPage = new ViewDoctorPage(viewVm);
|
|
await Application.Current.MainPage.Navigation.PushAsync(viewPage);
|
|
// await _navigation.PushAsync(viewPage);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await UtilityVM.ShowAlert("Error", $"Failed to view doctor: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
IsProcessing = false;
|
|
((Command<DoctorVM>)ViewDoctorCommand).ChangeCanExecute();
|
|
}
|
|
}
|
|
private async Task EditDoctor(DoctorVM doctor)
|
|
{
|
|
if (doctor == null || IsProcessing) return;
|
|
|
|
try
|
|
{
|
|
IsProcessing = true;
|
|
((Command<DoctorVM>)EditDoctorCommand).ChangeCanExecute();
|
|
|
|
var editVm = new AddEditDoctorVM(_doctorApiClient, _institutionApiClient, _institutions, doctor.Doctor);
|
|
var editPage = new AddEditDoctorPage(editVm);
|
|
|
|
MessagingCenter.Subscribe<AddEditDoctorVM>(this, "DoctorSaved", async (sender) =>
|
|
{
|
|
await LoadDataAsync();
|
|
MessagingCenter.Unsubscribe<AddEditDoctorVM>(this, "DoctorSaved");
|
|
});
|
|
await Application.Current.MainPage.Navigation.PushAsync(editPage);
|
|
//await _navigation.PushModalAsync(new NavigationPage(editPage));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await UtilityVM.ShowAlert("Error", $"Failed to edit doctor: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
IsProcessing = false;
|
|
((Command<DoctorVM>)EditDoctorCommand).ChangeCanExecute();
|
|
}
|
|
}
|
|
private async Task DeleteDoctor(DoctorVM doctor)
|
|
{
|
|
if (doctor == null || IsProcessing) return;
|
|
|
|
try
|
|
{
|
|
IsProcessing = true;
|
|
((Command<DoctorVM>)DeleteDoctorCommand).ChangeCanExecute();
|
|
|
|
var confirm = await UtilityVM.ShowConfirm(
|
|
"Confirm Delete",
|
|
$"Are you sure you want to delete Dr. {doctor.FullName}?",
|
|
"Delete",
|
|
"Cancel");
|
|
|
|
if (!confirm) return;
|
|
|
|
var response = await _doctorApiClient.DeleteAsync(doctor.Doctor.Id);
|
|
|
|
if (response.Success)
|
|
{
|
|
Doctors.Remove(doctor);
|
|
ApplyFilters();
|
|
await UtilityVM.ShowAlert("Success", "Doctor deleted successfully");
|
|
}
|
|
else
|
|
{
|
|
await UtilityVM.ShowAlert("Error", response.Message ?? "Failed to delete doctor");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await UtilityVM.ShowAlert("Error", $"Failed to delete doctor: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
IsProcessing = false;
|
|
((Command<DoctorVM>)DeleteDoctorCommand).ChangeCanExecute();
|
|
}
|
|
}
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_searchCancellationTokenSource?.Cancel();
|
|
_searchCancellationTokenSource?.Dispose();
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
#endregion
|
|
}
|
|
/// <summary>
|
|
/// Doctor View Model for UI binding - Now using centralized status helper
|
|
/// </summary>
|
|
public class DoctorVM : INotifyPropertyChanged
|
|
{
|
|
public Entities.Doctor.Doctor Doctor { get; }
|
|
|
|
public DoctorVM(Entities.Doctor.Doctor doctor)
|
|
{
|
|
Doctor = doctor ?? throw new ArgumentNullException(nameof(doctor));
|
|
}
|
|
|
|
#region Doctor Information
|
|
public int DoctorId => Doctor.DoctorId;
|
|
public Guid MRRawPlanId => Doctor.MRRawPlanId;
|
|
public string FullName => $"Dr. {Doctor.FirstName} {Doctor.MiddleInitial} {Doctor.LastName}".Replace(" ", " ").Trim();
|
|
public string EmailAddress => Doctor.EmailAddress ?? "N/A";
|
|
public string PhoneNo => Doctor.PhoneNo ?? "N/A";
|
|
public string LicenseNo => Doctor.LicenseNo ?? "N/A";
|
|
public DateTime BirthDate => Doctor.BirthDate;
|
|
public byte MaxVisit => Doctor.MaxVisit;
|
|
public string Specialization => Doctor.SpecializationName ?? "General";
|
|
public string InstitutionName => Doctor.InstitutionName ?? "No Institution";
|
|
public bool HasInstitution => !string.IsNullOrEmpty(Doctor.InstitutionName);
|
|
#endregion
|
|
|
|
#region Status Changes
|
|
public void UpdateDoctorModel(Entities.Doctor.Doctor updated)
|
|
{
|
|
if (updated == null) return;
|
|
Doctor.Status = updated.Status;
|
|
RefreshStatus();
|
|
}
|
|
|
|
public void RefreshStatus()
|
|
{
|
|
OnPropertyChanged(nameof(StatusText));
|
|
OnPropertyChanged(nameof(StatusBackgroundColor));
|
|
OnPropertyChanged(nameof(StatusTextColor));
|
|
}
|
|
#endregion
|
|
|
|
#region Status Properties - Using Centralized Helper
|
|
public string StatusText => DoctorStatusHelper.GetStatusText(Doctor.Status);
|
|
public byte Status=> Doctor.Status;
|
|
public Color StatusBackgroundColor => DoctorStatusHelper.GetStatusBackgroundColor(Doctor.Status);
|
|
|
|
public Color StatusTextColor => DoctorStatusHelper.GetStatusTextColor(Doctor.Status);
|
|
#endregion
|
|
|
|
#region INotifyPropertyChanged
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
#endregion
|
|
} |