diff --git a/angular/src/app/app-routing.module.ts b/angular/src/app/app-routing.module.ts index 2dd6ad4..5931c48 100644 --- a/angular/src/app/app-routing.module.ts +++ b/angular/src/app/app-routing.module.ts @@ -52,6 +52,10 @@ const routes: Routes = [ path: 'doctors', loadChildren: () => import('./doctors/doctors.module').then(m => m.DoctorsModule), }, + { + path: 'rooms', + loadChildren: () => import('./room-management/room-management.module').then(m => m.RoomManagementModule), + }, ]; @NgModule({ diff --git a/angular/src/app/doctors/doctor-dialog.component.html b/angular/src/app/doctors/doctor-dialog.component.html index f2f54ec..f2f8e0b 100644 --- a/angular/src/app/doctors/doctor-dialog.component.html +++ b/angular/src/app/doctors/doctor-dialog.component.html @@ -22,75 +22,371 @@ </div> <form #doctorForm="ngForm" (ngSubmit)="saveDoctor(doctorForm)"> <div class="p-fluid grid justify-content-center"> + <!-- First Name --> <div class="field col-md-5"> <label for="firstName">First Name <span class="text-danger">*</span></label> - <input pInputText id="firstName" name="firstName" [(ngModel)]="doctor.firstName" required #firstNameCtrl="ngModel" - [ngClass]="{'is-invalid': firstNameCtrl.invalid && firstNameCtrl.touched}" /> - <small class="text-danger" *ngIf="firstNameCtrl.invalid && firstNameCtrl.touched">First Name is required.</small> + <span class="p-input-icon-left p-input-icon-right"> + <i class="pi pi-user"></i> + <input + pInputText + id="firstName" + name="firstName" + [(ngModel)]="doctor.firstName" + #firstNameCtrl="ngModel" + required + minlength="2" + maxlength="30" + [ngClass]="{ + 'is-valid': firstNameCtrl.valid && firstNameCtrl.touched, + 'is-invalid': firstNameCtrl.invalid && firstNameCtrl.touched + }" + /> + <i + *ngIf="firstNameCtrl.valid && firstNameCtrl.touched" + class="pi pi-check text-success" + ></i> + <i + *ngIf="firstNameCtrl.invalid && firstNameCtrl.touched" + class="pi pi-times text-danger" + ></i> + </span> + <small class="text-danger" *ngIf="firstNameCtrl.invalid && firstNameCtrl.touched"> + <span *ngIf="firstNameCtrl.errors?.required">First Name is required.</span> + <span *ngIf="firstNameCtrl.errors?.minlength">Minimum 2 characters required.</span> + <span *ngIf="firstNameCtrl.errors?.maxlength">Maximum 30 characters allowed.</span> + </small> </div> + <div class="field col-md-1"></div> + + <!-- Last Name --> <div class="field col-md-5"> <label for="lastName">Last Name <span class="text-danger">*</span></label> - <input pInputText id="lastName" name="lastName" [(ngModel)]="doctor.lastName" required #lastNameCtrl="ngModel" - [ngClass]="{'is-invalid': lastNameCtrl.invalid && lastNameCtrl.touched}" /> - <small class="text-danger" *ngIf="lastNameCtrl.invalid && lastNameCtrl.touched">Last Name is required.</small> + <span class="p-input-icon-left p-input-icon-right"> + <i class="pi pi-user"></i> + <input + pInputText + id="lastName" + name="lastName" + [(ngModel)]="doctor.lastName" + #lastNameCtrl="ngModel" + required + minlength="2" + maxlength="30" + [ngClass]="{ + 'is-valid': lastNameCtrl.valid && lastNameCtrl.touched, + 'is-invalid': lastNameCtrl.invalid && lastNameCtrl.touched + }" + /> + <i + *ngIf="lastNameCtrl.valid && lastNameCtrl.touched" + class="pi pi-check text-success" + ></i> + <i + *ngIf="lastNameCtrl.invalid && lastNameCtrl.touched" + class="pi pi-times text-danger" + ></i> + </span> + <small class="text-danger" *ngIf="lastNameCtrl.invalid && lastNameCtrl.touched"> + <span *ngIf="lastNameCtrl.errors?.required">Last Name is required.</span> + </small> </div> + + <!-- Mobile --> <div class="field col-md-5"> <label for="mobile">Mobile <span class="text-danger">*</span></label> - <input pInputText id="mobile" name="mobile" [(ngModel)]="doctor.mobile" required #mobileCtrl="ngModel" - [ngClass]="{'is-invalid': mobileCtrl.invalid && mobileCtrl.touched}" /> - <small class="text-danger" *ngIf="mobileCtrl.invalid && mobileCtrl.touched">Mobile is required.</small> + <span class="p-input-icon-left p-input-icon-right"> + <i class="pi pi-phone"></i> + <input + pInputText + id="mobile" + name="mobile" + [(ngModel)]="doctor.mobile" + #mobileCtrl="ngModel" + required + pattern="^[0-9]{10}$" + [ngClass]="{ + 'is-valid': mobileCtrl.valid && mobileCtrl.touched, + 'is-invalid': mobileCtrl.invalid && mobileCtrl.touched + }" + /> + <i + *ngIf="mobileCtrl.valid && mobileCtrl.touched" + class="pi pi-check text-success" + ></i> + <i + *ngIf="mobileCtrl.invalid && mobileCtrl.touched" + class="pi pi-times text-danger" + ></i> + </span> + <small class="text-danger" *ngIf="mobileCtrl.invalid && mobileCtrl.touched"> + <span *ngIf="mobileCtrl.errors?.required">Mobile is required.</span> + <span *ngIf="mobileCtrl.errors?.pattern">Enter a valid 10-digit number.</span> + </small> </div> + <div class="field col-md-1"></div> + <!-- Email --> <div class="field col-md-5"> <label for="email">Email <span class="text-danger">*</span></label> - <input pInputText id="email" name="email" [(ngModel)]="doctor.email" required type="email" #emailCtrl="ngModel" - [ngClass]="{'is-invalid': emailCtrl.invalid && emailCtrl.touched}" /> - <small class="text-danger" *ngIf="emailCtrl.invalid && emailCtrl.touched">Valid Email is required.</small> + <span class="p-input-icon-left p-input-icon-right"> + <i class="pi pi-envelope"></i> + <input + pInputText + id="email" + name="email" + [(ngModel)]="doctor.email" + #emailCtrl="ngModel" + required + type="email" + pattern="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" + [ngClass]="{ + 'is-valid': emailCtrl.valid && emailCtrl.touched, + 'is-invalid': emailCtrl.invalid && emailCtrl.touched + }" + /> + <i *ngIf="emailCtrl.valid && emailCtrl.touched" class="pi pi-check text-success"></i> + <i *ngIf="emailCtrl.invalid && emailCtrl.touched" class="pi pi-times text-danger"></i> + </span> + <small class="text-danger" *ngIf="emailCtrl.invalid && emailCtrl.touched"> + <span *ngIf="emailCtrl.errors?.required">Email is required.</span> + <span *ngIf="emailCtrl.errors?.pattern">Enter a valid email address.</span> + </small> </div> + + <!-- Specialization --> <div class="field col-md-5"> <label for="specialization">Specialization</label> - <input pInputText id="specialization" name="specialization" [(ngModel)]="doctor.specialization" /> + <input + pInputText + id="specialization" + name="specialization" + [(ngModel)]="doctor.specialization" + /> </div> + <div class="field col-md-1"></div> + <!-- Experience --> <div class="field col-md-5"> <label for="experience">Experience (Years)</label> - <input type="number" pInputText id="experience" name="experience" [(ngModel)]="doctor.experience" min="0" /> + <input + type="number" + pInputText + id="experience" + name="experience" + [(ngModel)]="doctor.experience" + min="0" + /> </div> + <!-- Consultation Fee --> <div class="field col-md-5"> <label for="consultationFee">Consultation Fee</label> - <input type="number" pInputText id="consultationFee" name="consultationFee" [(ngModel)]="doctor.consultationFee" min="0" /> + <input + type="number" + pInputText + id="consultationFee" + name="consultationFee" + [(ngModel)]="doctor.consultationFee" + min="0" + /> </div> + <div class="field col-md-1"></div> + <!-- Clinic Location --> <div class="field col-md-5"> <label for="clinicLocation">Clinic Location</label> - <input pInputText id="clinicLocation" name="clinicLocation" [(ngModel)]="doctor.clinicLocation" /> + <input + pInputText + id="clinicLocation" + name="clinicLocation" + [(ngModel)]="doctor.clinicLocation" + /> </div> - <div class="field col-md-3"> - <label for="rating">Rating</label><br> - <p-rating [(ngModel)]="doctor.rating" [stars]="5" [cancel]="false" name="rating"></p-rating> + <div class="field col-md-5"> + <label for="dateofbirth">Date Of Birth <span class="text-danger">*</span></label> + <span class="p-input-icon-left p-input-icon-right"> + <i class="pi pi-calendar"></i> + <p-calendar + id="dateofbirth" + name="dateofbirth" + [(ngModel)]="dateofbirth" + #dateofbirthCtrl="ngModel" + required + [showIcon]="true" + dateFormat="dd/mm/yy" + [ngClass]="{ + 'is-valid': dateofbirthCtrl.valid && dateofbirthCtrl.touched, + 'is-invalid': dateofbirthCtrl.invalid && dateofbirthCtrl.touched + }" + > + </p-calendar> + <i + *ngIf="dateofbirthCtrl.valid && dateofbirthCtrl.touched" + class="pi pi-check text-success" + ></i> + <i + *ngIf="dateofbirthCtrl.invalid && dateofbirthCtrl.touched" + class="pi pi-times text-danger" + ></i> + </span> + <small class="text-danger" *ngIf="dateofbirthCtrl.invalid && dateofbirthCtrl.touched"> + <span *ngIf="dateofbirthCtrl.errors?.required">DOB is required.</span> + </small> </div> - <div class="field col-md-4"> - <label for="degree">Degree</label> - <input pInputText id="degree" name="degree" [(ngModel)]="doctor.degree" /> + <div class="field col-md-1"></div> + <div class="field col-md-5"> + <label for="joiningDate">Joining Date <span class="text-danger">*</span></label> + <span class="p-input-icon-left p-input-icon-right"> + <i class="pi pi-calendar"></i> + <p-calendar + id="joiningDate" + name="joiningDate" + [(ngModel)]="JoiningDate" + #joiningDateCtrl="ngModel" + required + [showIcon]="true" + dateFormat="dd/mm/yy" + [ngClass]="{ + 'is-valid': joiningDateCtrl.valid && joiningDateCtrl.touched, + 'is-invalid': joiningDateCtrl.invalid && joiningDateCtrl.touched + }" + > + </p-calendar> + <i + *ngIf="joiningDateCtrl.valid && joiningDateCtrl.touched" + class="pi pi-check text-success" + ></i> + <i + *ngIf="joiningDateCtrl.invalid && joiningDateCtrl.touched" + class="pi pi-times text-danger" + ></i> + </span> + <small class="text-danger" *ngIf="joiningDateCtrl.invalid && joiningDateCtrl.touched"> + <span *ngIf="joiningDateCtrl.errors?.required">Joining Date is required.</span> + </small> + </div> + <!-- Rating --> + <div class="field col-md-10"> + <label for="rating">Rating</label><br /> + <p-rating + [(ngModel)]="doctor.rating" + [stars]="5" + [cancel]="false" + name="rating" + ></p-rating> </div> <div class="field col-md-1"></div> - <div class="field col-md-3"> + <!-- <div class="field col-md-5"> <label for="availability">Availability</label> - <p-dropdown [options]="workScheduleOptions" [(ngModel)]="doctor.availability" name="availability" placeholder="Select Availability"></p-dropdown> + <p-dropdown + [options]="workScheduleOptions" + [(ngModel)]="doctor.availability" + name="availability" + placeholder="Select Availability" + optionLabel="label" + optionValue="value" + ></p-dropdown> + </div> --> + <div class="card p-4"> + <h4>Doctor Availability Schedule</h4> + + <!-- Add Availability Button --> + <div class="field"> + <button pButton type="button" (click)="addAvailability()" icon="pi pi-plus" label="Add Schedule"></button> + </div> + + <!-- Loop Through Availability Schedules --> + <div *ngFor="let avail of availabilitySchedules; let i = index" class="availability-container"> + + <!-- Work Schedule Selection --> + <div class="field col-md-3"> + <label for="availability-{{ i }}">Select Day</label> + <p-dropdown + [options]="workScheduleOptions" + [(ngModel)]="avail.schedule" + name="availability-{{ i }}" + placeholder="Select Availability" + optionLabel="label" + optionValue="value" + class="w-full" + ></p-dropdown> + </div> + + <!-- Start Time --> + <div class="field col-md-3"> + <label for="start-time-{{ i }}">Start Time</label> + <p-calendar + id="start-time-{{ i }}" + [(ngModel)]="avail.startTime" + name="startTime-{{ i }}" + showTime + timeOnly + hourFormat="24" + placeholder="Select Start Time" + class="w-full" + ></p-calendar> + </div> + + <!-- End Time --> + <div class="field col-md-3"> + <label for="end-time-{{ i }}">End Time</label> + <p-calendar + id="end-time-{{ i }}" + [(ngModel)]="avail.endTime" + name="endTime-{{ i }}" + showTime + timeOnly + hourFormat="24" + placeholder="Select End Time" + class="w-full" + ></p-calendar> + </div> + + <!-- Remove Button --> + <div class="field col-md-2 flex align-items-end"> + <button pButton type="button" (click)="removeAvailability(i)" icon="pi pi-trash" class="p-button-danger"></button> + </div> + + </div> + + </div> + + + <!-- Description --> <div class="field col-11"> <label for="description">Description</label> - <textarea id="description" name="description" [(ngModel)]="doctor.description" rows="5" cols="30" pInputTextarea></textarea> + <textarea + id="description" + name="description" + [(ngModel)]="doctor.description" + rows="5" + cols="30" + pInputTextarea + ></textarea> </div> + + <!-- Buttons --> <div class="field col-11 flex justify-content-end"> - <button pButton type="submit" label="Save" class="p-button-success" [disabled]="doctorForm.invalid"></button> - <button pButton type="button" label="Cancel" class="p-button-secondary ml-2" (click)="onClose()"></button> + <button + pButton + type="submit" + label="Save" + class="p-button-success" + [disabled]="doctorForm.invalid" + ></button> + <button + pButton + type="button" + label="Cancel" + class="p-button-secondary ml-2" + (click)="onClose()" + ></button> </div> </div> </form> diff --git a/angular/src/app/doctors/doctor-dialog.component.scss b/angular/src/app/doctors/doctor-dialog.component.scss index c1581bc..42889f1 100644 --- a/angular/src/app/doctors/doctor-dialog.component.scss +++ b/angular/src/app/doctors/doctor-dialog.component.scss @@ -20,4 +20,16 @@ .modal { z-index: 1040; /* Set lower z-index to ensure modal is behind the calendar */ } + .availability-container { + display: flex; + flex-wrap: wrap; + gap: 15px; + padding: 10px; + border-bottom: 1px solid #ddd; + margin-bottom: 10px; + } + + .w-full { + width: 100%; + } \ No newline at end of file diff --git a/angular/src/app/doctors/doctor-dialog.component.ts b/angular/src/app/doctors/doctor-dialog.component.ts index 5f42012..4e1b0ab 100644 --- a/angular/src/app/doctors/doctor-dialog.component.ts +++ b/angular/src/app/doctors/doctor-dialog.component.ts @@ -14,8 +14,13 @@ import { InputTextareaModule } from 'primeng/inputtextarea'; import { RadioButtonModule } from 'primeng/radiobutton'; import { TableModule } from 'primeng/table'; import { RatingModule } from 'primeng/rating'; -import { workScheduleOptions } from '@proxy/global-enum'; - +import { TimeSlot, WorkSchedule, workScheduleOptions } from '@proxy/global-enum'; +// Define Type for Availability +interface AvailabilitySchedule { + schedule: WorkSchedule | null; + startTime: Date | null; + endTime: Date | null; +} @Component({ selector: 'app-doctor-dialog', standalone: true, @@ -33,7 +38,7 @@ import { workScheduleOptions } from '@proxy/global-enum'; InputTextareaModule, ChipModule, CommonModule, - RatingModule + RatingModule, ], templateUrl: './doctor-dialog.component.html', styleUrl: './doctor-dialog.component.scss', @@ -48,14 +53,38 @@ export class DoctorDialogComponent implements OnInit { doctorDialog: boolean; JoiningDate: Date; dateofbirth: Date; + availabilitySchedules: AvailabilitySchedule[] = []; // Separate storage for availability constructor(private DoctorService: DoctorService, private toaster: ToasterService) {} - ngOnInit(): void { if (this.isEditMode) { this.fetchDoctorData(); } + else{ + this.doctor = { + firstName: '', + lastName: '', + gender: '', + mobile: '', + password: '', + designation: '', + departmentId: '', + address: '', + email: '', + dob: '', + education: '', + specialization: '', + degree: '', + joiningDate: '', + experience: 0, + consultationFee: 0, + availability: null, + timeSlot:null, + rating: 0, + clinicLocation: '', + }; + } } doctor: CreateDoctorDto = { @@ -77,15 +106,28 @@ export class DoctorDialogComponent implements OnInit { experience: 0, consultationFee: 0, availability: null, + timeSlot:null, + rating: 0, clinicLocation: '', }; - workScheduleOptions = Object.keys(workScheduleOptions) - .filter(key => isNaN(Number(key))) - .map(key => ({ - label: key.replace(/([A-Z])/g, ' $1').trim(), - value: workScheduleOptions[key as keyof typeof workScheduleOptions] - })); + workScheduleOptions = Object.keys(WorkSchedule) + .filter((key) => isNaN(Number(key))) // Only get string keys (not numeric values) + .map((key) => ({ + label: key.replace(/([A-Z])/g, ' $1').trim(), // Format enum keys as readable labels + value: WorkSchedule[key as keyof typeof WorkSchedule], // Get enum value + })); + + timeSlotOptions: { label: string, value: TimeSlot }[] = [ + { label: '10:00 AM - 7:00 PM', value: TimeSlot.TenToSeven }, + { label: '09:00 AM - 5:00 PM', value: TimeSlot.NineToFive }, + { label: '08:00 AM - 4:00 PM', value: TimeSlot.EightToFour }, + { label: '07:00 AM - 4:00 PM', value: TimeSlot.SevenToFour }, + { label: '06:00 AM - 3:00 PM', value: TimeSlot.SixToThree }, + { label: '12:00 PM - 9:00 PM', value: TimeSlot.TwelveToNine }, + { label: '10:00 AM - 6:00 PM', value: TimeSlot.TenToSix }, + { label: '11:00 AM - 8:00 PM', value: TimeSlot.ElevenToEight }, + ]; fetchDoctorData() { this.DoctorService.getDoctorById(this.Id).subscribe(result => { this.doctor = result; @@ -99,7 +141,7 @@ export class DoctorDialogComponent implements OnInit { return; } this.doctor.dob = this.dateofbirth.toDateString(); - + this.doctor.joiningDate = this.JoiningDate.toDateString(); if (this.isEditMode) { this.DoctorService.updatDoctor(this.doctor).subscribe( () => { @@ -126,4 +168,18 @@ export class DoctorDialogComponent implements OnInit { this.Id = ''; this.close.emit(); } + addAvailability() { + this.availabilitySchedules.push({ schedule: null, startTime: null, endTime: null }); + this.syncDoctorAvailability(); // Sync with doctor object + } + + removeAvailability(index: number) { + this.availabilitySchedules.splice(index, 1); + this.syncDoctorAvailability(); // Sync after removal + } + + syncDoctorAvailability() { + // this.doctor.availability = [...this.availabilitySchedules]; // Keep doctor object updated + } + } diff --git a/angular/src/app/doctors/doctors.component.html b/angular/src/app/doctors/doctors.component.html index 86132c3..283741c 100644 --- a/angular/src/app/doctors/doctors.component.html +++ b/angular/src/app/doctors/doctors.component.html @@ -45,8 +45,7 @@ </ng-template> <ng-template pTemplate="header"> <tr> - <th pSortableColumn="firstName">First Name <p-sortIcon field="firstName" /></th> - <th pSortableColumn="lastName">Last Name <p-sortIcon field="lastName" /></th> + <th pSortableColumn="firstName">Name <p-sortIcon field="firstName" /></th> <th pSortableColumn="mobile">Mobile <p-sortIcon field="mobile" /></th> <th pSortableColumn="email">Email <p-sortIcon field="email" /></th> <th pSortableColumn="specialization">Specialization <p-sortIcon field="specialization" /></th> @@ -57,8 +56,7 @@ </ng-template> <ng-template pTemplate="body" let-doctor> <tr> - <td>{{ doctor.firstName }}</td> - <td>{{ doctor.lastName }}</td> + <td>Dr. {{ doctor.firstName }} {{ doctor.lastName }}</td> <td>{{ doctor.mobile }}</td> <td>{{ doctor.email }}</td> <td>{{ doctor.specialization }}</td> diff --git a/angular/src/app/proxy/doctors/dto/models.ts b/angular/src/app/proxy/doctors/dto/models.ts index 711f9b2..a122baa 100644 --- a/angular/src/app/proxy/doctors/dto/models.ts +++ b/angular/src/app/proxy/doctors/dto/models.ts @@ -1,5 +1,6 @@ import type { FullAuditedEntity } from '../../volo/abp/domain/entities/auditing/models'; import type { WorkSchedule } from '../../global-enum/work-schedule.enum'; +import type { TimeSlot } from '../../global-enum/time-slot.enum'; export interface DoctorDto extends FullAuditedEntity<string> { id?: string; @@ -19,6 +20,7 @@ export interface DoctorDto extends FullAuditedEntity<string> { experience?: number; consultationFee?: number; availability?: WorkSchedule; + timeSlot: TimeSlot; rating?: number; clinicLocation?: string; } diff --git a/angular/src/app/proxy/dtos/models.ts b/angular/src/app/proxy/dtos/models.ts index d94a412..f2f5bbd 100644 --- a/angular/src/app/proxy/dtos/models.ts +++ b/angular/src/app/proxy/dtos/models.ts @@ -1,4 +1,5 @@ import type { WorkSchedule } from '../global-enum/work-schedule.enum'; +import type { TimeSlot } from '../global-enum/time-slot.enum'; import type { FullAuditedEntity } from '../volo/abp/domain/entities/auditing/models'; export interface CreateDepartmentDto { @@ -30,6 +31,7 @@ export interface CreateDoctorDto { experience?: number; consultationFee?: number; availability?: WorkSchedule; + timeSlot: TimeSlot; rating?: number; clinicLocation?: string; } diff --git a/angular/src/app/proxy/generate-proxy.json b/angular/src/app/proxy/generate-proxy.json index f70e398..b7b0d25 100644 --- a/angular/src/app/proxy/generate-proxy.json +++ b/angular/src/app/proxy/generate-proxy.json @@ -5724,6 +5724,18 @@ "maximum": null, "regex": null }, + { + "name": "TimeSlot", + "jsonName": null, + "type": "HospitalManagementSystem.GlobalEnum.TimeSlot", + "typeSimple": "HospitalManagementSystem.GlobalEnum.TimeSlot", + "isRequired": false, + "minLength": null, + "maxLength": null, + "minimum": null, + "maximum": null, + "regex": null + }, { "name": "Rating", "jsonName": null, @@ -6246,6 +6258,18 @@ "maximum": null, "regex": null }, + { + "name": "TimeSlot", + "jsonName": null, + "type": "HospitalManagementSystem.GlobalEnum.TimeSlot", + "typeSimple": "HospitalManagementSystem.GlobalEnum.TimeSlot", + "isRequired": false, + "minLength": null, + "maxLength": null, + "minimum": null, + "maximum": null, + "regex": null + }, { "name": "Rating", "jsonName": null, @@ -6415,6 +6439,32 @@ "genericArguments": null, "properties": null }, + "HospitalManagementSystem.GlobalEnum.TimeSlot": { + "baseType": "System.Enum", + "isEnum": true, + "enumNames": [ + "TenToSeven", + "NineToFive", + "EightToFour", + "SevenToFour", + "SixToThree", + "TwelveToNine", + "TenToSix", + "ElevenToEight" + ], + "enumValues": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "genericArguments": null, + "properties": null + }, "HospitalManagementSystem.GlobalEnum.visitType": { "baseType": "System.Enum", "isEnum": true, @@ -6433,6 +6483,13 @@ "baseType": "System.Enum", "isEnum": true, "enumNames": [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", "MondayToFriday", "TuesdayToSaturday", "WednesdayToSunday", @@ -6446,14 +6503,7 @@ "ThursdayToSunday", "FridayToMonday", "SaturdayToTuesday", - "SundayToWednesday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - "Sunday" + "SundayToWednesday" ], "enumValues": [ 1, diff --git a/angular/src/app/proxy/global-enum/index.ts b/angular/src/app/proxy/global-enum/index.ts index 0134ca4..46e6728 100644 --- a/angular/src/app/proxy/global-enum/index.ts +++ b/angular/src/app/proxy/global-enum/index.ts @@ -2,5 +2,6 @@ export * from './appointment-status.enum'; export * from './gender.enum'; export * from './payment-status.enum'; export * from './status.enum'; +export * from './time-slot.enum'; export * from './visit-type.enum'; export * from './work-schedule.enum'; diff --git a/angular/src/app/proxy/global-enum/time-slot.enum.ts b/angular/src/app/proxy/global-enum/time-slot.enum.ts new file mode 100644 index 0000000..2999c61 --- /dev/null +++ b/angular/src/app/proxy/global-enum/time-slot.enum.ts @@ -0,0 +1,14 @@ +import { mapEnumToOptions } from '@abp/ng.core'; + +export enum TimeSlot { + TenToSeven = 1, + NineToFive = 2, + EightToFour = 3, + SevenToFour = 4, + SixToThree = 5, + TwelveToNine = 6, + TenToSix = 7, + ElevenToEight = 8, +} + +export const timeSlotOptions = mapEnumToOptions(TimeSlot); diff --git a/angular/src/app/proxy/global-enum/work-schedule.enum.ts b/angular/src/app/proxy/global-enum/work-schedule.enum.ts index 0bb9f67..7c1a327 100644 --- a/angular/src/app/proxy/global-enum/work-schedule.enum.ts +++ b/angular/src/app/proxy/global-enum/work-schedule.enum.ts @@ -1,27 +1,27 @@ import { mapEnumToOptions } from '@abp/ng.core'; export enum WorkSchedule { - MondayToFriday = 1, - TuesdayToSaturday = 2, - WednesdayToSunday = 3, - ThursdayToMonday = 4, - FridayToTuesday = 5, - SaturdayToWednesday = 6, - SundayToThursday = 7, - MondayToThursday = 8, - TuesdayToFriday = 9, - WednesdayToSaturday = 10, - ThursdayToSunday = 11, - FridayToMonday = 12, - SaturdayToTuesday = 13, - SundayToWednesday = 14, - Monday = 15, - Tuesday = 16, - Wednesday = 17, - Thursday = 18, - Friday = 19, - Saturday = 20, - Sunday = 21, + Monday = 1, + Tuesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, + Sunday = 7, + MondayToFriday = 8, + TuesdayToSaturday = 9, + WednesdayToSunday = 10, + ThursdayToMonday = 11, + FridayToTuesday = 12, + SaturdayToWednesday = 13, + SundayToThursday = 14, + MondayToThursday = 15, + TuesdayToFriday = 16, + WednesdayToSaturday = 17, + ThursdayToSunday = 18, + FridayToMonday = 19, + SaturdayToTuesday = 20, + SundayToWednesday = 21, } export const workScheduleOptions = mapEnumToOptions(WorkSchedule); diff --git a/angular/src/app/room-management/rooms.component.html b/angular/src/app/room-management/rooms.component.html new file mode 100644 index 0000000..c4f9ddd --- /dev/null +++ b/angular/src/app/room-management/rooms.component.html @@ -0,0 +1,22 @@ +<div class="room-management-container"> + <h2 class="heading">Room Management</h2> + + <!-- Date Selection using PrimeNG --> + <div class="date-header"> + <label for="date">Select Date:</label> + <p-calendar id="date" [(ngModel)]="selectedDate" dateFormat="dd-mm-yy" (onSelect)="onDateChange()" showIcon></p-calendar> + </div> + + <!-- Room Grid --> + <div class="room-container p-grid"> + <div *ngFor="let room of roomData" class="p-col-12 p-md-3"> + <p-button + [label]="room.roomName" + [severity]="getRoomStatus(room.roomName) === 'occupied' ? 'danger' : 'success'" + class="room-button" + (click)="selectRoom(room.roomName)"> + </p-button> + </div> + </div> + </div> + \ No newline at end of file diff --git a/angular/src/app/room-management/rooms.component.scss b/angular/src/app/room-management/rooms.component.scss new file mode 100644 index 0000000..79e8a6c --- /dev/null +++ b/angular/src/app/room-management/rooms.component.scss @@ -0,0 +1,45 @@ +/* General Styling */ +.room-management-container { + padding: 20px; + font-family: 'Arial', sans-serif; + background-color: #f4f7fa; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + } + + .heading { + text-align: center; + font-size: 24px; + font-weight: bold; + margin-bottom: 20px; + } + + /* Date Picker */ + .date-header { + display: flex; + justify-content: center; + align-items: center; + gap: 10px; + margin-bottom: 20px; + font-size: 16px; + } + + .date-header label { + font-weight: 600; + } + + /* Room Grid */ + .room-container { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 15px; + } + + /* Room Buttons */ + .room-button { + width: 100%; + font-size: 14px; + font-weight: bold; + } + \ No newline at end of file diff --git a/angular/src/app/room-management/rooms.component.spec.ts b/angular/src/app/room-management/rooms.component.spec.ts new file mode 100644 index 0000000..da1e2ee --- /dev/null +++ b/angular/src/app/room-management/rooms.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RoomsComponent } from './rooms.component'; + +describe('RoomsComponent', () => { + let component: RoomsComponent; + let fixture: ComponentFixture<RoomsComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RoomsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RoomsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/angular/src/app/room-management/rooms.component.ts b/angular/src/app/room-management/rooms.component.ts new file mode 100644 index 0000000..18fc983 --- /dev/null +++ b/angular/src/app/room-management/rooms.component.ts @@ -0,0 +1,60 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-rooms', + + templateUrl: './rooms.component.html', + styleUrl: './rooms.component.scss' +}) +export class RoomsComponent { + + selectedDate: Date = new Date(); // Default to today + + roomData = [ + { roomName: 'Room 101' }, + { roomName: 'Room 102' }, + { roomName: 'Room 103' }, + { roomName: 'Room 104' }, + { roomName: 'Room 201' }, + { roomName: 'Room 202' }, + { roomName: 'Room 203' }, + { roomName: 'Room 301' }, + { roomName: 'Room 302' }, + { roomName: 'Room 303' }, + { roomName: 'Room 401' }, + { roomName: 'Room 402' }, + // Add more rooms as necessary + ]; + + roomStatus = { + 'Room 101': 'occupied', + 'Room 102': 'available', + 'Room 103': 'available', + 'Room 104': 'occupied', + 'Room 201': 'available', + 'Room 202': 'occupied', + 'Room 203': 'available', + 'Room 301': 'available', + 'Room 302': 'occupied', + 'Room 303': 'available', + 'Room 401': 'occupied', + 'Room 402': 'available', + // Add more rooms and statuses as necessary + }; + onDateChange() { + console.log('Selected date:', this.selectedDate); + // Logic to handle room status based on selected date, if needed + } + selectRoom(room: string) { + // Logic for selecting a room + console.log(`${room} selected.`); + } + + getRoomStatus(room: string) { + return this.roomStatus[room] || 'available'; // Default to 'available' if not specified + } + + getRoomStatusLabel(room: string) { + return this.getRoomStatus(room) === 'available' ? 'Available' : 'Occupied'; + } +} diff --git a/angular/src/app/route.provider.ts b/angular/src/app/route.provider.ts index 1a34e20..8f45a1b 100644 --- a/angular/src/app/route.provider.ts +++ b/angular/src/app/route.provider.ts @@ -91,6 +91,21 @@ function configureRoutes(routesService: RoutesService) { order: 402, requiredPolicy:'HospitalManagementSystem.Doctor' }, + { + path: '', + name: 'Rooms', + order: 501, + iconClass: 'fas fa-user-md', + layout: eLayoutType.application, + }, + { + path: '/rooms', + name: 'All Rooms', + parentName: 'Rooms', + iconClass: 'fas fa-clock', + order: 502, + requiredPolicy:'HospitalManagementSystem.Doctor' + }, ]); }; } diff --git a/aspnet-core/src/HospitalManagementSystem.Application.Contracts/Doctors/Dto/DoctorDto.cs b/aspnet-core/src/HospitalManagementSystem.Application.Contracts/Doctors/Dto/DoctorDto.cs index d361d3a..72620c0 100644 --- a/aspnet-core/src/HospitalManagementSystem.Application.Contracts/Doctors/Dto/DoctorDto.cs +++ b/aspnet-core/src/HospitalManagementSystem.Application.Contracts/Doctors/Dto/DoctorDto.cs @@ -27,6 +27,7 @@ namespace HospitalManagementSystem.Doctors.Dto public int? Experience { get; set; } public decimal? ConsultationFee { get; set; } public WorkSchedule? Availability { get; set; } + public TimeSlot TimeSlot { get; set; } public decimal? Rating { get; set; } public string? ClinicLocation { get; set; } } diff --git a/aspnet-core/src/HospitalManagementSystem.Application/Doctors/DoctorAppService.cs b/aspnet-core/src/HospitalManagementSystem.Application/Doctors/DoctorAppService.cs index acf98b6..0748a14 100644 --- a/aspnet-core/src/HospitalManagementSystem.Application/Doctors/DoctorAppService.cs +++ b/aspnet-core/src/HospitalManagementSystem.Application/Doctors/DoctorAppService.cs @@ -130,7 +130,7 @@ namespace HospitalManagementSystem.Doctors worksheet.Cell(i + 2, 2).Value = DoctorRecord[i].Email; worksheet.Cell(i + 2, 3).Value = DoctorRecord[i].Specialization; worksheet.Cell(i + 2, 4).Value = DoctorRecord[i].JoiningDate?.ToShortDateString(); - worksheet.Cell(i + 2, 5).Value = DoctorRecord[i].Department.DepartmentName; + worksheet.Cell(i + 2, 5).Value = DoctorRecord[i].Department==null?"": DoctorRecord[i].Department.DepartmentName; worksheet.Cell(i + 2, 6).Value = DoctorRecord[i].Mobile; worksheet.Cell(i + 2, 6).Value = DoctorRecord[i].Degree; worksheet.Cell(i + 2, 6).Value = DoctorRecord[i].Experience; @@ -138,9 +138,7 @@ namespace HospitalManagementSystem.Doctors worksheet.Cell(i + 2, 6).Value = DoctorRecord[i].Availability.ToString(); worksheet.Cell(i + 2, 6).Value = DoctorRecord[i].Rating; worksheet.Cell(i + 2, 6).Value = DoctorRecord[i].ClinicLocation; - } - worksheet.Columns().AdjustToContents(); workbook.SaveAs(filePath); } diff --git a/aspnet-core/src/HospitalManagementSystem.Application/Dtos/CreateDoctorDto.cs b/aspnet-core/src/HospitalManagementSystem.Application/Dtos/CreateDoctorDto.cs index 9f56671..5ffe610 100644 --- a/aspnet-core/src/HospitalManagementSystem.Application/Dtos/CreateDoctorDto.cs +++ b/aspnet-core/src/HospitalManagementSystem.Application/Dtos/CreateDoctorDto.cs @@ -29,6 +29,8 @@ namespace HospitalManagementSystem.Dtos public int? Experience { get; set; } public decimal? ConsultationFee { get; set; } public WorkSchedule? Availability { get; set; } + public TimeSlot TimeSlot { get; set; } + public decimal? Rating { get; set; } public string? ClinicLocation { get; set; } } diff --git a/aspnet-core/src/HospitalManagementSystem.Domain.Shared/Enum/GlobalEnum.cs b/aspnet-core/src/HospitalManagementSystem.Domain.Shared/Enum/GlobalEnum.cs index 966b82e..eaf86e5 100644 --- a/aspnet-core/src/HospitalManagementSystem.Domain.Shared/Enum/GlobalEnum.cs +++ b/aspnet-core/src/HospitalManagementSystem.Domain.Shared/Enum/GlobalEnum.cs @@ -39,28 +39,42 @@ namespace HospitalManagementSystem.GlobalEnum public enum WorkSchedule { - MondayToFriday = 1, - TuesdayToSaturday = 2, - WednesdayToSunday = 3, - ThursdayToMonday = 4, - FridayToTuesday = 5, - SaturdayToWednesday = 6, - SundayToThursday = 7, - MondayToThursday = 8, - TuesdayToFriday = 9, - WednesdayToSaturday = 10, - ThursdayToSunday = 11, - FridayToMonday = 12, - SaturdayToTuesday = 13, - SundayToWednesday = 14, - Monday = 15, - Tuesday = 16, - Wednesday = 17, - Thursday = 18, - Friday = 19, - Saturday = 20, - Sunday = 21 + Monday = 1, + Tuesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, + Sunday = 7, + MondayToFriday = 8, + TuesdayToSaturday = 9, + WednesdayToSunday = 10, + ThursdayToMonday = 11, + FridayToTuesday = 12, + SaturdayToWednesday = 13, + SundayToThursday = 14, + MondayToThursday = 15, + TuesdayToFriday = 16, + WednesdayToSaturday = 17, + ThursdayToSunday = 18, + FridayToMonday = 19, + SaturdayToTuesday = 20, + SundayToWednesday = 21 + + } + public enum TimeSlot + { + TenToSeven = 1, // 10:00 AM to 7:00 PM + NineToFive = 2, // 09:00 AM to 5:00 PM + EightToFour = 3, // 08:00 AM to 4:00 PM + SevenToFour = 4, // 07:00 AM to 4:00 PM + SixToThree = 5, // 06:00 AM to 3:00 PM + TwelveToNine = 6, // 12:00 PM to 9:00 PM + TenToSix = 7, // 10:00 AM to 6:00 PM + ElevenToEight = 8, // 11:00 AM to 8:00 PM } + + }