From 48d6a3fae83ef6029118c3a9f6f06340b98b9936 Mon Sep 17 00:00:00 2001 From: Sandipan Mitra <sandipan.mitra@sentientgeeks.com> Date: Thu, 6 Feb 2025 15:33:27 +0530 Subject: [PATCH] design changes --- .../all-patients/all-patients.component.html | 345 ++++++++++-------- .../all-patients/all-patients.component.scss | 9 + .../all-patients/all-patients.component.ts | 2 +- .../patient-record.component.html | 308 +++++++--------- .../patient-record.component.scss | 3 +- .../patient-record.component.ts | 35 +- .../Patients/PatientAppService.cs | 4 +- 7 files changed, 368 insertions(+), 338 deletions(-) diff --git a/angular/src/app/patients/all-patients/all-patients.component.html b/angular/src/app/patients/all-patients/all-patients.component.html index b79aacd..3aadf3e 100644 --- a/angular/src/app/patients/all-patients/all-patients.component.html +++ b/angular/src/app/patients/all-patients/all-patients.component.html @@ -1,4 +1,4 @@ -<div> +<!-- <div> <p-table #dt2 dataKey="id" [value]="patients" [paginator]="true" [rows]="10" [totalRecords]="totalRecords" [lazy]="true" (onLazyLoad)="loadPatient($event)" [rowsPerPageOptions]="[10, 20, 50]" [responsiveLayout]="'scroll'" [globalFilterFields]="['id', 'name', 'status']" @@ -74,169 +74,216 @@ </ng-template> </p-table> <span>Total Records: {{totalRecords}}</span> +</div> --> +<div class="container-fluid py-3"> + <div class="card shadow-sm p-3"> + <div class="d-flex justify-content-between align-items-center mb-3"> + <h2 class="mb-0">Patient List</h2> + <div class="d-flex align-items-center gap-2"> + <button *ngIf="createpermission" class="btn btn-success btn-sm" (click)="openNewPatientDialog()"> + <i class="pi pi-plus-circle"></i> + </button> + <button class="btn btn-warning btn-sm" (click)="exportPatient()"> + <i class="pi pi-download"></i> + </button> + <div class="input-group"> + <span class="input-group-text"><i class="pi pi-search"></i></span> + <input pInputText type="text" class="form-control" + (input)="dt2.filterGlobal($event.target.value, 'contains')" [(ngModel)]="globalFilter" + placeholder="Search keyword" /> + </div> + </div> + </div> + + <p-table #dt2 dataKey="id" [value]="patients" [paginator]="true" [rows]="10" [totalRecords]="totalRecords" + [lazy]="true" (onLazyLoad)="loadPatient($event)" [rowsPerPageOptions]="[10, 20, 50]" + styleClass="p-datatable-gridlines" [responsiveLayout]="'scroll'" + [globalFilterFields]="['id', 'name', 'status']" [filters]="{ global: { value: '', matchMode: 'contains' } }" + class="table table-hover table-responsive-md"> + + <ng-template pTemplate="header"> + <tr class="table-dark"> + <th class="hidden" pSortableColumn="id">Patient ID <p-sortIcon field="id" /></th> + <th pSortableColumn="name">Full Name <p-sortIcon field="name" /></th> + <th pSortableColumn="gender">Gender <p-sortIcon field="gender" /></th> + <th pSortableColumn="admissionDate">Date of Admission <p-sortIcon field="admissionDate" /></th> + <th pSortableColumn="bloodGroup">Blood Group <p-sortIcon field="bloodGroup" /></th> + <th>Mobile</th> + <th>Email</th> + <th pSortableColumn="status">Status <p-sortIcon field="status" /></th> + <th>Actions</th> + </tr> + </ng-template> + + <ng-template pTemplate="body" let-patient> + <tr> + <td class="hidden">{{ patient.id }}</td> + <td>{{ patient.name }}</td> + <td> + <span class="badge" [ngClass]="patient.gender === 1 ? 'bg-primary' : 'bg-pink'"> + {{ gender[patient.gender] }} + </span> + </td> + <td>{{ patient.admissionDate | date }}</td> + <td>{{ patient.bloodGroup }}</td> + <td>{{ patient.mobile }}</td> + <td>{{ patient.email }}</td> + <td> + <span class="badge" + [ngClass]="patient.status === 1 ? 'bg-success' : (patient.status === 2 ? 'bg-primary':'bg-danger')"> + {{ status[patient.status] }} + </span> + </td> + <td class="d-flex gap-1"> + <button *ngIf="createpermission" class="btn btn-success btn-sm" + (click)="addnewrecord(patient.id)"> + <i class="pi pi-arrow-right"></i> + </button> + <button *ngIf="editpermission" class="btn btn-warning btn-sm" (click)="editPatient(patient)"><i + class="pi pi-pencil"></i></button> + <button *ngIf="deletepermission" class="btn btn-danger btn-sm" + (click)="deletePatient(patient.id)"><i class="pi pi-trash"></i></button> + </td> + </tr> + </ng-template> + + <ng-template pTemplate="emptymessage"> + <tr> + <td colspan="10" class="text-center">No Patients found.</td> + </tr> + </ng-template> + </p-table> + <div class="text-end mt-2 fw-bold">Total Records: {{ totalRecords }}</div> + </div> </div> + <div> <p-dialog *ngIf="patientDialog" header="{{patientDialogTitle}}" [(visible)]="patientDialog" [modal]="true" - [closable]="true" [style]="{width: '85%', height: '100%'}"> + [closable]="true" [style]="{width: '80%', height: 'auto'}" class="modern-dialog"> <form #patientrecord="ngForm" (ngSubmit)="savePatient(patientrecord)"> - <div class="p-fluid"> - <div class="p-grid"> - <!-- Full Name --> - <div class="p-col-6"> - <div class="field"> - <label for="name">Full Name</label> - <input id="name" name="name" type="text" pInputText [(ngModel)]="selectedPatient.name" - placeholder="Enter full patient name" required #name="ngModel" /> - <small *ngIf="name.invalid && name.touched" class="p-error">Full Name is required</small> - </div> - <div class="field"> - <label for="image">Profile Image</label> - <input type="file" id="image" name="image" accept=".jpg,.png" - (change)="profileimageupload($event)"/> - </div> - <small *ngIf="error !== ''" class="p-error">{{error}}</small> - <!-- Progress Bar --> - <div *ngIf="uploadProgress > 0"> - <p>Uploading... {{ uploadProgress }}%</p> - <progress [value]="uploadProgress" max="100"></progress> - </div> - <small *ngIf="imgpath !== ''">{{imgpath}} <i class="pi pi-image"></i></small> + <div class="p-fluid grid"> + <!-- Full Name & Profile Image --> + <div class="col-6"> + <div class="field"> + <label for="name"><i class="pi pi-user"></i> Full Name</label> + <input id="name" name="name" type="text" pInputText [(ngModel)]="selectedPatient.name" + placeholder="Enter full patient name" required #name="ngModel" /> + <small *ngIf="name.invalid && name.touched" class="p-error">Full Name is required</small> </div> - - <!-- Mobile --> - <div class="p-col-6"> - <div class="field"> - <label for="mobile">Mobile</label> - <input id="mobile" name="mobile" type="text" pInputText [(ngModel)]="selectedPatient.mobile" - placeholder="Enter mobile number" maxlength="10" required pattern="[0-9]{10}" - #mobile="ngModel" /> - <small *ngIf="mobile.invalid && mobile.touched" class="p-error"> - Mobile is required and must be 10 digits - </small> - </div> + <div class="field"> + <label for="image"><i class="pi pi-image"></i> Profile Image</label> + <input type="file" id="image" name="image" accept=".jpg,.png" + (change)="profileimageupload($event)" /> </div> - - <!-- Address --> - <div class="p-col-6"> - <div class="field"> - <label for="address">Address</label> - <input id="address" name="address" type="text" pInputText - [(ngModel)]="selectedPatient.address" placeholder="Enter address" required - #address="ngModel" /> - <small *ngIf="address.invalid && address.touched" class="p-error">Address is - required</small> - </div> + <small *ngIf="error !== ''" class="p-error">{{error}}</small> + <div *ngIf="uploadProgress > 0"> + <p>Uploading... {{ uploadProgress }}%</p> + <progress [value]="uploadProgress" max="100"></progress> </div> + <small *ngIf="imgpath !== ''">{{imgpath}} <i class="pi pi-image"></i></small> </div> - <div class="p-grid"> - <!-- Gender --> - <div class="p-col-6"> - <div class="field"> - <label for="gender">Gender</label> - <div> - <label class="mx-1"> - <input id="male" type="radio" name="gender" [(ngModel)]="selectedgender" [value]="1" - required /> - Male - </label> - <label> - <input id="female" type="radio" name="gender" [(ngModel)]="selectedgender" - [value]="2" /> - Female - </label> - </div> - <small *ngIf="!selectedgender" class="p-error">Gender is required</small> - </div> + <!-- Mobile & Address --> + <div class="col-6"> + <div class="field"> + <label for="mobile"><i class="pi pi-phone"></i> Mobile</label> + <input id="mobile" name="mobile" type="text" pInputText [(ngModel)]="selectedPatient.mobile" + placeholder="Enter mobile number" maxlength="10" required pattern="[0-9]{10}" + #mobile="ngModel" /> + <small *ngIf="mobile.invalid && mobile.touched" class="p-error"> + Mobile is required and must be 10 digits + </small> </div> - - <!-- Admission Date --> - <div class="p-col-6"> - <div class="field"> - <label for="admissionDate">Admission Date</label> - <p-calendar id="admissionDate" name="admissionDate" [(ngModel)]="selectadmissionDate" - showIcon styleClass="small-calendar" required #admissionDate="ngModel"></p-calendar> - <small *ngIf="admissionDate.invalid && admissionDate.touched" class="p-error"> - Admission Date is required - </small> - </div> - </div> - </div> - <div class="p-grid"> - <!-- Doctors Note --> - <div class="p-col-6"> - <div class="field"> - <label for="doctorAssigned">Doctor Assigned</label> - <input id="doctorAssigned" name="doctorAssigned" type="text" pInputText - [(ngModel)]="selectedPatient.doctorAssigned" placeholder="Enter assigned doctor" /> - </div> - </div> - - <!-- Treatment --> - <div class="p-col-6"> - <div class="field"> - <label for="treatment">Treatment</label> - <input id="treatment" name="treatment" type="treatment" pInputText - [(ngModel)]="selectedPatient.treatment" placeholder="Enter treatment" /> - </div> - </div> - </div> - - <div class="p-grid"> - <!-- Blood Group --> - <div class="p-col-6"> - <div class="field"> - <label for="bloodGroup">Blood Group</label> - <input id="bloodGroup" name="bloodGroup" type="text" pInputText - [(ngModel)]="selectedPatient.bloodGroup" placeholder="Enter blood group" required - #bloodGroup="ngModel" /> - <small *ngIf="bloodGroup.invalid && bloodGroup.touched" class="p-error">Blood Group is - required</small> - </div> - </div> - - <!-- Email --> - <div class="p-col-6"> - <div class="field"> - <label for="email">Email</label> - <input id="email" name="email" type="email" pInputText [(ngModel)]="selectedPatient.email" - placeholder="Enter email address" required email #email="ngModel" /> - <small *ngIf="email.invalid && email.touched" class="p-error">Enter a valid email - address</small> - </div> - </div> - </div> - - <div class="p-grid"> - <!-- Age --> - <div class="p-col-6"> - <div class="field"> - <label for="age">Age</label> - <input id="age" name="age" type="number" pInputText [(ngModel)]="selectedPatient.age" - placeholder="Enter age" required min="1" max="120" #age="ngModel" /> - <small *ngIf="age.invalid && age.touched" class="p-error"> - Age is required and must be between 1 and 90 - </small> - </div> - </div> - - <!-- Status --> - <div class="p-col-6"> - <div class="field"> - <label for="status">Status</label> - <p-dropdown name="status" id="status" [options]="statuslist" [(ngModel)]="selectedstatus" - optionLabel="label" optionValue="value" placeholder="Select status" - required></p-dropdown> - <small *ngIf="selectedstatus === 0" class="p-error">Status is required</small> - </div> + <div class="field"> + <label for="address"><i class="pi pi-map-marker"></i> Address</label> + <input id="address" name="address" type="text" pInputText [(ngModel)]="selectedPatient.address" + placeholder="Enter address" required #address="ngModel" /> + <small *ngIf="address.invalid && address.touched" class="p-error">Address is required</small> </div> </div> </div> - <div> + <div class="p-fluid grid"> + <!-- Gender & Admission Date --> + <div class="col-6"> + <div class="field"> + <label for="gender"><i class="pi pi-users"></i> Gender</label> + <div> + <label class="mx-1"> + <input id="male" type="radio" name="gender" [(ngModel)]="selectedgender" [value]="1" + required /> + Male + </label> + <label> + <input id="female" type="radio" name="gender" [(ngModel)]="selectedgender" + [value]="2" /> + Female + </label> + </div> + <small *ngIf="!selectedgender" class="p-error">Gender is required</small> + </div> + </div> + <div class="col-6"> + <div class="field"> + <label for="admissionDate"><i class="pi pi-calendar"></i> Admission Date</label> + <p-calendar id="admissionDate" name="admissionDate" [(ngModel)]="selectadmissionDate" showIcon + styleClass="small-calendar" required #admissionDate="ngModel"></p-calendar> + <small *ngIf="admissionDate.invalid && admissionDate.touched" class="p-error"> + Admission Date is required + </small> + </div> + </div> + </div> + + <div class="p-fluid grid"> + <!-- Doctor & Treatment --> + <div class="col-6"> + <div class="field"> + <label for="doctorAssigned"><i class="pi pi-user-md"></i> Doctor Assigned</label> + <input id="doctorAssigned" name="doctorAssigned" type="text" pInputText + [(ngModel)]="selectedPatient.doctorAssigned" placeholder="Enter assigned doctor" /> + </div> + </div> + <div class="col-6"> + <div class="field"> + <label for="treatment"><i class="pi pi-heartbeat"></i> Treatment</label> + <input id="treatment" name="treatment" type="text" pInputText + [(ngModel)]="selectedPatient.treatment" placeholder="Enter treatment" /> + </div> + </div> + </div> + + <div class="p-fluid grid"> + <!-- Blood Group & Email --> + <div class="col-6"> + <div class="field"> + <label for="bloodGroup"><i class="pi pi-tint"></i> Blood Group</label> + <input id="bloodGroup" name="bloodGroup" type="text" pInputText + [(ngModel)]="selectedPatient.bloodGroup" placeholder="Enter blood group" required + #bloodGroup="ngModel" /> + <small *ngIf="bloodGroup.invalid && bloodGroup.touched" class="p-error">Blood Group is + required</small> + </div> + </div> + <div class="col-6"> + <div class="field"> + <label for="email"><i class="pi pi-envelope"></i> Email</label> + <input id="email" name="email" type="email" pInputText [(ngModel)]="selectedPatient.email" + placeholder="Enter email address" required email #email="ngModel" /> + <small *ngIf="email.invalid && email.touched" class="p-error">Enter a valid email + address</small> + </div> + </div> + </div> + + <div class="text-right"> <button type="submit" pButton class="btn btn-primary" - [disabled]="(patientrecord.invalid || selectedstatus === 0 || !selectedgender)">Save</button> - <button pButton class="btn btn-secondary ml-1" (click)="closeDialog()">Close</button> + [disabled]="(patientrecord.invalid || selectedstatus === 0 || !selectedgender)"> + <i class="pi pi-check"></i> Save + </button> + <button pButton class="btn btn-secondary ml-1" (click)="closeDialog()"> + <i class="pi pi-times"></i> Close + </button> </div> </form> </p-dialog> diff --git a/angular/src/app/patients/all-patients/all-patients.component.scss b/angular/src/app/patients/all-patients/all-patients.component.scss index 9b907b1..cd3ef1e 100644 --- a/angular/src/app/patients/all-patients/all-patients.component.scss +++ b/angular/src/app/patients/all-patients/all-patients.component.scss @@ -25,4 +25,13 @@ color: red; font-size: 1.2rem; } + + .bg-pink { + background-color: #ff4081 !important; + color: white; +} + +.gap-1 { + gap: 5px; +} \ No newline at end of file diff --git a/angular/src/app/patients/all-patients/all-patients.component.ts b/angular/src/app/patients/all-patients/all-patients.component.ts index c722433..54fcec2 100644 --- a/angular/src/app/patients/all-patients/all-patients.component.ts +++ b/angular/src/app/patients/all-patients/all-patients.component.ts @@ -158,6 +158,7 @@ export class AllPatientsComponent implements OnInit { this.error = 'Please Type a Name'; return; } + this.error = ''; const input = event.target as HTMLInputElement; if (input.files.length > 0) { const tag = 'Image'; @@ -170,7 +171,6 @@ export class AllPatientsComponent implements OnInit { } } - UploadFileData(tag: string, formdata: FormData) { // this.patientService.uploadFile(tag, formdata).subscribe(result => { // this.selectedPatient.imageID = result; diff --git a/angular/src/app/patients/patient-record/patient-record.component.html b/angular/src/app/patients/patient-record/patient-record.component.html index 630f94b..1640b18 100644 --- a/angular/src/app/patients/patient-record/patient-record.component.html +++ b/angular/src/app/patients/patient-record/patient-record.component.html @@ -52,30 +52,27 @@ </button> </div> -<div> - <p-table #dt2 dataKey="id" [value]="patientrecords" [paginator]="true" [rows]="10" [totalRecords]="totalRecords" - [lazy]="true" (onLazyLoad)="loadPatient($event,patientId)" [rowsPerPageOptions]="[10, 20, 50]" - [responsiveLayout]="'scroll'" [globalFilterFields]="['id', 'name', 'diagnosis']" - [filters]="{ global: { value: '', matchMode: 'contains' } }" class="table table-striped"> +<div class="mt-4"> + <p-table #dt2 [value]="patientrecords" [paginator]="true" [rows]="10" [totalRecords]="totalRecords" [lazy]="true" + (onLazyLoad)="loadPatient($event,patientId)" [rowsPerPageOptions]="[10, 20, 50]" [responsiveLayout]="'scroll'" + [globalFilterFields]="['id', 'name', 'diagnosis']" class="card shadow-sm"> <ng-template pTemplate="caption"> - <div class="flex"> - <h2 class="mr-auto">{{'::PatientHeader' | abpLocalization}}</h2> - <div> - <button *ngIf="createpermission" pButton class="p-button-rounded p-button-success ml-2" + <div class="flex justify-content-between align-items-center"> + <h3>{{'::PatientHeader' | abpLocalization}}</h3> + <div class="flex gap-2"> + <button *ngIf="createpermission" pButton class="p-button-rounded p-button-success" (click)="openNewPatientDialog()"> <i class="pi pi-plus-circle"></i> </button> - <button pButton class="p-button-rounded p-button-warning ml-2" (click)="exportPatient()"> + <button pButton class="p-button-rounded p-button-warning" (click)="exportPatient()"> <i class="pi pi-download"></i> </button> - <p-iconField iconPosition="right" class="ml-2"> - <p-inputIcon> - <i class="pi pi-search"></i> - </p-inputIcon> - <input pInputText type="text" (input)="dt2.filterGlobal($event.target.value, 'contains')" - [(ngModel)]="globalFilter" placeholder="Search keyword" /> - </p-iconField> + <span class="p-input-icon-left"> + <i class="pi pi-search"></i> + <input pInputText type="text" [(ngModel)]="globalFilter" + (input)="dt2.filterGlobal($event.target.value, 'contains')" placeholder="Search..."> + </span> </div> </div> </ng-template> @@ -90,7 +87,7 @@ <th>Lab Reports</th> <th>Medications</th> <th pSortableColumn="nextFollowUp">Next Follow-Up <p-sortIcon field="nextFollowUp" /></th> - <th pSortableColumn="status">Status <p-sortIcon field="status" /></th> + <th>Status</th> <th>Actions</th> </tr> </ng-template> @@ -106,186 +103,141 @@ </td> <td>{{ patientrecord.dateOfAdmission | date }}</td> <td>{{ patientrecord.diagnosis }}</td> - <td><i class="pi pi-file-pdf pdf-icon"></i></td> - <td><i class="pi pi-file-pdf pdf-icon"></i></td> + <td><i class="pi pi-file-pdf text-danger"></i></td> + <td><i class="pi pi-file-pdf text-primary"></i></td> <td>{{ patientrecord.nextFollowUp | date }}</td> - <td>{{ status[patientrecord.patients.status] }}</td> - <td class="d-flex"> - <button *ngIf="editpermission" class="btn btn-warning btn-sm" (click)="editPatient(patientrecord)"><i - class="pi pi-pencil"></i></button> - <button *ngIf="deletepermission" class="btn btn-danger btn-sm ml-1" - (click)="deletePatient(patientrecord.id)"><i class="pi pi-trash"></i></button> + <td> + <span class="badge" + [ngClass]="patientrecord.patients.status === 1 ? 'bg-success' : (patientrecord.patients.status === 2 ? 'bg-primary':'bg-danger')"> + {{ status[patientrecord.patients.status] }} + </span> + </td> + <td class="flex gap-2"> + <button *ngIf="editpermission" class="btn btn-warning btn-sm" (click)="editPatient(patientrecord)"> + <i class="pi pi-pencil"></i> + </button> + <button *ngIf="deletepermission" class="btn btn-danger btn-sm" (click)="deletePatient(patientrecord.id)"> + <i class="pi pi-trash"></i> + </button> </td> </tr> </ng-template> + <ng-template pTemplate="emptymessage"> <tr> - <td colspan="11">No Patients found.</td> + <td colspan="9">No Patients found.</td> </tr> </ng-template> </p-table> - <span>Total Records: {{totalRecords}}</span> + <div class="mt-2">Total Records: {{totalRecords}}</div> </div> <div> <p-dialog *ngIf="patientDialog" header="{{patientDialogTitle}}" [(visible)]="patientDialog" [modal]="true" - [closable]="true" [style]="{width: '85%', height: '100%'}"> + [closable]="true" [style]="{width: '70%', height: 'auto'}"> <form #patientrecord="ngForm" (ngSubmit)="savePatient(patientrecord)" novalidate> - <div class="p-fluid"> - <div class="p-grid"> - <!-- <div class="p-col-6"> - <div class="field"> - <label for="fullname">Full Name</label> - <input id="fullname" name="fullname" type="text" autocomplete="off" pInputText - [(ngModel)]="selectedPatient.fullName" placeholder="Enter full patient name" required - #fullname="ngModel" /> - <small *ngIf="fullname.invalid && fullname.touched" class="p-error"> - Full Name is required. - </small> - </div> - </div> --> - <!-- <div class="p-col-6"> - <div class="field"> - <label for="mobile">Mobile</label> - <input id="mobile" name="mobile" type="text" autocomplete="off" pInputText - [(ngModel)]="selectedPatient.mobile" maxlength="10" pattern="^[0-9]{10}$" - placeholder="Enter mobile number" required #mobile="ngModel" /> - <small *ngIf="mobile.invalid && mobile.touched" class="p-error"> - Mobile number is required and must be 10 digits. - </small> - </div> - </div> --> - </div> + <div class="p-fluid grid"> - <div class="p-grid"> - <div class="p-col-6"> - <!-- <div class="field"> - <label for="gender">Gender</label> - <div> - <label class="mx-1"> - <input style="background-color: #fff;" id="male" type="radio" name="gender" - [(ngModel)]="selectedgender" [value]="1" required #gender="ngModel" /> - Male - </label> - <label> - <input style="background-color: #fff;" id="female" type="radio" name="gender" - [(ngModel)]="selectedgender" [value]="2" required /> - Female - </label> - <small *ngIf="!selectedgender" class="p-error"> - Please select a gender. - </small> - </div> - </div> --> - </div> - <div class="p-col-6"> - <div class="field"> - <label for="admissionDate">Admission Date</label> - <p-calendar id="admissionDate" name="admissionDate" [(ngModel)]="selectdateOfAdmission" showIcon required - #admissionDate="ngModel"></p-calendar> - <small *ngIf="admissionDate.invalid && admissionDate.touched" class="p-error"> - Admission Date is required. - </small> - </div> + <!-- Admission Date --> + <div class="col-6"> + <div class="field"> + <label for="admissionDate"><i class="pi pi-calendar"></i> Admission Date</label> + <p-calendar id="admissionDate" name="admissionDate" [(ngModel)]="selectdateOfAdmission" showIcon required + #admissionDate="ngModel"></p-calendar> + <small *ngIf="admissionDate.invalid && admissionDate.touched" class="p-error"> + Admission Date is required. + </small> </div> </div> - <div class="p-grid"> - <div class="p-col-6"> - <div class="field"> - <label for="labReport">Lab Report</label> - <input type="file" id="labReport" name="labReport" accept=".pdf,.doc,.docx" - (change)="handleUpload($event,'Lab-Report')" /> - </div> - <div *ngIf="uploadProgress > 0"> - <p>Uploading... {{ uploadProgress }}%</p> - <progress [value]="uploadProgress" max="100"></progress> - </div> - <small *ngIf="labReportUrlpath !==''">{{labReportUrlpath}} <i class="pi pi-file-pdf pdf-icon"></i></small> - </div> - <div class="p-col-6"> - <div class="field"> - <label for="medications">Medications</label> - <input type="file" id="medications" name="medications" accept=".pdf,.doc,.docx" - (change)="handleUpload($event,'Medication')" /> - </div> - <div *ngIf="uploadProgress > 0"> - <p>Uploading... {{ uploadProgress }}%</p> - <progress [value]="uploadProgress" max="100"></progress> - </div> - <small *ngIf="medicationUrlpath !==''">{{medicationUrlpath}} <i class="pi pi-file-pdf pdf-icon"></i></small> - </div> - </div> - - <div class="p-grid"> - <div class="p-col-6"> - <div class="field"> - <label for="medicationHistory">Medication History</label> - <input type="file" id="medicationHistory" name="medicationHistory" accept=".pdf,.doc,.docx" - (change)="handleUpload($event,'Medication-History')" /> - </div> - <div *ngIf="uploadProgress > 0"> - <p>Uploading... {{ uploadProgress }}%</p> - <progress [value]="uploadProgress" max="100"></progress> - </div> - <small *ngIf="medicationHistoryUrlpath !==''">{{medicationHistoryUrlpath}} <i - class="pi pi-file-pdf pdf-icon"></i></small> - </div> - <div class="p-col-6"> - <div class="field"> - <label for="nextFollowUp">Next FollowUp Date</label> - <p-calendar id="nextFollowUp" name="nextFollowUp" [(ngModel)]="selectnextFollowUp" showIcon required - #nextFollowUp="ngModel"></p-calendar> - <small *ngIf="nextFollowUp.invalid && nextFollowUp.touched" class="p-error"> - Next Follow-Up Date is required. - </small> - </div> - </div> - </div> - - <div class="p-grid"> - <div class="p-col-12"> - <div class="field"> - <div> - <label for="diagnosis">Diagnosis</label> - </div> - <textarea style="width: 100%; background-color: #fff; color: black;" id="diagnosis" name="diagnosis" - pInputTextarea rows="5" cols="30" [(ngModel)]="selectedPatient.diagnosis" required - #diagnosis="ngModel"></textarea> - <small *ngIf="diagnosis.invalid && diagnosis.touched" class="p-error"> - Diagnosis is required. - </small> - </div> - </div> - </div> - - <div class="p-grid"> - <div class="p-col-6"> - <div class="field"> - <label for="insuranceProvider">Insurance Provider</label> - <input id="insuranceProvider" name="insuranceProvider" type="text" autocomplete="off" pInputText - [(ngModel)]="selectedPatient.insuranceProvider" required placeholder="Enter insurance provider" - #insurance="ngModel" /> - <small *ngIf="insurance.invalid && insurance.touched" class="p-error"> - Insurance is required. - </small> - </div> - </div> - <div class="p-col-6"> - <!-- <div class="field"> - <label for="status">Status</label> - <p-dropdown name="status" id="status" [options]="statuslist" [(ngModel)]="selectedstatus" - optionLabel="label" optionValue="value" placeholder="Select status" required - #status="ngModel"></p-dropdown> - <small *ngIf="selectedstatus === 0" class="p-error"> - Status is required. - </small> - </div> --> + <!-- Next Follow-Up Date --> + <div class="col-6"> + <div class="field"> + <label for="nextFollowUp"><i class="pi pi-calendar-plus"></i> Next Follow-Up Date</label> + <p-calendar id="nextFollowUp" name="nextFollowUp" [(ngModel)]="selectnextFollowUp" showIcon required + #nextFollowUp="ngModel"></p-calendar> + <small *ngIf="nextFollowUp.invalid && nextFollowUp.touched" class="p-error"> + Next Follow-Up Date is required. + </small> </div> </div> </div> - <div> - <button type="submit" pButton class="btn btn-primary" [disabled]="patientrecord.invalid">Save</button> - <button pButton class="btn btn-secondary ml-1" (click)="closeDialog()">Close</button> + + <!-- File Uploads --> + <div class="p-fluid grid"> + <div class="col-6"> + <div class="field"> + <label for="labReport"><i class="pi pi-file-pdf"></i> Lab Report</label> + <input type="file" id="labReport" name="labReport" accept=".pdf,.doc,.docx" + (change)="handleUpload($event,'Lab-Report')" /> + <div *ngIf="uploadProgress1 > 0"> + <p>Uploading... {{ uploadProgress1 }}%</p> + <progress [value]="uploadProgress1" max="100"></progress> + </div> + <small *ngIf="labReportUrlpath!==''">{{labReportUrlpath}} <i class="pi pi-file"></i></small> + </div> + </div> + + <div class="col-6"> + <div class="field"> + <label for="medications"><i class="pi pi-file-pdf"></i> Medications</label> + <input type="file" id="medications" name="medications" accept=".pdf,.doc,.docx" + (change)="handleUpload($event,'Medication')" /> + <div *ngIf="uploadProgress2 > 0"> + <p>Uploading... {{ uploadProgress2 }}%</p> + <progress [value]="uploadProgress2" max="100"></progress> + </div> + <small *ngIf="medicationUrlpath!==''">{{medicationUrlpath}} <i class="pi pi-file"></i></small> + </div> + </div> + <div class="col-6"> + <div class="field"> + <label for="medicationHistory"><i class="pi pi-file-pdf"></i>Medication History</label> + <input type="file" id="medicationHistory" name="medicationHistory" accept=".pdf,.doc,.docx" + (change)="handleUpload($event,'Medication-History')" /> + <div *ngIf="uploadProgress3 > 0"> + <p>Uploading... {{ uploadProgress3 }}%</p> + <progress [value]="uploadProgress3" max="100"></progress> + </div> + <small *ngIf="medicationHistoryUrlpath !==''">{{medicationHistoryUrlpath}} <i + class="pi pi-file-pdf pdf-icon"></i></small> + </div> + </div> + </div> + + <!-- Diagnosis --> + <div class="p-fluid"> + <div class="field"> + <label for="diagnosis"><i class="pi pi-heartbeat"></i> Diagnosis</label> + <textarea style="width: 100%; background-color: #fff; color: black;" id="diagnosis" name="diagnosis" + pInputTextarea rows="5" cols="30" [(ngModel)]="selectedPatient.diagnosis" required + #diagnosis="ngModel"></textarea> + <small *ngIf="diagnosis.invalid && diagnosis.touched" class="p-error"> + Diagnosis is required. + </small> + </div> + </div> + + <!-- Insurance Provider --> + <div class="p-fluid"> + <div class="field"> + <label for="insuranceProvider"><i class="pi pi-credit-card"></i> Insurance Provider</label> + <input id="insuranceProvider" name="insuranceProvider" type="text" pInputText + [(ngModel)]="selectedPatient.insuranceProvider" required placeholder="Enter insurance provider" + #insurance="ngModel" /> + <small *ngIf="insurance.invalid && insurance.touched" class="p-error"> + Insurance is required. + </small> + </div> + </div> + + <!-- Buttons --> + <div class="p-dialog-footer flex justify-content-end"> + <button type="submit" pButton class="btn btn-primary" [disabled]="patientrecord.invalid"> + <i class="pi pi-check"></i> Save + </button> + <button pButton class="btn btn-secondary ml-2" (click)="closeDialog()"> + <i class="pi pi-times"></i> Close + </button> </div> </form> </p-dialog> diff --git a/angular/src/app/patients/patient-record/patient-record.component.scss b/angular/src/app/patients/patient-record/patient-record.component.scss index 0bc5d64..049d143 100644 --- a/angular/src/app/patients/patient-record/patient-record.component.scss +++ b/angular/src/app/patients/patient-record/patient-record.component.scss @@ -18,7 +18,8 @@ } .female { - background-color: purple; + background-color: #ff4081 !important; + color: white; } .pdf-icon { diff --git a/angular/src/app/patients/patient-record/patient-record.component.ts b/angular/src/app/patients/patient-record/patient-record.component.ts index b3ee512..6916fc5 100644 --- a/angular/src/app/patients/patient-record/patient-record.component.ts +++ b/angular/src/app/patients/patient-record/patient-record.component.ts @@ -41,7 +41,9 @@ export class PatientRecordComponent implements OnInit { medicationHistoryUrlpath: string; medicationUrlpath: string; guid: string = '00000000-0000-0000-0000-000000000000'; - uploadProgress = 0; + uploadProgress1 = 0; + uploadProgress2 = 0; + uploadProgress3 = 0; constructor( private patientService: PatientService, @@ -94,6 +96,9 @@ export class PatientRecordComponent implements OnInit { this.medicationHistoryUrlpath = ''; this.selectdateOfAdmission = new Date(); this.selectnextFollowUp = new Date(); + this.uploadProgress1 = 0; + this.uploadProgress2 = 0; + this.uploadProgress3 = 0; } loadPatient(event: any, id: any) { @@ -198,7 +203,9 @@ export class PatientRecordComponent implements OnInit { formdata.append('file', input.files[0]); this.UploadFileData(tag, formdata); } else { - this.uploadProgress = 0; + this.uploadProgress1 = 0; + this.uploadProgress2 = 0; + this.uploadProgress3 = 0; return; } } @@ -260,18 +267,30 @@ export class PatientRecordComponent implements OnInit { this.http.request(req).subscribe( event => { if (event.type === HttpEventType.UploadProgress) { - this.uploadProgress = Math.round((event.loaded / event.total!) * 100); - console.log(event.type, this.uploadProgress); - } else if (event.type === HttpEventType.Response) { - this.uploadProgress = 100; + // this.uploadProgress = Math.round((event.loaded / event.total!) * 100); switch (tag) { case 'Lab-Report': + this.uploadProgress1 = Math.round((event.loaded / event.total!) * 100); + break; + case 'Medication': + this.uploadProgress2 = Math.round((event.loaded / event.total!) * 100); + break; + case 'Medication-History': + this.uploadProgress3 = Math.round((event.loaded / event.total!) * 100); + break; + } + } else if (event.type === HttpEventType.Response) { + switch (tag) { + case 'Lab-Report': + this.uploadProgress1 = 100; this.selectedPatient.labReportUrlID = event.body.toString(); break; case 'Medication': + this.uploadProgress2 = 100; this.selectedPatient.medicationUrlID = event.body.toString(); break; case 'Medication-History': + this.uploadProgress3 = 100; this.selectedPatient.medicationHistoryUrlID = event.body.toString(); break; } @@ -279,7 +298,9 @@ export class PatientRecordComponent implements OnInit { }, error => { console.error('Upload failed', error); - this.uploadProgress = 0; + this.uploadProgress1 = 100; + this.uploadProgress2 = 100; + this.uploadProgress3 = 100; } ); } diff --git a/aspnet-core/src/HospitalManagementSystem.Application/Patients/PatientAppService.cs b/aspnet-core/src/HospitalManagementSystem.Application/Patients/PatientAppService.cs index cd53ffa..35acb19 100644 --- a/aspnet-core/src/HospitalManagementSystem.Application/Patients/PatientAppService.cs +++ b/aspnet-core/src/HospitalManagementSystem.Application/Patients/PatientAppService.cs @@ -54,7 +54,7 @@ namespace HospitalManagementSystem.Patients .Include(x => x.LabReportUrl) .Include(x => x.MedicationUrl) .Include(x => x.MedicationHistoryUrl) - .WhereIf(!string.IsNullOrEmpty(input.Search), x => x.Patients.Name.ToLower().Contains(input.Search.ToLower())) + .WhereIf(!string.IsNullOrEmpty(input.Search), x => x.Patients.Name.ToLower().Contains(input.Search.ToLower()) || x.Patients.Email.Contains(input.Search)) .Where(x => x.Patients.Id == Id); var totalCount = await filteredQuery.CountAsync(); @@ -270,7 +270,7 @@ namespace HospitalManagementSystem.Patients if (!string.IsNullOrEmpty(input.Search)) { query = _patientRepository.GetQueryableAsync().Result - .Where(x => x.Name.ToLower().Contains(input.Search.ToLower())) + .Where(x => x.Name.ToLower().Contains(input.Search.ToLower()) || x.Email.Contains(input.Search)) .OrderBy(input.Sorting ?? (nameof(Patient.Id) + " asc")) .Skip(input.SkipCount) .Take(input.MaxResultCount)