Start
This commit is contained in:
626
frontend/src/app/pages/doctor/components/ehr/ehr.component.ts
Normal file
626
frontend/src/app/pages/doctor/components/ehr/ehr.component.ts
Normal file
@@ -0,0 +1,626 @@
|
||||
import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MedicalRecordService, MedicalRecord, MedicalRecordRequest, VitalSigns, VitalSignsRequest, LabResultRequest } from '../../../../services/medical-record.service';
|
||||
import { UserService, PatientProfile } from '../../../../services/user.service';
|
||||
import { ModalService } from '../../../../services/modal.service';
|
||||
import { LoggerService } from '../../../../services/logger.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ehr',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule],
|
||||
templateUrl: './ehr.component.html',
|
||||
styleUrl: './ehr.component.scss'
|
||||
})
|
||||
export class EhrComponent implements OnInit, OnChanges {
|
||||
@Input() doctorId: string | null = null;
|
||||
@Input() selectedPatientId: string | null = null;
|
||||
@Input() patients: any[] = [];
|
||||
@Output() patientSelected = new EventEmitter<string>();
|
||||
@Output() dataChanged = new EventEmitter<void>();
|
||||
|
||||
// State
|
||||
showAllRecords = false;
|
||||
activeTab: 'records' | 'vitals' | 'labResults' = 'records';
|
||||
loading = false;
|
||||
error: string | null = null;
|
||||
|
||||
// Local patient selection for dropdown (separate from Input)
|
||||
localSelectedPatientId: string | null = null;
|
||||
|
||||
// Patient search
|
||||
patientSearchQuery: string = '';
|
||||
filteredPatients: any[] = [];
|
||||
|
||||
// Medical Records
|
||||
medicalRecords: MedicalRecord[] = [];
|
||||
allMedicalRecords: MedicalRecord[] = [];
|
||||
showCreateMedicalRecord = false;
|
||||
newMedicalRecord: MedicalRecordRequest = {
|
||||
patientId: '',
|
||||
doctorId: '',
|
||||
recordType: 'NOTE',
|
||||
title: '',
|
||||
content: '',
|
||||
diagnosisCode: ''
|
||||
};
|
||||
|
||||
// Vital Signs
|
||||
vitalSigns: VitalSigns[] = [];
|
||||
latestVitalSigns: VitalSigns | null = null;
|
||||
showCreateVitalSigns = false;
|
||||
newVitalSigns: VitalSignsRequest = {
|
||||
patientId: '',
|
||||
temperature: undefined,
|
||||
bloodPressureSystolic: undefined,
|
||||
bloodPressureDiastolic: undefined,
|
||||
heartRate: undefined,
|
||||
respiratoryRate: undefined,
|
||||
oxygenSaturation: undefined,
|
||||
weight: undefined,
|
||||
height: undefined,
|
||||
notes: ''
|
||||
};
|
||||
|
||||
// Lab Results
|
||||
labResults: any[] = [];
|
||||
showCreateLabResult = false;
|
||||
showUpdateLabResult = false;
|
||||
selectedLabResult: any = null;
|
||||
newLabResult: LabResultRequest = {
|
||||
patientId: undefined as any,
|
||||
doctorId: '',
|
||||
testName: '',
|
||||
resultValue: '',
|
||||
status: 'PENDING',
|
||||
orderedDate: new Date().toISOString().split('T')[0]
|
||||
};
|
||||
|
||||
// Patient Profile Modal
|
||||
selectedPatientProfile: PatientProfile | null = null;
|
||||
showPatientProfileModal = false;
|
||||
|
||||
constructor(
|
||||
private medicalRecordService: MedicalRecordService,
|
||||
private userService: UserService,
|
||||
private modalService: ModalService,
|
||||
private logger: LoggerService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.doctorId) {
|
||||
this.newMedicalRecord.doctorId = this.doctorId;
|
||||
this.newLabResult.doctorId = this.doctorId;
|
||||
this.loadAllDoctorRecords();
|
||||
}
|
||||
// Initialize local selection from Input if provided, but don't auto-load
|
||||
// This allows parent to set initial selection, but user must explicitly choose
|
||||
if (this.selectedPatientId) {
|
||||
this.localSelectedPatientId = this.selectedPatientId;
|
||||
}
|
||||
// Initialize filtered patients
|
||||
this.filterPatients();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['doctorId'] && this.doctorId) {
|
||||
this.newMedicalRecord.doctorId = this.doctorId;
|
||||
this.newLabResult.doctorId = this.doctorId;
|
||||
if (!this.allMedicalRecords.length) {
|
||||
this.loadAllDoctorRecords();
|
||||
}
|
||||
}
|
||||
// Update local selection when Input changes, but don't auto-load data
|
||||
// User must explicitly select a patient from the dropdown
|
||||
if (changes['selectedPatientId']) {
|
||||
if (this.selectedPatientId) {
|
||||
this.localSelectedPatientId = this.selectedPatientId;
|
||||
} else {
|
||||
this.localSelectedPatientId = null;
|
||||
this.showAllRecords = true;
|
||||
}
|
||||
}
|
||||
// Update filtered patients when patients list changes
|
||||
if (changes['patients']) {
|
||||
this.filterPatients();
|
||||
}
|
||||
}
|
||||
|
||||
async loadAllDoctorRecords() {
|
||||
if (!this.doctorId) return;
|
||||
try {
|
||||
this.loading = true;
|
||||
this.allMedicalRecords = await this.medicalRecordService.getMedicalRecordsByDoctorId(this.doctorId);
|
||||
} catch (e: any) {
|
||||
this.logger.error('Error loading all doctor records:', e);
|
||||
this.error = e?.response?.data?.error || 'Failed to load medical records';
|
||||
this.allMedicalRecords = [];
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async loadPatientData() {
|
||||
if (!this.localSelectedPatientId) return;
|
||||
await Promise.all([
|
||||
this.loadPatientMedicalRecords(),
|
||||
this.loadPatientVitalSigns(),
|
||||
this.loadPatientLabResults()
|
||||
]);
|
||||
}
|
||||
|
||||
async loadPatientMedicalRecords() {
|
||||
if (!this.localSelectedPatientId) return;
|
||||
try {
|
||||
this.loading = true;
|
||||
this.medicalRecords = await this.medicalRecordService.getMedicalRecordsByPatientId(this.localSelectedPatientId);
|
||||
} catch (e: any) {
|
||||
this.logger.error('Error loading medical records:', e);
|
||||
this.error = e?.response?.data?.error || 'Failed to load medical records';
|
||||
this.medicalRecords = [];
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async loadPatientVitalSigns() {
|
||||
if (!this.localSelectedPatientId) return;
|
||||
try {
|
||||
this.loading = true;
|
||||
[this.vitalSigns, this.latestVitalSigns] = await Promise.all([
|
||||
this.medicalRecordService.getVitalSignsByPatientId(this.localSelectedPatientId),
|
||||
this.medicalRecordService.getLatestVitalSignsByPatientId(this.localSelectedPatientId)
|
||||
]);
|
||||
} catch (e: any) {
|
||||
this.logger.error('Error loading vital signs:', e);
|
||||
this.error = e?.response?.data?.error || 'Failed to load vital signs';
|
||||
this.vitalSigns = [];
|
||||
this.latestVitalSigns = null;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async loadPatientLabResults() {
|
||||
if (!this.localSelectedPatientId) return;
|
||||
try {
|
||||
this.loading = true;
|
||||
this.labResults = await this.medicalRecordService.getLabResultsByPatientId(this.localSelectedPatientId);
|
||||
} catch (e: any) {
|
||||
this.logger.error('Error loading lab results:', e);
|
||||
this.error = e?.response?.data?.error || 'Failed to load lab results';
|
||||
this.labResults = [];
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
selectPatient(patientId: string | null) {
|
||||
if (!patientId) {
|
||||
// Clear selection
|
||||
this.localSelectedPatientId = null;
|
||||
this.selectedPatientId = null;
|
||||
this.showAllRecords = true;
|
||||
this.patientSelected.emit('');
|
||||
// Clear patient-specific data
|
||||
this.medicalRecords = [];
|
||||
this.vitalSigns = [];
|
||||
this.latestVitalSigns = null;
|
||||
this.labResults = [];
|
||||
return;
|
||||
}
|
||||
|
||||
// User explicitly selected a patient - load their data
|
||||
this.localSelectedPatientId = patientId;
|
||||
this.selectedPatientId = patientId;
|
||||
this.showAllRecords = false;
|
||||
this.patientSelected.emit(patientId);
|
||||
this.loadPatientData();
|
||||
}
|
||||
|
||||
async toggleRecordsView() {
|
||||
this.showAllRecords = !this.showAllRecords;
|
||||
if (this.showAllRecords) {
|
||||
await this.loadAllDoctorRecords();
|
||||
// Clear patient selection when showing all records
|
||||
this.localSelectedPatientId = null;
|
||||
} else if (this.localSelectedPatientId) {
|
||||
// Only load if patient is explicitly selected
|
||||
await this.loadPatientData();
|
||||
}
|
||||
}
|
||||
|
||||
// Medical Records Methods
|
||||
openCreateMedicalRecord() {
|
||||
this.showCreateMedicalRecord = !this.showCreateMedicalRecord;
|
||||
if (this.showCreateMedicalRecord) {
|
||||
this.newMedicalRecord = {
|
||||
patientId: this.localSelectedPatientId || '',
|
||||
doctorId: this.doctorId || '',
|
||||
recordType: 'NOTE',
|
||||
title: '',
|
||||
content: '',
|
||||
diagnosisCode: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async createMedicalRecord() {
|
||||
if (!this.newMedicalRecord.patientId || !this.newMedicalRecord.title || !this.newMedicalRecord.content) {
|
||||
this.error = 'Please fill in all required fields';
|
||||
return;
|
||||
}
|
||||
if (!this.newMedicalRecord.doctorId) {
|
||||
this.newMedicalRecord.doctorId = this.doctorId || '';
|
||||
}
|
||||
try {
|
||||
this.loading = true;
|
||||
const recordId = (this.newMedicalRecord as any).recordId;
|
||||
if (recordId) {
|
||||
await this.medicalRecordService.updateMedicalRecord(recordId, this.newMedicalRecord);
|
||||
} else {
|
||||
await this.medicalRecordService.createMedicalRecord(this.newMedicalRecord);
|
||||
}
|
||||
this.showCreateMedicalRecord = false;
|
||||
this.newMedicalRecord = {
|
||||
patientId: '',
|
||||
doctorId: this.doctorId || '',
|
||||
recordType: 'NOTE',
|
||||
title: '',
|
||||
content: '',
|
||||
diagnosisCode: ''
|
||||
};
|
||||
delete (this.newMedicalRecord as any).recordId;
|
||||
await Promise.all([
|
||||
this.localSelectedPatientId ? this.loadPatientMedicalRecords() : Promise.resolve(),
|
||||
this.loadAllDoctorRecords()
|
||||
]);
|
||||
this.dataChanged.emit();
|
||||
} catch (e: any) {
|
||||
this.logger.error('Error creating/updating medical record:', e);
|
||||
const recordId = (this.newMedicalRecord as any).recordId;
|
||||
const errorMessage = e?.response?.data?.message ||
|
||||
e?.response?.data?.error ||
|
||||
e?.message ||
|
||||
(recordId ? 'Failed to update medical record' : 'Failed to create medical record');
|
||||
this.error = errorMessage;
|
||||
// Auto-hide error after 5 seconds
|
||||
setTimeout(() => {
|
||||
this.error = null;
|
||||
}, 5000);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
editMedicalRecord(record: MedicalRecord) {
|
||||
this.newMedicalRecord = {
|
||||
patientId: record.patientId,
|
||||
doctorId: record.doctorId,
|
||||
appointmentId: record.appointmentId,
|
||||
recordType: record.recordType,
|
||||
title: record.title,
|
||||
content: record.content,
|
||||
diagnosisCode: record.diagnosisCode
|
||||
};
|
||||
this.showCreateMedicalRecord = true;
|
||||
(this.newMedicalRecord as any).recordId = record.id;
|
||||
}
|
||||
|
||||
async deleteMedicalRecord(recordId: string) {
|
||||
const confirmed = await this.modalService.confirm(
|
||||
'Are you sure you want to delete this medical record? This action cannot be undone.',
|
||||
'Delete Medical Record',
|
||||
'Delete',
|
||||
'Cancel'
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.medicalRecordService.deleteMedicalRecord(recordId);
|
||||
if (this.showAllRecords) {
|
||||
await this.loadAllDoctorRecords();
|
||||
} else if (this.localSelectedPatientId) {
|
||||
await this.loadPatientMedicalRecords();
|
||||
}
|
||||
this.dataChanged.emit();
|
||||
} catch (e: any) {
|
||||
this.error = e?.response?.data?.error || 'Failed to delete medical record';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Vital Signs Methods
|
||||
openCreateVitalSigns() {
|
||||
this.showCreateVitalSigns = !this.showCreateVitalSigns;
|
||||
if (this.showCreateVitalSigns) {
|
||||
this.newVitalSigns = {
|
||||
patientId: this.localSelectedPatientId || '',
|
||||
temperature: undefined,
|
||||
bloodPressureSystolic: undefined,
|
||||
bloodPressureDiastolic: undefined,
|
||||
heartRate: undefined,
|
||||
respiratoryRate: undefined,
|
||||
oxygenSaturation: undefined,
|
||||
weight: undefined,
|
||||
height: undefined,
|
||||
notes: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async createVitalSigns() {
|
||||
if (!this.newVitalSigns.patientId) {
|
||||
this.error = 'Please select a patient';
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.medicalRecordService.createVitalSigns(this.newVitalSigns);
|
||||
this.showCreateVitalSigns = false;
|
||||
this.newVitalSigns = {
|
||||
patientId: '',
|
||||
temperature: undefined,
|
||||
bloodPressureSystolic: undefined,
|
||||
bloodPressureDiastolic: undefined,
|
||||
heartRate: undefined,
|
||||
respiratoryRate: undefined,
|
||||
oxygenSaturation: undefined,
|
||||
weight: undefined,
|
||||
height: undefined,
|
||||
notes: ''
|
||||
};
|
||||
if (this.localSelectedPatientId) {
|
||||
await this.loadPatientVitalSigns();
|
||||
}
|
||||
this.dataChanged.emit();
|
||||
} catch (e: any) {
|
||||
this.error = e?.response?.data?.error || 'Failed to create vital signs';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteVitalSigns(vitalSignsId: string) {
|
||||
const confirmed = await this.modalService.confirm(
|
||||
'Are you sure you want to delete this vital signs record?',
|
||||
'Delete Vital Signs',
|
||||
'Delete',
|
||||
'Cancel'
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.medicalRecordService.deleteVitalSigns(vitalSignsId);
|
||||
if (this.localSelectedPatientId) {
|
||||
await this.loadPatientVitalSigns();
|
||||
}
|
||||
this.dataChanged.emit();
|
||||
} catch (e: any) {
|
||||
this.error = e?.response?.data?.error || 'Failed to delete vital signs';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Lab Results Methods
|
||||
openCreateLabResult() {
|
||||
this.showCreateLabResult = !this.showCreateLabResult;
|
||||
this.showUpdateLabResult = false;
|
||||
if (this.showCreateLabResult) {
|
||||
this.newLabResult = {
|
||||
patientId: undefined as any,
|
||||
doctorId: this.doctorId || '',
|
||||
testName: '',
|
||||
resultValue: '',
|
||||
status: 'PENDING',
|
||||
orderedDate: new Date().toISOString().split('T')[0]
|
||||
};
|
||||
if (this.localSelectedPatientId) {
|
||||
this.newLabResult.patientId = this.localSelectedPatientId as any;
|
||||
}
|
||||
delete (this.newLabResult as any).labResultId;
|
||||
}
|
||||
}
|
||||
|
||||
async createLabResult() {
|
||||
// Auto-fill patientId from context if missing
|
||||
if (!this.newLabResult.patientId) {
|
||||
if (this.localSelectedPatientId) {
|
||||
this.newLabResult.patientId = this.localSelectedPatientId as any;
|
||||
} else if (Array.isArray(this.patients) && this.patients.length === 1) {
|
||||
this.newLabResult.patientId = this.patients[0].id as any;
|
||||
}
|
||||
}
|
||||
|
||||
// If patientId is not in known patient IDs, try to resolve from userId
|
||||
if (this.newLabResult.patientId && Array.isArray(this.patients) && !this.patients.some(p => p.id === this.newLabResult.patientId)) {
|
||||
try {
|
||||
const resolved = await this.userService.getPatientIdByUserId(this.newLabResult.patientId as any);
|
||||
if (resolved) {
|
||||
this.newLabResult.patientId = resolved as any;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const missing: string[] = [];
|
||||
if (!this.newLabResult.patientId) missing.push('patient');
|
||||
if (!this.newLabResult.testName) missing.push('test name');
|
||||
if (!this.newLabResult.resultValue) missing.push('result value');
|
||||
|
||||
if (missing.length) {
|
||||
this.error = `Please fill in all required fields: ${missing.join(', ')}`;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const labResultId = (this.newLabResult as any).labResultId;
|
||||
if (labResultId) {
|
||||
await this.medicalRecordService.updateLabResult(labResultId, this.newLabResult);
|
||||
} else {
|
||||
await this.medicalRecordService.createLabResult(this.newLabResult);
|
||||
}
|
||||
this.showCreateLabResult = false;
|
||||
this.showUpdateLabResult = false;
|
||||
this.newLabResult = {
|
||||
patientId: undefined as any,
|
||||
doctorId: this.doctorId || '',
|
||||
testName: '',
|
||||
resultValue: '',
|
||||
status: 'PENDING',
|
||||
orderedDate: new Date().toISOString().split('T')[0]
|
||||
};
|
||||
delete (this.newLabResult as any).labResultId;
|
||||
if (this.localSelectedPatientId) {
|
||||
await this.loadPatientLabResults();
|
||||
}
|
||||
this.dataChanged.emit();
|
||||
} catch (e: any) {
|
||||
this.logger.error('[CreateLabResult] Error:', e);
|
||||
let errorMsg = 'Failed to create lab result';
|
||||
if (e?.response?.data) {
|
||||
if (typeof e.response.data === 'string') {
|
||||
errorMsg = e.response.data;
|
||||
} else if (e.response.data.error) {
|
||||
errorMsg = e.response.data.error;
|
||||
} else if (e.response.data.message) {
|
||||
errorMsg = e.response.data.message;
|
||||
}
|
||||
} else if (e?.message) {
|
||||
errorMsg = e.message;
|
||||
}
|
||||
this.error = errorMsg;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
editLabResult(labResult: any) {
|
||||
this.selectedLabResult = labResult;
|
||||
this.newLabResult = {
|
||||
patientId: labResult.patientId,
|
||||
doctorId: labResult.doctorId,
|
||||
testName: labResult.testName,
|
||||
resultValue: labResult.resultValue,
|
||||
referenceRange: labResult.referenceRange,
|
||||
unit: labResult.unit,
|
||||
status: labResult.status,
|
||||
orderedDate: labResult.orderedDate,
|
||||
resultDate: labResult.resultDate,
|
||||
notes: labResult.notes
|
||||
};
|
||||
this.showCreateLabResult = true;
|
||||
this.showUpdateLabResult = true;
|
||||
(this.newLabResult as any).labResultId = labResult.id;
|
||||
}
|
||||
|
||||
async deleteLabResult(labResultId: string) {
|
||||
const confirmed = await this.modalService.confirm(
|
||||
'Are you sure you want to delete this lab result?',
|
||||
'Delete Lab Result',
|
||||
'Delete',
|
||||
'Cancel'
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.medicalRecordService.deleteLabResult(labResultId);
|
||||
if (this.localSelectedPatientId) {
|
||||
await this.loadPatientLabResults();
|
||||
}
|
||||
this.dataChanged.emit();
|
||||
} catch (e: any) {
|
||||
this.error = e?.response?.data?.error || 'Failed to delete lab result';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
formatDate(dateString: string): string {
|
||||
if (!dateString) return 'N/A';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
formatDateTime(dateString: string): string {
|
||||
if (!dateString) return 'N/A';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
getCurrentRecords() {
|
||||
return this.showAllRecords ? this.allMedicalRecords : this.medicalRecords;
|
||||
}
|
||||
|
||||
isUpdatingMedicalRecord(): boolean {
|
||||
return !!(this.newMedicalRecord as any).recordId;
|
||||
}
|
||||
|
||||
isUpdatingLabResult(): boolean {
|
||||
return !!(this.newLabResult as any).labResultId;
|
||||
}
|
||||
|
||||
cancelMedicalRecordForm() {
|
||||
this.showCreateMedicalRecord = false;
|
||||
delete (this.newMedicalRecord as any).recordId;
|
||||
}
|
||||
|
||||
cancelLabResultForm() {
|
||||
this.showCreateLabResult = false;
|
||||
this.showUpdateLabResult = false;
|
||||
delete (this.newLabResult as any).labResultId;
|
||||
}
|
||||
|
||||
async viewPatientProfile(patientId: string) {
|
||||
try {
|
||||
this.selectedPatientProfile = await this.userService.getPatientProfileById(patientId);
|
||||
this.showPatientProfileModal = true;
|
||||
} catch (e: any) {
|
||||
this.error = e?.message || 'Failed to load patient profile';
|
||||
this.logger.error('Failed to load patient profile:', e);
|
||||
}
|
||||
}
|
||||
|
||||
closePatientProfileModal() {
|
||||
this.showPatientProfileModal = false;
|
||||
this.selectedPatientProfile = null;
|
||||
}
|
||||
|
||||
filterPatients() {
|
||||
if (!this.patientSearchQuery || this.patientSearchQuery.trim() === '') {
|
||||
this.filteredPatients = this.patients || [];
|
||||
return;
|
||||
}
|
||||
|
||||
const query = this.patientSearchQuery.toLowerCase().trim();
|
||||
this.filteredPatients = (this.patients || []).filter(patient => {
|
||||
const firstName = (patient.firstName || '').toLowerCase();
|
||||
const lastName = (patient.lastName || '').toLowerCase();
|
||||
const fullName = `${firstName} ${lastName}`.trim();
|
||||
const email = (patient.email || '').toLowerCase();
|
||||
|
||||
return firstName.includes(query) ||
|
||||
lastName.includes(query) ||
|
||||
fullName.includes(query) ||
|
||||
email.includes(query);
|
||||
});
|
||||
}
|
||||
|
||||
onPatientSearchChange() {
|
||||
this.filterPatients();
|
||||
}
|
||||
|
||||
clearPatientSearch() {
|
||||
this.patientSearchQuery = '';
|
||||
this.filterPatients();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user