Compare commits
	
		
			37 Commits
		
	
	
		
			master
			...
			Appointmen
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 666d66a339 | |||
| 62a1030bd4 | |||
| 0e14f4e199 | |||
| 74c18e7b07 | |||
| 2b5b7be681 | |||
| 8545975107 | |||
| fa1430fb17 | |||
| 6a241003db | |||
| 33421a3d2a | |||
| 9c376a64b9 | |||
| aec173f9f4 | |||
| 79cadbf9b7 | |||
| 49799abf29 | |||
| d975c46a6f | |||
| 5b86b58104 | |||
| b2ede1c9c7 | |||
| 003bfea125 | |||
| 4876806860 | |||
| 79d1e38f26 | |||
| 91bfc622d1 | |||
| b5ef24a736 | |||
| 6394ece8d3 | |||
| 48d6a3fae8 | |||
| bcd8aa205a | |||
| c5df13a8f2 | |||
| a84ddd9f03 | |||
| 54278bb753 | |||
| 291df2525b | |||
| 21e3f97891 | |||
| 71dd119efe | |||
| ba2f370300 | |||
| 9ca3ab6eba | |||
| 14eb61b75d | |||
| ec91f9ee4f | |||
| 
						 | 
					2fefbe934c | ||
| e65b1f5870 | |||
| 69a0b38b41 | 
@ -30,6 +30,31 @@
 | 
				
			|||||||
            "allowedCommonJsDependencies": ["chart.js", "js-sha256"],
 | 
					            "allowedCommonJsDependencies": ["chart.js", "js-sha256"],
 | 
				
			||||||
            "assets": ["src/favicon.ico", "src/assets"],
 | 
					            "assets": ["src/favicon.ico", "src/assets"],
 | 
				
			||||||
            "styles": [
 | 
					            "styles": [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "input": "node_modules/primeng/resources/themes/saga-blue/theme.css",
 | 
				
			||||||
 | 
					                "inject": true,
 | 
				
			||||||
 | 
					                "bundleName": "saga-blue"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "input": "node_modules/primeflex/themes/primeone-dark.css",
 | 
				
			||||||
 | 
					                "inject": true,
 | 
				
			||||||
 | 
					                "bundleName": "primeone-dark"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "input": "node_modules/primeng/resources/primeng.min.css",
 | 
				
			||||||
 | 
					                "inject": true,
 | 
				
			||||||
 | 
					                "bundleName": "primeng.min"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "input": "node_modules/primeicons/primeicons.css",
 | 
				
			||||||
 | 
					                "inject": true,
 | 
				
			||||||
 | 
					                "bundleName": "primeicons"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "input": "node_modules/primeflex/primeflex.min.css",
 | 
				
			||||||
 | 
					                "inject": true,
 | 
				
			||||||
 | 
					                "bundleName": "primeflex.min"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css",
 | 
					                "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css",
 | 
				
			||||||
                "inject": false,
 | 
					                "inject": false,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										86
									
								
								angular/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										86
									
								
								angular/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -26,7 +26,14 @@
 | 
				
			|||||||
        "@angular/platform-browser": "~18.1.0",
 | 
					        "@angular/platform-browser": "~18.1.0",
 | 
				
			||||||
        "@angular/platform-browser-dynamic": "~18.1.0",
 | 
					        "@angular/platform-browser-dynamic": "~18.1.0",
 | 
				
			||||||
        "@angular/router": "~18.1.0",
 | 
					        "@angular/router": "~18.1.0",
 | 
				
			||||||
 | 
					        "@fullcalendar/angular": "^6.1.16",
 | 
				
			||||||
 | 
					        "@fullcalendar/core": "^6.1.15",
 | 
				
			||||||
 | 
					        "@fullcalendar/daygrid": "^6.1.15",
 | 
				
			||||||
 | 
					        "@fullcalendar/interaction": "^6.1.15",
 | 
				
			||||||
        "bootstrap-icons": "~1.8.0",
 | 
					        "bootstrap-icons": "~1.8.0",
 | 
				
			||||||
 | 
					        "primeflex": "^3.3.1",
 | 
				
			||||||
 | 
					        "primeicons": "^6.0.1",
 | 
				
			||||||
 | 
					        "primeng": "^17.18.0",
 | 
				
			||||||
        "rxjs": "~7.8.0",
 | 
					        "rxjs": "~7.8.0",
 | 
				
			||||||
        "tslib": "^2.0.0",
 | 
					        "tslib": "^2.0.0",
 | 
				
			||||||
        "zone.js": "~0.14.0"
 | 
					        "zone.js": "~0.14.0"
 | 
				
			||||||
@ -3500,6 +3507,47 @@
 | 
				
			|||||||
        "node": ">=6"
 | 
					        "node": ">=6"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fullcalendar/angular": {
 | 
				
			||||||
 | 
					      "version": "6.1.16",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fullcalendar/angular/-/angular-6.1.16.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Qqs0MZPlIDretmWgtOr0H+uiLO6DKeqxqH1Y2oeWufwEbQTaAxhH7mivdTmxL596JkiuJ/1dhCm+v4tVbFb40w==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "tslib": "^2.3.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "@angular/common": "12 - 19",
 | 
				
			||||||
 | 
					        "@angular/core": "12 - 19",
 | 
				
			||||||
 | 
					        "@fullcalendar/core": "~6.1.15"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fullcalendar/core": {
 | 
				
			||||||
 | 
					      "version": "6.1.15",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.15.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-BuX7o6ALpLb84cMw1FCB9/cSgF4JbVO894cjJZ6kP74jzbUZNjtwffwRdA+Id8rrLjT30d/7TrkW90k4zbXB5Q==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "preact": "~10.12.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fullcalendar/daygrid": {
 | 
				
			||||||
 | 
					      "version": "6.1.15",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.15.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-j8tL0HhfiVsdtOCLfzK2J0RtSkiad3BYYemwQKq512cx6btz6ZZ2RNc/hVnIxluuWFyvx5sXZwoeTJsFSFTEFA==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "@fullcalendar/core": "~6.1.15"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@fullcalendar/interaction": {
 | 
				
			||||||
 | 
					      "version": "6.1.15",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.15.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-DOTSkofizM7QItjgu7W68TvKKvN9PSEEvDJceyMbQDvlXHa7pm/WAVtAc6xSDZ9xmB1QramYoWGLHkCYbTW1rQ==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "@fullcalendar/core": "~6.1.15"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@humanwhocodes/config-array": {
 | 
					    "node_modules/@humanwhocodes/config-array": {
 | 
				
			||||||
      "version": "0.13.0",
 | 
					      "version": "0.13.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
 | 
				
			||||||
@ -12977,6 +13025,16 @@
 | 
				
			|||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/preact": {
 | 
				
			||||||
 | 
					      "version": "10.12.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "type": "opencollective",
 | 
				
			||||||
 | 
					        "url": "https://opencollective.com/preact"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/prelude-ls": {
 | 
					    "node_modules/prelude-ls": {
 | 
				
			||||||
      "version": "1.2.1",
 | 
					      "version": "1.2.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
 | 
				
			||||||
@ -13015,6 +13073,34 @@
 | 
				
			|||||||
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
 | 
					        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/primeflex": {
 | 
				
			||||||
 | 
					      "version": "3.3.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==",
 | 
				
			||||||
 | 
					      "license": "MIT"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/primeicons": {
 | 
				
			||||||
 | 
					      "version": "6.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==",
 | 
				
			||||||
 | 
					      "license": "MIT"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/primeng": {
 | 
				
			||||||
 | 
					      "version": "17.18.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/primeng/-/primeng-17.18.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-EcvU/0Ex9QoBR6g6db9fDTCTAmzokW70TV5Oroy2gdvXRr3eqlflnOBoArQsmxTaw1oxSsu68YVj3RvcKYWhTg==",
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "tslib": "^2.3.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "@angular/common": "^17.0.0 || ^18.0.0",
 | 
				
			||||||
 | 
					        "@angular/core": "^17.0.0 || ^18.0.0",
 | 
				
			||||||
 | 
					        "@angular/forms": "^17.0.0 || ^18.0.0",
 | 
				
			||||||
 | 
					        "rxjs": "^6.0.0 || ^7.8.1",
 | 
				
			||||||
 | 
					        "zone.js": "~0.14.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/proc-log": {
 | 
					    "node_modules/proc-log": {
 | 
				
			||||||
      "version": "4.2.0",
 | 
					      "version": "4.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@
 | 
				
			|||||||
    "@abp/ng.setting-management": "~9.0.2",
 | 
					    "@abp/ng.setting-management": "~9.0.2",
 | 
				
			||||||
    "@abp/ng.tenant-management": "~9.0.2",
 | 
					    "@abp/ng.tenant-management": "~9.0.2",
 | 
				
			||||||
    "@abp/ng.theme.lepton-x": "~4.0.3",
 | 
					    "@abp/ng.theme.lepton-x": "~4.0.3",
 | 
				
			||||||
    "@abp/ng.theme.shared": "~9.0.2",
 | 
					    "@abp/ng.theme.shared": "^9.0.4",
 | 
				
			||||||
    "@angular/animations": "~18.1.0",
 | 
					    "@angular/animations": "~18.1.0",
 | 
				
			||||||
    "@angular/common": "~18.1.0",
 | 
					    "@angular/common": "~18.1.0",
 | 
				
			||||||
    "@angular/compiler": "~18.1.0",
 | 
					    "@angular/compiler": "~18.1.0",
 | 
				
			||||||
@ -30,7 +30,14 @@
 | 
				
			|||||||
    "@angular/platform-browser": "~18.1.0",
 | 
					    "@angular/platform-browser": "~18.1.0",
 | 
				
			||||||
    "@angular/platform-browser-dynamic": "~18.1.0",
 | 
					    "@angular/platform-browser-dynamic": "~18.1.0",
 | 
				
			||||||
    "@angular/router": "~18.1.0",
 | 
					    "@angular/router": "~18.1.0",
 | 
				
			||||||
    "bootstrap-icons": "~1.8.0",
 | 
					    "@fullcalendar/angular": "^6.1.16",
 | 
				
			||||||
 | 
					    "@fullcalendar/core": "^6.1.15",
 | 
				
			||||||
 | 
					    "@fullcalendar/daygrid": "^6.1.15",
 | 
				
			||||||
 | 
					    "@fullcalendar/interaction": "^6.1.15",
 | 
				
			||||||
 | 
					"@swimlane/ngx-datatable": "^20.1.0",    "bootstrap-icons": "~1.8.0",
 | 
				
			||||||
 | 
					    "primeflex": "^3.3.1",
 | 
				
			||||||
 | 
					    "primeicons": "^6.0.1",
 | 
				
			||||||
 | 
					    "primeng": "^17.18.0",
 | 
				
			||||||
    "rxjs": "~7.8.0",
 | 
					    "rxjs": "~7.8.0",
 | 
				
			||||||
    "tslib": "^2.0.0",
 | 
					    "tslib": "^2.0.0",
 | 
				
			||||||
    "zone.js": "~0.14.0"
 | 
					    "zone.js": "~0.14.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
import { RouterModule, Routes } from '@angular/router';
 | 
					import { RouterModule, Routes } from '@angular/router';
 | 
				
			||||||
 | 
					import { CustomUsersComponent } from './modules/custom-identity/custom-users/custom-users.component';
 | 
				
			||||||
 | 
					import { CustomRolesComponent } from './modules/custom-identity/custom-roles/custom-roles.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routes: Routes = [
 | 
					const routes: Routes = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@ -11,10 +13,12 @@ const routes: Routes = [
 | 
				
			|||||||
    path: 'account',
 | 
					    path: 'account',
 | 
				
			||||||
    loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()),
 | 
					    loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()),
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  { path: 'identity/users', component: CustomUsersComponent },
 | 
				
			||||||
    path: 'identity',
 | 
					  { path: 'identity/roles', component: CustomRolesComponent },
 | 
				
			||||||
    loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
 | 
					  // {
 | 
				
			||||||
  },
 | 
					  //   path: 'identity',
 | 
				
			||||||
 | 
					  //   loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
 | 
				
			||||||
 | 
					  // },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    path: 'tenant-management',
 | 
					    path: 'tenant-management',
 | 
				
			||||||
    loadChildren: () =>
 | 
					    loadChildren: () =>
 | 
				
			||||||
@ -25,12 +29,37 @@ const routes: Routes = [
 | 
				
			|||||||
    loadChildren: () =>
 | 
					    loadChildren: () =>
 | 
				
			||||||
      import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()),
 | 
					      import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()),
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  { path: 'appointment/appointment-calendar', 
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'appointment/appointment-calendar',
 | 
				
			||||||
    loadChildren: () =>
 | 
					    loadChildren: () =>
 | 
				
			||||||
      import('./appointment/appointment-calendar/appointment-calendar.module').then(m => m.AppointmentCalendarModule) },
 | 
					      import('./appointment/appointment-calendar/appointment-calendar.module').then(
 | 
				
			||||||
  { path: 'appointment/view-appointment', loadChildren: () => import('./appointment/view-appointment/view-appointment.module').then(m => m.ViewAppointmentModule) },
 | 
					        m => m.AppointmentCalendarModule
 | 
				
			||||||
  { path: 'appointment/book-appointment', loadChildren: () => import('./appointment/book-appointment/book-appointment.module').then(m => m.BookAppointmentModule) },
 | 
					      ),
 | 
				
			||||||
  { path: 'appointment/edit-appointment', loadChildren: () => import('./appointment/edit-appointment/edit-appointment.module').then(m => m.EditAppointmentModule) },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'appointment/view-appointment',
 | 
				
			||||||
 | 
					    loadChildren: () =>
 | 
				
			||||||
 | 
					      import('./appointment/view-appointment/view-appointment.module').then(
 | 
				
			||||||
 | 
					        m => m.ViewAppointmentModule
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'patients',
 | 
				
			||||||
 | 
					    loadChildren: () => import('./patients/patients.module').then(m => m.PatientsModule),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'departments',
 | 
				
			||||||
 | 
					    loadChildren: () => import('./departments/departments.module').then(m => m.DepartmentsModule),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    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({
 | 
					@NgModule({
 | 
				
			||||||
 | 
				
			|||||||
@ -30,8 +30,6 @@ import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
 | 
				
			|||||||
    CoreModule,
 | 
					    CoreModule,
 | 
				
			||||||
    ThemeSharedModule,
 | 
					    ThemeSharedModule,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    InternetConnectionStatusComponent,
 | 
					    InternetConnectionStatusComponent,
 | 
				
			||||||
    ThemeLeptonXModule.forRoot(),
 | 
					    ThemeLeptonXModule.forRoot(),
 | 
				
			||||||
    SideMenuLayoutModule.forRoot(),
 | 
					    SideMenuLayoutModule.forRoot(),
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1,6 @@
 | 
				
			|||||||
<p>appointment-calendar works!</p>
 | 
					<full-calendar [options]="calendarOptions" style="cursor: pointer;text-decoration:none;"></full-calendar>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<app-appointment-dialog   [selectedDate]="selectedDate"
 | 
				
			||||||
 | 
					[appointmentId]="appointmentIdToEdit"[isEditMode]="isEditMode"
 | 
				
			||||||
 | 
					 [visible]="isModalVisible"*ngIf="isModalVisible" [name]="'Appointment'" (close)="closeDialog()"></app-appointment-dialog>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					.fc.fc-theme-standard .fc-view-harness .fc-event.fc-daygrid-block-event {
 | 
				
			||||||
 | 
					    color: #ffffff;
 | 
				
			||||||
 | 
					    background: #2563eb;
 | 
				
			||||||
 | 
					    border-color: #2563eb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.fc-daygrid-day-number {
 | 
				
			||||||
 | 
					    text-decoration: none !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,10 +1,109 @@
 | 
				
			|||||||
import { Component } from '@angular/core';
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { CalendarOptions } from '@fullcalendar/core'; // useful for typechecking
 | 
				
			||||||
 | 
					import dayGridPlugin from '@fullcalendar/daygrid';
 | 
				
			||||||
 | 
					import interactionPlugin from '@fullcalendar/interaction';
 | 
				
			||||||
 | 
					import { AppointmentService } from '@proxy/appointments';
 | 
				
			||||||
 | 
					import { PagingSortResultDto } from '@proxy/dto';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-appointment-calendar',
 | 
					  selector: 'app-appointment-calendar',
 | 
				
			||||||
  templateUrl: './appointment-calendar.component.html',
 | 
					  templateUrl: './appointment-calendar.component.html',
 | 
				
			||||||
  styleUrl: './appointment-calendar.component.scss'
 | 
					  styleUrl: './appointment-calendar.component.scss',
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class AppointmentCalendarComponent {
 | 
					export class AppointmentCalendarComponent implements OnInit {
 | 
				
			||||||
 | 
					  appointments: any[] = [];
 | 
				
			||||||
 | 
					  params: PagingSortResultDto;
 | 
				
			||||||
 | 
					  selectedDate: string;
 | 
				
			||||||
 | 
					  isModalVisible: boolean = false;
 | 
				
			||||||
 | 
					  appointmentIdToEdit: string;
 | 
				
			||||||
 | 
					  isEditMode: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private appointmentService: AppointmentService) {}
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					    this.loadAppointments({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  loadAppointments(event: any) {
 | 
				
			||||||
 | 
					    let order = event.sortOrder == 1 ? ' asc' : ' desc';
 | 
				
			||||||
 | 
					    this.params = {
 | 
				
			||||||
 | 
					      skipCount: event.first,
 | 
				
			||||||
 | 
					      maxResultCount: event.rows,
 | 
				
			||||||
 | 
					      sorting: event.sortField + order,
 | 
				
			||||||
 | 
					      search: event.globalFilter == null ? '' : event.globalFilter,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    this.appointmentService.getAppointmentList(this.params).subscribe(data => {
 | 
				
			||||||
 | 
					      this.appointments = data.items;
 | 
				
			||||||
 | 
					      this.updateCalendarEvents();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  updateCalendarEvents() {
 | 
				
			||||||
 | 
					    this.calendarOptions = {
 | 
				
			||||||
 | 
					      initialView: 'dayGridMonth',
 | 
				
			||||||
 | 
					      plugins: [dayGridPlugin, interactionPlugin],
 | 
				
			||||||
 | 
					      events: this.appointments.map(appointment => ({
 | 
				
			||||||
 | 
					        id: appointment.id,
 | 
				
			||||||
 | 
					        title: `${appointment.firstName} ${appointment.lastName}`,
 | 
				
			||||||
 | 
					        date: this.combineDateTime(appointment.dateOfAppointment, appointment.timeOfAppointment),
 | 
				
			||||||
 | 
					      })),
 | 
				
			||||||
 | 
					      dateClick: arg => this.handleDateClick(arg),
 | 
				
			||||||
 | 
					      eventClick: info => this.onEventClick(info),
 | 
				
			||||||
 | 
					      eventContent: function(arg) {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          html: `<div style="background-color: #3788d8; color: white; padding: 5px;cursor: pointer; border-radius: 5px;">
 | 
				
			||||||
 | 
					                   ${arg.event.title}
 | 
				
			||||||
 | 
					                 </div>`
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  combineDateTime(dateStr: string, timeStr: string): string {
 | 
				
			||||||
 | 
					    if (!timeStr) return dateStr; 
 | 
				
			||||||
 | 
					    const date = new Date(dateStr);
 | 
				
			||||||
 | 
					    const [hours, minutes] = timeStr.split(':'); 
 | 
				
			||||||
 | 
					    date.setHours(parseInt(hours, 10), parseInt(minutes, 10), 0);  
 | 
				
			||||||
 | 
					    return date.toISOString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  calendarOptions: CalendarOptions = {
 | 
				
			||||||
 | 
					    initialView: 'dayGridMonth',
 | 
				
			||||||
 | 
					    plugins: [dayGridPlugin, interactionPlugin],
 | 
				
			||||||
 | 
					    dateClick: arg => this.handleDateClick(arg),
 | 
				
			||||||
 | 
					    events: [
 | 
				
			||||||
 | 
					      { title: 'event 1', date: '2025-01-01' },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible = false;
 | 
				
			||||||
 | 
					    this.loadAppointments({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  handleDateClick(arg) {
 | 
				
			||||||
 | 
					    this.selectedDate = arg.dateStr;
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  onModalClose() {
 | 
				
			||||||
 | 
					    this.isModalVisible = false;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					    this.appointmentIdToEdit = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onEventClick(info: any) {
 | 
				
			||||||
 | 
					    this.appointmentIdToEdit = info.event.id;
 | 
				
			||||||
 | 
					    this.isEditMode = true;
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,11 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
import { CommonModule } from '@angular/common';
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { RouterOutlet } from '@angular/router';
 | 
				
			||||||
 | 
					import { FullCalendarModule } from '@fullcalendar/angular';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AppointmentCalendarRoutingModule } from './appointment-calendar-routing.module';
 | 
					import { AppointmentCalendarRoutingModule } from './appointment-calendar-routing.module';
 | 
				
			||||||
import { AppointmentCalendarComponent } from './appointment-calendar.component';
 | 
					import { AppointmentCalendarComponent } from './appointment-calendar.component';
 | 
				
			||||||
 | 
					import { AppointmentDialogComponent } from '../appointment-dialog/appointment-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
@ -11,7 +14,10 @@ import { AppointmentCalendarComponent } from './appointment-calendar.component';
 | 
				
			|||||||
  ],
 | 
					  ],
 | 
				
			||||||
  imports: [
 | 
					  imports: [
 | 
				
			||||||
    CommonModule,
 | 
					    CommonModule,
 | 
				
			||||||
    AppointmentCalendarRoutingModule
 | 
					    AppointmentCalendarRoutingModule,
 | 
				
			||||||
 | 
					    RouterOutlet, 
 | 
				
			||||||
 | 
					    FullCalendarModule,
 | 
				
			||||||
 | 
					    AppointmentDialogComponent
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class AppointmentCalendarModule { }
 | 
					export class AppointmentCalendarModule { }
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,446 @@
 | 
				
			|||||||
 | 
					<div
 | 
				
			||||||
 | 
					  class="modal fade show d-block"
 | 
				
			||||||
 | 
					  tabindex="-1"
 | 
				
			||||||
 | 
					  role="dialog"
 | 
				
			||||||
 | 
					  style="background: rgba(0, 0, 0, 0.5)"
 | 
				
			||||||
 | 
					  *ngIf="visible"
 | 
				
			||||||
 | 
					  aria-label="l('name')"
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					  <div class="modal-dialog modal-lg">
 | 
				
			||||||
 | 
					    <div class="modal-content">
 | 
				
			||||||
 | 
					      <div class="modal-header py-4">
 | 
				
			||||||
 | 
					        <h4 class="text-success mb-0 fs-3 fw-normal">
 | 
				
			||||||
 | 
					          {{ isEditMode ? ('::edit' | abpLocalization) : ('::create' | abpLocalization) }}
 | 
				
			||||||
 | 
					          {{ '::appointmentStatus' | abpLocalization }}
 | 
				
			||||||
 | 
					        </h4>
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          tabindex="0"
 | 
				
			||||||
 | 
					          type="button"
 | 
				
			||||||
 | 
					          (click)="onClose()"
 | 
				
			||||||
 | 
					          class="btn-close"
 | 
				
			||||||
 | 
					          aria-label="Close"
 | 
				
			||||||
 | 
					        ></button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <form #appointmentForm="ngForm" (ngSubmit)="saveAppointment(appointmentForm)">
 | 
				
			||||||
 | 
					        <div class="p-fluid grid justify-content-center">
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="fname"
 | 
				
			||||||
 | 
					              >{{ '::firstName' | abpLocalization }}<span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-user"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                autofocus
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="fname"
 | 
				
			||||||
 | 
					                name="fname"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.firstName"
 | 
				
			||||||
 | 
					                #fnameCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					                minlength="2"
 | 
				
			||||||
 | 
					                maxlength="30"
 | 
				
			||||||
 | 
					                [ngClass]="{
 | 
				
			||||||
 | 
					                  'is-valid': fnameCtrl.valid && fnameCtrl.touched,
 | 
				
			||||||
 | 
					                  'is-invalid': fnameCtrl.invalid && fnameCtrl.touched
 | 
				
			||||||
 | 
					                }"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              <i *ngIf="fnameCtrl.valid && fnameCtrl.touched" class="pi pi-check text-success"></i>
 | 
				
			||||||
 | 
					              <i *ngIf="fnameCtrl.invalid && fnameCtrl.touched" class="pi pi-times text-danger"></i>
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <small class="text-danger" *ngIf="fnameCtrl.invalid && fnameCtrl.touched">
 | 
				
			||||||
 | 
					              <span *ngIf="fnameCtrl.errors?.required">{{
 | 
				
			||||||
 | 
					                '::firstNameRequired' | abpLocalization
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					              <span *ngIf="fnameCtrl.errors?.minlength">
 | 
				
			||||||
 | 
					                {{
 | 
				
			||||||
 | 
					                  '::minLength'
 | 
				
			||||||
 | 
					                    | abpLocalization : { length: fnameCtrl.errors?.minlength.requiredLength }
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					              <span *ngIf="fnameCtrl.errors?.maxlength">{{
 | 
				
			||||||
 | 
					                '::maxLength'
 | 
				
			||||||
 | 
					                  | abpLocalization : { length: fnameCtrl.errors?.maxlength.requiredLength }
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="lname"
 | 
				
			||||||
 | 
					              >{{ '::lastName' | abpLocalization }}<span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-user"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="lname"
 | 
				
			||||||
 | 
					                name="lname"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.lastName"
 | 
				
			||||||
 | 
					                #lnameCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					                minlength="2"
 | 
				
			||||||
 | 
					                maxlength="30"
 | 
				
			||||||
 | 
					                [ngClass]="{
 | 
				
			||||||
 | 
					                  'is-valid': lnameCtrl.valid && lnameCtrl.touched,
 | 
				
			||||||
 | 
					                  'is-invalid': lnameCtrl.invalid && lnameCtrl.touched
 | 
				
			||||||
 | 
					                }"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              <i *ngIf="lnameCtrl.valid && lnameCtrl.touched" class="pi pi-check text-success"></i>
 | 
				
			||||||
 | 
					              <i *ngIf="lnameCtrl.invalid && lnameCtrl.touched" class="pi pi-times text-danger"></i>
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					            <small class="text-danger" *ngIf="lnameCtrl.invalid && lnameCtrl.touched">
 | 
				
			||||||
 | 
					              <span *ngIf="lnameCtrl.errors?.required">{{
 | 
				
			||||||
 | 
					                '::lastNameRequired' | abpLocalization
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					              <span *ngIf="lnameCtrl.errors?.minlength">
 | 
				
			||||||
 | 
					                {{
 | 
				
			||||||
 | 
					                  '::minLength'
 | 
				
			||||||
 | 
					                    | abpLocalization : { length: lnameCtrl.errors?.minlength.requiredLength }
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					              <span *ngIf="lnameCtrl.errors?.maxlength">
 | 
				
			||||||
 | 
					                {{
 | 
				
			||||||
 | 
					                  '::maxLength'
 | 
				
			||||||
 | 
					                    | abpLocalization : { length: lnameCtrl.errors?.maxlength.requiredLength }
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label>{{ '::gender' | abpLocalization }} <span class="text-danger">*</span></label>
 | 
				
			||||||
 | 
					            <div class="flex align-items-center p-input-icon-right">
 | 
				
			||||||
 | 
					              <p-radioButton
 | 
				
			||||||
 | 
					                name="gender"
 | 
				
			||||||
 | 
					                value="1"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.gender"
 | 
				
			||||||
 | 
					                inputId="male"
 | 
				
			||||||
 | 
					                #genderCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					              ></p-radioButton>
 | 
				
			||||||
 | 
					              <label for="male" class="ml-2 mr-3">{{ '::male' | abpLocalization }}</label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <p-radioButton
 | 
				
			||||||
 | 
					                name="gender"
 | 
				
			||||||
 | 
					                value="2"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.gender"
 | 
				
			||||||
 | 
					                inputId="female"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					              ></p-radioButton>
 | 
				
			||||||
 | 
					              <label for="female" class="ml-2">{{ '::female' | abpLocalization }}</label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <i
 | 
				
			||||||
 | 
					                *ngIf="genderCtrl.valid && genderCtrl.touched"
 | 
				
			||||||
 | 
					                class="pi pi-check text-success ml-2"
 | 
				
			||||||
 | 
					              ></i>
 | 
				
			||||||
 | 
					              <i
 | 
				
			||||||
 | 
					                *ngIf="genderCtrl.invalid && genderCtrl.touched"
 | 
				
			||||||
 | 
					                class="pi pi-times text-danger ml-2"
 | 
				
			||||||
 | 
					              ></i>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <small class="text-danger d-block" *ngIf="genderCtrl.invalid && genderCtrl.touched">
 | 
				
			||||||
 | 
					              {{ '::genderRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="mobile"
 | 
				
			||||||
 | 
					              >{{ '::mobileNo' | abpLocalization }} <span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-phone"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="mobile"
 | 
				
			||||||
 | 
					                name="mobile"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.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 d-block" *ngIf="mobileCtrl.invalid && mobileCtrl.touched">
 | 
				
			||||||
 | 
					              <span *ngIf="mobileCtrl.errors?.required">{{
 | 
				
			||||||
 | 
					                '::mobileNoRequired' | abpLocalization
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					              <span *ngIf="mobileCtrl.errors?.pattern">{{
 | 
				
			||||||
 | 
					                '::mobileNoInvalid' | abpLocalization
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-11">
 | 
				
			||||||
 | 
					            {{ '::address' | abpLocalization }} <span class="text-danger">*</span>
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-map-marker"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="address"
 | 
				
			||||||
 | 
					                name="address"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.address"
 | 
				
			||||||
 | 
					                #addressCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					                minlength="5"
 | 
				
			||||||
 | 
					                maxlength="100"
 | 
				
			||||||
 | 
					                [ngClass]="{
 | 
				
			||||||
 | 
					                  'is-valid': addressCtrl.valid && addressCtrl.touched,
 | 
				
			||||||
 | 
					                  'is-invalid': addressCtrl.invalid && addressCtrl.touched
 | 
				
			||||||
 | 
					                }"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              <i
 | 
				
			||||||
 | 
					                *ngIf="addressCtrl.valid && addressCtrl.touched"
 | 
				
			||||||
 | 
					                class="pi pi-check text-success"
 | 
				
			||||||
 | 
					              ></i>
 | 
				
			||||||
 | 
					              <i
 | 
				
			||||||
 | 
					                *ngIf="addressCtrl.invalid && addressCtrl.touched"
 | 
				
			||||||
 | 
					                class="pi pi-times text-danger"
 | 
				
			||||||
 | 
					              ></i>
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					            <small class="text-danger d-block" *ngIf="addressCtrl.invalid && addressCtrl.touched">
 | 
				
			||||||
 | 
					              <span *ngIf="addressCtrl.errors?.required">{{
 | 
				
			||||||
 | 
					                '::addressRequired' | abpLocalization
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					              <span *ngIf="addressCtrl.errors?.minlength">
 | 
				
			||||||
 | 
					                {{
 | 
				
			||||||
 | 
					                  '::minLength'
 | 
				
			||||||
 | 
					                    | abpLocalization : { length: addressCtrl.errors?.minlength.requiredLength }
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					              <span *ngIf="addressCtrl.errors?.maxlength">
 | 
				
			||||||
 | 
					                {{
 | 
				
			||||||
 | 
					                  '::maxLength'
 | 
				
			||||||
 | 
					                    | abpLocalization : { length: addressCtrl.errors?.maxlength.requiredLength }
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="email"
 | 
				
			||||||
 | 
					              >{{ '::emailId' | abpLocalization }} <span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-envelope"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="email"
 | 
				
			||||||
 | 
					                name="email"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.email"
 | 
				
			||||||
 | 
					                #emailCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					                email
 | 
				
			||||||
 | 
					                [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 d-block" *ngIf="emailCtrl.invalid && emailCtrl.touched">
 | 
				
			||||||
 | 
					              <span *ngIf="emailCtrl.errors?.required">{{
 | 
				
			||||||
 | 
					                '::emailRequired' | abpLocalization
 | 
				
			||||||
 | 
					              }}</span>
 | 
				
			||||||
 | 
					              <span *ngIf="emailCtrl.errors?.email">{{ '::emailInvalid' | abpLocalization }}</span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="dob"
 | 
				
			||||||
 | 
					              >{{ '::dateOfBirth' | abpLocalization }} <span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <p-calendar
 | 
				
			||||||
 | 
					              id="dob"
 | 
				
			||||||
 | 
					              required
 | 
				
			||||||
 | 
					              name="dob"
 | 
				
			||||||
 | 
					              [(ngModel)]="Dateofbirth"
 | 
				
			||||||
 | 
					              [showIcon]="true"
 | 
				
			||||||
 | 
					              required
 | 
				
			||||||
 | 
					            ></p-calendar>
 | 
				
			||||||
 | 
					            <small
 | 
				
			||||||
 | 
					              class="p-error"
 | 
				
			||||||
 | 
					              *ngIf="appointmentForm.controls.dob?.invalid && appointmentForm.controls.dob?.touched"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {{ '::dobRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="doctor"
 | 
				
			||||||
 | 
					              >{{ '::consultingDoctor' | abpLocalization }}
 | 
				
			||||||
 | 
					              <span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <p-dropdown
 | 
				
			||||||
 | 
					              id="doctor"
 | 
				
			||||||
 | 
					              name="doctor"
 | 
				
			||||||
 | 
					              [(ngModel)]="appointment.doctorId"
 | 
				
			||||||
 | 
					              [options]="doctorOptions"
 | 
				
			||||||
 | 
					              placeholder="Select Doctor"
 | 
				
			||||||
 | 
					              optionLabel="label"
 | 
				
			||||||
 | 
					              optionValue="value"
 | 
				
			||||||
 | 
					              required
 | 
				
			||||||
 | 
					            ></p-dropdown>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="date"
 | 
				
			||||||
 | 
					              >{{ '::dateOfAppointment' | abpLocalization }}
 | 
				
			||||||
 | 
					              <span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <p-calendar
 | 
				
			||||||
 | 
					              id="date"
 | 
				
			||||||
 | 
					              name="date"
 | 
				
			||||||
 | 
					              [(ngModel)]="AppointmentDate"
 | 
				
			||||||
 | 
					              [showIcon]="true"
 | 
				
			||||||
 | 
					              required
 | 
				
			||||||
 | 
					            ></p-calendar>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="time"
 | 
				
			||||||
 | 
					              >{{ '::timeOfAppointment' | abpLocalization }}
 | 
				
			||||||
 | 
					              <span class="text-danger">*</span></label
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left">
 | 
				
			||||||
 | 
					              <i class="pi pi-clock"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="time"
 | 
				
			||||||
 | 
					                name="time"
 | 
				
			||||||
 | 
					                type="time"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.timeOfAppointment"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="injury">{{ '::injuryCondition' | abpLocalization }}</label>
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left">
 | 
				
			||||||
 | 
					              <i class="pi pi-exclamation-triangle"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="injury"
 | 
				
			||||||
 | 
					                name="injury"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.injuryORContion"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="insurance">
 | 
				
			||||||
 | 
					              {{ '::insuranceProvider' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left">
 | 
				
			||||||
 | 
					              <i class="pi pi-credit-card"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="insurance"
 | 
				
			||||||
 | 
					                name="insuranceProvider"
 | 
				
			||||||
 | 
					                [(ngModel)]="appointment.insuranceProvider"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="status">
 | 
				
			||||||
 | 
					              {{ '::appointmentStatus' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <p-dropdown
 | 
				
			||||||
 | 
					              id="status"
 | 
				
			||||||
 | 
					              name="status"
 | 
				
			||||||
 | 
					              [(ngModel)]="appointment.appointmentStatus"
 | 
				
			||||||
 | 
					              [options]="appointmentStatuses"
 | 
				
			||||||
 | 
					              optionLabel="label"
 | 
				
			||||||
 | 
					              optionValue="value"
 | 
				
			||||||
 | 
					              placeholder="Select Status"
 | 
				
			||||||
 | 
					            ></p-dropdown>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="visitType">
 | 
				
			||||||
 | 
					              {{ '::visitType' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <p-dropdown
 | 
				
			||||||
 | 
					              id="visitType"
 | 
				
			||||||
 | 
					              name="visitType"
 | 
				
			||||||
 | 
					              [(ngModel)]="appointment.visitType"
 | 
				
			||||||
 | 
					              [options]="visitTypes"
 | 
				
			||||||
 | 
					              optionLabel="label"
 | 
				
			||||||
 | 
					              optionValue="value"
 | 
				
			||||||
 | 
					              placeholder="Select Visit Type"
 | 
				
			||||||
 | 
					            ></p-dropdown>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="paymentStatus">
 | 
				
			||||||
 | 
					              {{ '::paymentStatus' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <p-dropdown
 | 
				
			||||||
 | 
					              id="paymentStatus"
 | 
				
			||||||
 | 
					              name="paymentStatus"
 | 
				
			||||||
 | 
					              [(ngModel)]="appointment.paymentStatus"
 | 
				
			||||||
 | 
					              [options]="paymentStatuses"
 | 
				
			||||||
 | 
					              optionLabel="label"
 | 
				
			||||||
 | 
					              optionValue="value"
 | 
				
			||||||
 | 
					              placeholder="Select Payment Status"
 | 
				
			||||||
 | 
					            ></p-dropdown>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-11">
 | 
				
			||||||
 | 
					            <label for="notes">
 | 
				
			||||||
 | 
					              {{ '::notes' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <textarea
 | 
				
			||||||
 | 
					              id="notes"
 | 
				
			||||||
 | 
					              name="notes"
 | 
				
			||||||
 | 
					              [(ngModel)]="appointment.note"
 | 
				
			||||||
 | 
					              rows="5"
 | 
				
			||||||
 | 
					              cols="30"
 | 
				
			||||||
 | 
					              pInputTextarea
 | 
				
			||||||
 | 
					            ></textarea>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-11 flex justify-content-end">
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              type="submit"
 | 
				
			||||||
 | 
					              [label]="'::save' | abpLocalization"
 | 
				
			||||||
 | 
					              class="p-button-success"
 | 
				
			||||||
 | 
					              [disabled]="appointmentForm.invalid"
 | 
				
			||||||
 | 
					            ></button>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              type="button"
 | 
				
			||||||
 | 
					              [label]="'::cancel' | abpLocalization"
 | 
				
			||||||
 | 
					              class="p-button-secondary ml-2"
 | 
				
			||||||
 | 
					              (click)="onClose()"
 | 
				
			||||||
 | 
					            ></button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					.hide_body{
 | 
				
			||||||
 | 
					    scrollbar-width: auto !important;
 | 
				
			||||||
 | 
					    min-height: 150px;
 | 
				
			||||||
 | 
					    max-height: calc(100vh - 13rem);
 | 
				
			||||||
 | 
					    overflow-y: auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .is-valid {
 | 
				
			||||||
 | 
					    border-color: green !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .is-invalid {
 | 
				
			||||||
 | 
					    border-color: red !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					.p-calendar .p-datepicker {
 | 
				
			||||||
 | 
					    z-index: 1050 !important; 
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .modal {
 | 
				
			||||||
 | 
					    z-index: 1040; 
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AppointmentDialogComponent } from './appointment-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('AppointmentDialogComponent', () => {
 | 
				
			||||||
 | 
					  let component: AppointmentDialogComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<AppointmentDialogComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [AppointmentDialogComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(AppointmentDialogComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,187 @@
 | 
				
			|||||||
 | 
					import {ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 | 
				
			||||||
 | 
					import { FormsModule, NgForm } from '@angular/forms';
 | 
				
			||||||
 | 
					import { CreateOrUpdateAppointmentDto } from '@proxy/appoinments/dto';
 | 
				
			||||||
 | 
					import { Gender, appointmentStatus, visitType, paymentStatus } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors';
 | 
				
			||||||
 | 
					import { AppointmentService } from '@proxy/appointments';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { ChipModule } from 'primeng/chip';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { InputTextareaModule } from 'primeng/inputtextarea';
 | 
				
			||||||
 | 
					import { RadioButtonModule } from 'primeng/radiobutton';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { ViewAppointmentRoutingModule } from '../view-appointment/view-appointment-routing.module';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { SharedModule } from 'src/app/shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-appointment-dialog',
 | 
				
			||||||
 | 
					  standalone: true,
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    ViewAppointmentRoutingModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    RadioButtonModule,
 | 
				
			||||||
 | 
					    InputTextareaModule,
 | 
				
			||||||
 | 
					    ChipModule,
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    SharedModule,
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  templateUrl: './appointment-dialog.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './appointment-dialog.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AppointmentDialogComponent implements OnInit {
 | 
				
			||||||
 | 
					  @Input() visible: boolean = false; 
 | 
				
			||||||
 | 
					  @Input() name: string;
 | 
				
			||||||
 | 
					  @Input() isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  @Output() save = new EventEmitter<any>();
 | 
				
			||||||
 | 
					  @Output() close = new EventEmitter<void>(); 
 | 
				
			||||||
 | 
					  @Input() appointmentId: string;
 | 
				
			||||||
 | 
					  @Input() selectedDate: string;
 | 
				
			||||||
 | 
					  appointmentsForDate: any[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loading: boolean = false;
 | 
				
			||||||
 | 
					  AppointmentDialogTitle: string = '';
 | 
				
			||||||
 | 
					  AppointmentDialog: boolean = false;
 | 
				
			||||||
 | 
					  genders = Gender;
 | 
				
			||||||
 | 
					  Dateofbirth: Date = null;
 | 
				
			||||||
 | 
					  AppointmentDate: Date = null;
 | 
				
			||||||
 | 
					  doctors = [];
 | 
				
			||||||
 | 
					  doctorOptions = [];
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private DoctorService: DoctorService,
 | 
				
			||||||
 | 
					    private AppointmentService: AppointmentService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.getdoctorlist();
 | 
				
			||||||
 | 
					    if (!this.isEditMode) {
 | 
				
			||||||
 | 
					      this.appointmentId = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.appointment = {
 | 
				
			||||||
 | 
					        firstName: '',
 | 
				
			||||||
 | 
					        lastName: '',
 | 
				
			||||||
 | 
					        email: '',
 | 
				
			||||||
 | 
					        gender: Gender.Male,
 | 
				
			||||||
 | 
					        dateOfAppointment: '',
 | 
				
			||||||
 | 
					        dob: '',
 | 
				
			||||||
 | 
					        timeOfAppointment: '',
 | 
				
			||||||
 | 
					        mobile: '',
 | 
				
			||||||
 | 
					        injuryORContion: '',
 | 
				
			||||||
 | 
					        note: '',
 | 
				
			||||||
 | 
					        doctorId: '',
 | 
				
			||||||
 | 
					        address: '',
 | 
				
			||||||
 | 
					        appointmentStatus: null,
 | 
				
			||||||
 | 
					        visitType: null,
 | 
				
			||||||
 | 
					        paymentStatus: null,
 | 
				
			||||||
 | 
					        insuranceProvider: '',
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.fetchAppointmentData();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fetchAppointmentData() {
 | 
				
			||||||
 | 
					    this.AppointmentService.getAppointmentById(this.appointmentId).subscribe(result => {
 | 
				
			||||||
 | 
					      this.appointment = result;
 | 
				
			||||||
 | 
					      this.AppointmentDate = new Date(result.dateOfAppointment);
 | 
				
			||||||
 | 
					      this.Dateofbirth = new Date(result.dob);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  appointment: CreateOrUpdateAppointmentDto = {
 | 
				
			||||||
 | 
					    id: '',
 | 
				
			||||||
 | 
					    firstName: '',
 | 
				
			||||||
 | 
					    lastName: '',
 | 
				
			||||||
 | 
					    email: '',
 | 
				
			||||||
 | 
					    gender: Gender.Male,
 | 
				
			||||||
 | 
					    mobile: '',
 | 
				
			||||||
 | 
					    address: '',
 | 
				
			||||||
 | 
					    dob: '',
 | 
				
			||||||
 | 
					    doctorId: '',
 | 
				
			||||||
 | 
					    dateOfAppointment: '',
 | 
				
			||||||
 | 
					    timeOfAppointment: '',
 | 
				
			||||||
 | 
					    injuryORContion: '',
 | 
				
			||||||
 | 
					    note: '',
 | 
				
			||||||
 | 
					    appointmentStatus: appointmentStatus.Scheduled,
 | 
				
			||||||
 | 
					    visitType: visitType.NewPatient,
 | 
				
			||||||
 | 
					    paymentStatus: paymentStatus.Unpaid,
 | 
				
			||||||
 | 
					    insuranceProvider: '',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  saveAppointment(form: NgForm) {
 | 
				
			||||||
 | 
					    if (form.invalid) {
 | 
				
			||||||
 | 
					      Object.values(form.controls).forEach(control => control.markAsTouched());
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.appointment.dob = this.Dateofbirth.toDateString();
 | 
				
			||||||
 | 
					    this.appointment.dateOfAppointment = this.AppointmentDate.toDateString();
 | 
				
			||||||
 | 
					    if (this.isEditMode) {
 | 
				
			||||||
 | 
					      this.AppointmentService.updateAppointment(this.appointment).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Appointment updated successfully', 'Success');
 | 
				
			||||||
 | 
					          this.AppointmentDialog = false;
 | 
				
			||||||
 | 
					          this.onClose();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.toaster.error(error, 'Error');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.AppointmentService.createAppointment(this.appointment).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Appointment created successfully', 'Success');
 | 
				
			||||||
 | 
					          this.AppointmentDialog = false;
 | 
				
			||||||
 | 
					          this.onClose();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.toaster.error(error, 'Error');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getdoctorlist() {
 | 
				
			||||||
 | 
					    this.DoctorService.get().subscribe(result => {
 | 
				
			||||||
 | 
					      this.doctors = result;
 | 
				
			||||||
 | 
					      this.doctorOptions = this.doctors.map(doctor => ({
 | 
				
			||||||
 | 
					        label: `Dr. ${doctor.firstName} ${doctor.lastName}`,
 | 
				
			||||||
 | 
					        value: doctor.id,
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  appointmentStatuses = Object.keys(appointmentStatus)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: appointmentStatus[key as unknown as keyof typeof appointmentStatus],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  visitTypes = Object.keys(visitType)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: visitType[key as unknown as keyof typeof visitType],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  paymentStatuses = Object.keys(paymentStatus)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: paymentStatus[key as unknown as keyof typeof paymentStatus],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onClose() {
 | 
				
			||||||
 | 
					    this.AppointmentDialog = false;
 | 
				
			||||||
 | 
					    this.appointmentId = '';
 | 
				
			||||||
 | 
					    this.close.emit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								angular/src/app/appointment/appointment-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								angular/src/app/appointment/appointment-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { RouterModule, Routes } from '@angular/router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes: Routes = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: '',
 | 
				
			||||||
 | 
					    children: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        path: 'appointment-calendar',
 | 
				
			||||||
 | 
					        loadChildren: () => import('./appointment-calendar/appointment-calendar.module').then(m => m.AppointmentCalendarModule)
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        path: 'view-appointment:date',
 | 
				
			||||||
 | 
					        loadChildren: () => import('./view-appointment/view-appointment.module').then(m => m.ViewAppointmentModule)
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  imports: [RouterModule.forChild(routes)],
 | 
				
			||||||
 | 
					  exports: [RouterModule]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AppointmentRoutingModule { }
 | 
				
			||||||
							
								
								
									
										18
									
								
								angular/src/app/appointment/appointment.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								angular/src/app/appointment/appointment.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AppointmentRoutingModule } from './appointment-routing.module';
 | 
				
			||||||
 | 
					import { AppointmentDialogComponent } from './appointment-dialog/appointment-dialog.component';
 | 
				
			||||||
 | 
					import { SharedModule } from '../shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  declarations: [],
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    SharedModule,
 | 
				
			||||||
 | 
					    AppointmentRoutingModule,
 | 
				
			||||||
 | 
					    AppointmentDialogComponent
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AppointmentModule { }
 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					 | 
				
			||||||
import { RouterModule, Routes } from '@angular/router';
 | 
					 | 
				
			||||||
import { BookAppointmentComponent } from './book-appointment.component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const routes: Routes = [{ path: '', component: BookAppointmentComponent }];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@NgModule({
 | 
					 | 
				
			||||||
  imports: [RouterModule.forChild(routes)],
 | 
					 | 
				
			||||||
  exports: [RouterModule]
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class BookAppointmentRoutingModule { }
 | 
					 | 
				
			||||||
@ -1 +0,0 @@
 | 
				
			|||||||
<p>book-appointment works!</p>
 | 
					 | 
				
			||||||
@ -1,23 +0,0 @@
 | 
				
			|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { BookAppointmentComponent } from './book-appointment.component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('BookAppointmentComponent', () => {
 | 
					 | 
				
			||||||
  let component: BookAppointmentComponent;
 | 
					 | 
				
			||||||
  let fixture: ComponentFixture<BookAppointmentComponent>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  beforeEach(async () => {
 | 
					 | 
				
			||||||
    await TestBed.configureTestingModule({
 | 
					 | 
				
			||||||
      declarations: [BookAppointmentComponent]
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .compileComponents();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fixture = TestBed.createComponent(BookAppointmentComponent);
 | 
					 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					 | 
				
			||||||
    fixture.detectChanges();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('should create', () => {
 | 
					 | 
				
			||||||
    expect(component).toBeTruthy();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,10 +0,0 @@
 | 
				
			|||||||
import { Component } from '@angular/core';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Component({
 | 
					 | 
				
			||||||
  selector: 'app-book-appointment',
 | 
					 | 
				
			||||||
  templateUrl: './book-appointment.component.html',
 | 
					 | 
				
			||||||
  styleUrl: './book-appointment.component.scss'
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class BookAppointmentComponent {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,17 +0,0 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					 | 
				
			||||||
import { CommonModule } from '@angular/common';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { BookAppointmentRoutingModule } from './book-appointment-routing.module';
 | 
					 | 
				
			||||||
import { BookAppointmentComponent } from './book-appointment.component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@NgModule({
 | 
					 | 
				
			||||||
  declarations: [
 | 
					 | 
				
			||||||
    BookAppointmentComponent
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  imports: [
 | 
					 | 
				
			||||||
    CommonModule,
 | 
					 | 
				
			||||||
    BookAppointmentRoutingModule
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class BookAppointmentModule { }
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					 | 
				
			||||||
import { RouterModule, Routes } from '@angular/router';
 | 
					 | 
				
			||||||
import { EditAppointmentComponent } from './edit-appointment.component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const routes: Routes = [{ path: '', component: EditAppointmentComponent }];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@NgModule({
 | 
					 | 
				
			||||||
  imports: [RouterModule.forChild(routes)],
 | 
					 | 
				
			||||||
  exports: [RouterModule]
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class EditAppointmentRoutingModule { }
 | 
					 | 
				
			||||||
@ -1 +0,0 @@
 | 
				
			|||||||
<p>edit-appointment works!</p>
 | 
					 | 
				
			||||||
@ -1,10 +0,0 @@
 | 
				
			|||||||
import { Component } from '@angular/core';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Component({
 | 
					 | 
				
			||||||
  selector: 'app-edit-appointment',
 | 
					 | 
				
			||||||
  templateUrl: './edit-appointment.component.html',
 | 
					 | 
				
			||||||
  styleUrl: './edit-appointment.component.scss'
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class EditAppointmentComponent {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,17 +0,0 @@
 | 
				
			|||||||
import { NgModule } from '@angular/core';
 | 
					 | 
				
			||||||
import { CommonModule } from '@angular/common';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { EditAppointmentRoutingModule } from './edit-appointment-routing.module';
 | 
					 | 
				
			||||||
import { EditAppointmentComponent } from './edit-appointment.component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@NgModule({
 | 
					 | 
				
			||||||
  declarations: [
 | 
					 | 
				
			||||||
    EditAppointmentComponent
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  imports: [
 | 
					 | 
				
			||||||
    CommonModule,
 | 
					 | 
				
			||||||
    EditAppointmentRoutingModule
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class EditAppointmentModule { }
 | 
					 | 
				
			||||||
@ -1 +1,144 @@
 | 
				
			|||||||
<p>view-appointment works!</p>
 | 
					<div>
 | 
				
			||||||
 | 
					  <p-table
 | 
				
			||||||
 | 
					    #dt2
 | 
				
			||||||
 | 
					    dataKey="id"
 | 
				
			||||||
 | 
					    [value]="appointments"
 | 
				
			||||||
 | 
					    [paginator]="true"
 | 
				
			||||||
 | 
					    [rows]="10"
 | 
				
			||||||
 | 
					    [totalRecords]="totalRecords"
 | 
				
			||||||
 | 
					    [lazy]="true"
 | 
				
			||||||
 | 
					    (onLazyLoad)="loadappointments($event)"
 | 
				
			||||||
 | 
					    [rowsPerPageOptions]="[10, 20, 50]"
 | 
				
			||||||
 | 
					    [responsiveLayout]="'scroll'"
 | 
				
			||||||
 | 
					    [globalFilterFields]="['id', 'name', 'status']"
 | 
				
			||||||
 | 
					    [filters]="{ global: { value: '', matchMode: 'contains' } }"
 | 
				
			||||||
 | 
					    class="table table-striped"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <ng-template pTemplate="caption">
 | 
				
			||||||
 | 
					      <div class="flex align-items-center justify-content-between mb-3 gap-3">
 | 
				
			||||||
 | 
					        <h4 class="m-0">{{ '::appointmentList' | abpLocalization }}</h4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="flex-grow-1 flex justify-content-center">
 | 
				
			||||||
 | 
					          <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="{{ '::searchKeyword' | abpLocalization }}"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            pButton
 | 
				
			||||||
 | 
					            class="p-button-rounded p-button-secondary ml-2"
 | 
				
			||||||
 | 
					            (click)="loadappointments($event)"
 | 
				
			||||||
 | 
					            [title]="'::refresh' | abpLocalization"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="pi pi-refresh"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            *ngIf="createPermission"
 | 
				
			||||||
 | 
					            pButton
 | 
				
			||||||
 | 
					            class="p-button-rounded p-button-success ml-2"
 | 
				
			||||||
 | 
					            (click)="openNewAppointmentDialog()"
 | 
				
			||||||
 | 
					            pTooltip="{{ '::addAppointment' | abpLocalization }}"
 | 
				
			||||||
 | 
					            tooltipPosition="left"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="pi pi-plus-circle"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            pButton
 | 
				
			||||||
 | 
					            class="p-button-rounded p-button-warning ml-2"
 | 
				
			||||||
 | 
					            (click)="exportAppointments()"
 | 
				
			||||||
 | 
					            [title]="'::export' | abpLocalization"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="pi pi-download"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <th pSortableColumn="firstName">
 | 
				
			||||||
 | 
					          {{ '::name' | abpLocalization }} <p-sortIcon field="firstName" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="doctor">
 | 
				
			||||||
 | 
					          {{ '::doctor' | abpLocalization }} <p-sortIcon field="doctor" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="gender">
 | 
				
			||||||
 | 
					          {{ '::gender' | abpLocalization }} <p-sortIcon field="gender" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="dateOfAppointment">
 | 
				
			||||||
 | 
					          {{ '::date' | abpLocalization }} <p-sortIcon field="dateOfAppointment" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="timeOfAppointment">
 | 
				
			||||||
 | 
					          {{ '::time' | abpLocalization }} <p-sortIcon field="timeOfAppointment" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th>{{ '::mobileNo' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					        <th>{{ '::email' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="appointmentStatus">
 | 
				
			||||||
 | 
					          {{ '::appointmentStatus' | abpLocalization }} <p-sortIcon field="appointmentStatus" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="visitType">
 | 
				
			||||||
 | 
					          {{ '::visitType' | abpLocalization }} <p-sortIcon field="visitType" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th>{{ '::actions' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template pTemplate="body" let-appointment>
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <td>{{ appointment.firstName }} {{ appointment.lastName }}</td>
 | 
				
			||||||
 | 
					        <td>{{ '::doctorPrefix' | abpLocalization }}  {{ appointment.doctor.firstName }} {{ appointment.doctor.lastName }}</td>
 | 
				
			||||||
 | 
					        <td>
 | 
				
			||||||
 | 
					          <span class="badge" [ngClass]="appointment.gender === 1 ? 'bg-primary' : 'bg-pink'">
 | 
				
			||||||
 | 
					            {{ getGenderLabel(appointment.gender) }}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td>{{ appointment.dateOfAppointment | date }}</td>
 | 
				
			||||||
 | 
					        <td>{{ appointment.timeOfAppointment }}</td>
 | 
				
			||||||
 | 
					        <td>{{ appointment.mobile }}</td>
 | 
				
			||||||
 | 
					        <td>{{ appointment.email }}</td>
 | 
				
			||||||
 | 
					        <td>
 | 
				
			||||||
 | 
					          <span
 | 
				
			||||||
 | 
					            class="badge"
 | 
				
			||||||
 | 
					            [ngClass]="
 | 
				
			||||||
 | 
					              appointment.appointmentStatus === 1
 | 
				
			||||||
 | 
					                ? 'bg-success'
 | 
				
			||||||
 | 
					                : appointment.appointmentStatus === 2
 | 
				
			||||||
 | 
					                ? 'bg-primary'
 | 
				
			||||||
 | 
					                : 'bg-danger'
 | 
				
			||||||
 | 
					            "
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {{ getStatusLabel(appointment.appointmentStatus) }}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td>
 | 
				
			||||||
 | 
					          <span class="badge" [ngClass]="appointment.visitType === 1 ? 'bg-success' : 'bg-danger'">
 | 
				
			||||||
 | 
					            {{ getVisitTypeLabel(appointment.visitType) }}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td class="d-flex">
 | 
				
			||||||
 | 
					          <button class="btn btn-warning btn-sm ml-1" (click)="editAppointment(appointment)">
 | 
				
			||||||
 | 
					            <i class="pi pi-pencil"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button class="btn btn-danger btn-sm ml-1" (click)="deleteAppointment(appointment.id)">
 | 
				
			||||||
 | 
					            <i class="pi pi-trash"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					  </p-table>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<app-appointment-dialog   [appointmentId]="appointmentIdToEdit"[isEditMode]="isEditMode"
 | 
				
			||||||
 | 
					 [visible]="isModalVisible"*ngIf="isModalVisible" 
 | 
				
			||||||
 | 
					 [name]="'::appointment' | abpLocalization"
 | 
				
			||||||
 | 
					 (close)="closeDialog()"></app-appointment-dialog>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					.is-valid {
 | 
				
			||||||
 | 
					  border-color: green !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.is-invalid {
 | 
				
			||||||
 | 
					  border-color: red !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.table-header {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.badge {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  padding: 0.2rem 0.6rem;
 | 
				
			||||||
 | 
					  border-radius: 0.5rem;
 | 
				
			||||||
 | 
					  color: white;
 | 
				
			||||||
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  font-size: 0.8rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.male {
 | 
				
			||||||
 | 
					  background-color: green;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.female {
 | 
				
			||||||
 | 
					  background-color: purple;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pdf-icon {
 | 
				
			||||||
 | 
					  color: red;
 | 
				
			||||||
 | 
					  font-size: 1.2rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.bg-pink {
 | 
				
			||||||
 | 
					  background-color: #ff4081 !important;
 | 
				
			||||||
 | 
					  color: white;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.gap-1 {
 | 
				
			||||||
 | 
					  gap: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,10 +1,192 @@
 | 
				
			|||||||
 | 
					import { Confirmation, ConfirmationService, ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { HttpClient } from '@angular/common/http';
 | 
				
			||||||
import { Component } from '@angular/core';
 | 
					import { Component } from '@angular/core';
 | 
				
			||||||
 | 
					import { CreateOrUpdateAppointmentDto } from '@proxy/appoinments/dto';
 | 
				
			||||||
 | 
					import { AppointmentService } from '@proxy/appointments';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors';
 | 
				
			||||||
 | 
					import { PagingSortResultDto } from '@proxy/dto';
 | 
				
			||||||
 | 
					import { appointmentStatus, Gender, paymentStatus, visitType } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-view-appointment',
 | 
					  selector: 'app-view-appointment',
 | 
				
			||||||
  templateUrl: './view-appointment.component.html',
 | 
					  templateUrl: './view-appointment.component.html',
 | 
				
			||||||
  styleUrl: './view-appointment.component.scss'
 | 
					  styleUrl: './view-appointment.component.scss',
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class ViewAppointmentComponent {
 | 
					export class ViewAppointmentComponent {
 | 
				
			||||||
 | 
					  totalRecords: number = 0;
 | 
				
			||||||
 | 
					  appointmentIdToEdit: string;
 | 
				
			||||||
 | 
					  AppointmentDialogTitle: string = '';
 | 
				
			||||||
 | 
					  AppointmentDialog: boolean = false;
 | 
				
			||||||
 | 
					  patients: [];
 | 
				
			||||||
 | 
					  genders = Gender;
 | 
				
			||||||
 | 
					  Dateofbirth: Date = new Date();
 | 
				
			||||||
 | 
					  AppointmentDate: Date = new Date();
 | 
				
			||||||
 | 
					  isModalVisible:boolean=false;
 | 
				
			||||||
 | 
					  appointmentStatuses = Object.keys(appointmentStatus)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: appointmentStatus[key as unknown as keyof typeof appointmentStatus],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  visitTypes = Object.keys(visitType)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: visitType[key as unknown as keyof typeof visitType],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  paymentStatuses = Object.keys(paymentStatus)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: paymentStatus[key as unknown as keyof typeof paymentStatus],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  loading: boolean = false;
 | 
				
			||||||
 | 
					  params: PagingSortResultDto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  appointment: CreateOrUpdateAppointmentDto = {
 | 
				
			||||||
 | 
					    id: '',
 | 
				
			||||||
 | 
					    firstName: '',
 | 
				
			||||||
 | 
					    lastName: '',
 | 
				
			||||||
 | 
					    email: '',
 | 
				
			||||||
 | 
					    gender: Gender.Male,
 | 
				
			||||||
 | 
					    mobile: '',
 | 
				
			||||||
 | 
					    address: '',
 | 
				
			||||||
 | 
					    dob: '',
 | 
				
			||||||
 | 
					    doctorId: '',
 | 
				
			||||||
 | 
					    dateOfAppointment: '',
 | 
				
			||||||
 | 
					    timeOfAppointment: '',
 | 
				
			||||||
 | 
					    injuryORContion: '',
 | 
				
			||||||
 | 
					    note: '',
 | 
				
			||||||
 | 
					    appointmentStatus: appointmentStatus.Scheduled,
 | 
				
			||||||
 | 
					    visitType: visitType.NewPatient,
 | 
				
			||||||
 | 
					    paymentStatus: paymentStatus.Unpaid,
 | 
				
			||||||
 | 
					    insuranceProvider: '',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  appointments = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  doctors = [];
 | 
				
			||||||
 | 
					  doctorOptions = [];
 | 
				
			||||||
 | 
					  createPermission = true;
 | 
				
			||||||
 | 
					  editPermission = true;
 | 
				
			||||||
 | 
					  deletePermission = true;
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private DoctorService: DoctorService,
 | 
				
			||||||
 | 
					    private AppointmentService: AppointmentService,
 | 
				
			||||||
 | 
					    private confirmation: ConfirmationService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.getdoctorlist();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.loadappointments({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getGenderLabel(gender: number): string {
 | 
				
			||||||
 | 
					    return Gender[gender] ?? 'Unknown';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getStatusLabel(Status: number): string {
 | 
				
			||||||
 | 
					    return appointmentStatus[Status] ?? 'Unknown';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getVisitTypeLabel(VisitType: number): string {
 | 
				
			||||||
 | 
					    return visitType[VisitType] ?? 'Unknown';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadappointments(event: any) {
 | 
				
			||||||
 | 
					    this.loading = true;
 | 
				
			||||||
 | 
					    let order = event.sortOrder == 1 ? ' asc' : ' desc';
 | 
				
			||||||
 | 
					    event.sortField = event.sortField == undefined ? 'id' : event.sortField;
 | 
				
			||||||
 | 
					    this.params = {
 | 
				
			||||||
 | 
					      skipCount: event.first,
 | 
				
			||||||
 | 
					      maxResultCount: event.rows,
 | 
				
			||||||
 | 
					      sorting: event.sortField + order,
 | 
				
			||||||
 | 
					      search: event.globalFilter == null ? '' : event.globalFilter,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.AppointmentService.getAppointmentList(this.params).subscribe(data => {
 | 
				
			||||||
 | 
					      this.appointments = data.items;
 | 
				
			||||||
 | 
					      this.totalRecords = data.totalCount;
 | 
				
			||||||
 | 
					      this.loading = false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  openNewAppointmentDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible=true;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exportAppointments() {
 | 
				
			||||||
 | 
					    this.AppointmentService.getExportAppointmentRecord().subscribe(result => {
 | 
				
			||||||
 | 
					      const binary = atob(result.fileContent);
 | 
				
			||||||
 | 
					      const len = binary.length;
 | 
				
			||||||
 | 
					      const bytes = new Uint8Array(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        bytes[i] = binary.charCodeAt(i);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const blob = new Blob([bytes], { type: 'application/xlsx' });
 | 
				
			||||||
 | 
					      const url = window.URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					      const link = document.createElement('a');
 | 
				
			||||||
 | 
					      link.href = url;
 | 
				
			||||||
 | 
					      link.download = result.fileName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.appendChild(link);
 | 
				
			||||||
 | 
					      link.click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.removeChild(link);
 | 
				
			||||||
 | 
					      window.URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  editAppointment(appointment: any) {
 | 
				
			||||||
 | 
					    this.isEditMode = true;
 | 
				
			||||||
 | 
					    this.appointmentIdToEdit = appointment.id;  
 | 
				
			||||||
 | 
					    this.isModalVisible=true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteAppointment(id: string) {
 | 
				
			||||||
 | 
					   this.confirmation
 | 
				
			||||||
 | 
					         .warn('Do you really want to delete this Appointment?', {
 | 
				
			||||||
 | 
					           key: '::AreYouSure',
 | 
				
			||||||
 | 
					           defaultValue: 'Are you sure?',
 | 
				
			||||||
 | 
					         })
 | 
				
			||||||
 | 
					         .subscribe((status: Confirmation.Status) => {
 | 
				
			||||||
 | 
					           if (status == 'confirm') {
 | 
				
			||||||
 | 
					             this.AppointmentService.deleteAppointmentRecord(id).subscribe(() => {
 | 
				
			||||||
 | 
					               this.toaster.success('Appointment deleted successfully', 'Success');
 | 
				
			||||||
 | 
					               this.loadappointments(this.params);
 | 
				
			||||||
 | 
					             });
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					         });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible = false;
 | 
				
			||||||
 | 
					    this.loadappointments({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getdoctorlist() {
 | 
				
			||||||
 | 
					    this.DoctorService.get().subscribe(result => {
 | 
				
			||||||
 | 
					      this.doctors = result;
 | 
				
			||||||
 | 
					      this.doctorOptions = this.doctors.map(doctor => ({
 | 
				
			||||||
 | 
					        label: `Dr. ${doctor.firstName} ${doctor.lastName}`, 
 | 
				
			||||||
 | 
					        value: doctor.id,
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  saveAppointment(appointmentData: any) {
 | 
				
			||||||
 | 
					    this.closeDialog(); 
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,15 +3,40 @@ import { CommonModule } from '@angular/common';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { ViewAppointmentRoutingModule } from './view-appointment-routing.module';
 | 
					import { ViewAppointmentRoutingModule } from './view-appointment-routing.module';
 | 
				
			||||||
import { ViewAppointmentComponent } from './view-appointment.component';
 | 
					import { ViewAppointmentComponent } from './view-appointment.component';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { FormsModule } from '@angular/forms';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { RadioButtonModule } from 'primeng/radiobutton';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors';
 | 
				
			||||||
 | 
					import { InputTextareaModule } from 'primeng/inputtextarea';
 | 
				
			||||||
 | 
					import { ChipModule } from 'primeng/chip';
 | 
				
			||||||
 | 
					import { AppointmentDialogComponent } from "../appointment-dialog/appointment-dialog.component";
 | 
				
			||||||
 | 
					import { SharedModule } from 'src/app/shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
  declarations: [
 | 
					  declarations: [ViewAppointmentComponent],
 | 
				
			||||||
    ViewAppointmentComponent
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  imports: [
 | 
					  imports: [
 | 
				
			||||||
    CommonModule,
 | 
					    CommonModule,
 | 
				
			||||||
    ViewAppointmentRoutingModule
 | 
					    ViewAppointmentRoutingModule,
 | 
				
			||||||
  ]
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    RadioButtonModule,
 | 
				
			||||||
 | 
					    InputTextareaModule,
 | 
				
			||||||
 | 
					    ChipModule,
 | 
				
			||||||
 | 
					    SharedModule,
 | 
				
			||||||
 | 
					    AppointmentDialogComponent
 | 
				
			||||||
 | 
					],
 | 
				
			||||||
 | 
					  providers:[DoctorService]
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class ViewAppointmentModule {}
 | 
					export class ViewAppointmentModule {}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										176
									
								
								angular/src/app/departments/department-dialog.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								angular/src/app/departments/department-dialog.component.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					<div
 | 
				
			||||||
 | 
					  class="modal fade show d-block"
 | 
				
			||||||
 | 
					  tabindex="-1"
 | 
				
			||||||
 | 
					  role="dialog"
 | 
				
			||||||
 | 
					  style="background: rgba(0, 0, 0, 0.5)"
 | 
				
			||||||
 | 
					  *ngIf="visible"
 | 
				
			||||||
 | 
					  aria-label="{{ '::department' | abpLocalization }}"
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					  <div class="modal-dialog modal-lg">
 | 
				
			||||||
 | 
					    <div class="modal-content">
 | 
				
			||||||
 | 
					      <div class="modal-header py-4">
 | 
				
			||||||
 | 
					        <h4 class="text-success mb-0 fs-3 fw-normal">
 | 
				
			||||||
 | 
					          {{ isEditMode ? ('::edit' | abpLocalization) : ('::create' | abpLocalization) }}
 | 
				
			||||||
 | 
					          {{ '::department' | abpLocalization }}
 | 
				
			||||||
 | 
					        </h4>
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          tabindex="0"
 | 
				
			||||||
 | 
					          type="button"
 | 
				
			||||||
 | 
					          (click)="onClose()"
 | 
				
			||||||
 | 
					          class="btn-close"
 | 
				
			||||||
 | 
					          aria-label="{{ '::close' | abpLocalization }}"
 | 
				
			||||||
 | 
					        ></button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <form #departmentForm="ngForm" (ngSubmit)="saveDepartment(departmentForm)">
 | 
				
			||||||
 | 
					        <div class="p-fluid grid justify-content-center">
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="departmentNo">
 | 
				
			||||||
 | 
					              {{ '::departmentNo' | abpLocalization }} <span class="text-danger">*</span>
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-hashtag"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="departmentNo"
 | 
				
			||||||
 | 
					                name="departmentNo"
 | 
				
			||||||
 | 
					                [(ngModel)]="department.departmentNo"
 | 
				
			||||||
 | 
					                #departmentNoCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					                [ngClass]="{
 | 
				
			||||||
 | 
					                  'is-valid': departmentNoCtrl.valid && departmentNoCtrl.touched,
 | 
				
			||||||
 | 
					                  'is-invalid': departmentNoCtrl.invalid && departmentNoCtrl.touched
 | 
				
			||||||
 | 
					                }"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              <i
 | 
				
			||||||
 | 
					                *ngIf="departmentNoCtrl.valid && departmentNoCtrl.touched"
 | 
				
			||||||
 | 
					                class="pi pi-check text-success"
 | 
				
			||||||
 | 
					              ></i>
 | 
				
			||||||
 | 
					              <i
 | 
				
			||||||
 | 
					                *ngIf="departmentNoCtrl.invalid && departmentNoCtrl.touched"
 | 
				
			||||||
 | 
					                class="pi pi-times text-danger"
 | 
				
			||||||
 | 
					              ></i>
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					            <small class="text-danger" *ngIf="departmentNoCtrl.invalid && departmentNoCtrl.touched">
 | 
				
			||||||
 | 
					              <span *ngIf="departmentNoCtrl.errors?.required">
 | 
				
			||||||
 | 
					                {{ '::departmentNoRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="departmentName">
 | 
				
			||||||
 | 
					              {{ '::departmentName' | abpLocalization }} <span class="text-danger">*</span>
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left p-input-icon-right">
 | 
				
			||||||
 | 
					              <i class="pi pi-building"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="departmentName"
 | 
				
			||||||
 | 
					                name="departmentName"
 | 
				
			||||||
 | 
					                [(ngModel)]="department.departmentName"
 | 
				
			||||||
 | 
					                #departmentNameCtrl="ngModel"
 | 
				
			||||||
 | 
					                required
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					            <small
 | 
				
			||||||
 | 
					              class="text-danger"
 | 
				
			||||||
 | 
					              *ngIf="departmentNameCtrl.invalid && departmentNameCtrl.touched"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <span *ngIf="departmentNameCtrl.errors?.required">
 | 
				
			||||||
 | 
					                {{ '::departmentNameRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </small>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="departmentDate">
 | 
				
			||||||
 | 
					              {{ '::departmentDate' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <p-calendar
 | 
				
			||||||
 | 
					              id="departmentDate"
 | 
				
			||||||
 | 
					              name="departmentDate"
 | 
				
			||||||
 | 
					              [(ngModel)]="Departmentdate"
 | 
				
			||||||
 | 
					              [showIcon]="true"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            </p-calendar>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label for="departmentHead">
 | 
				
			||||||
 | 
					              {{ '::departmentHead' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <span class="p-input-icon-left">
 | 
				
			||||||
 | 
					              <i class="pi pi-user"></i>
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                pInputText
 | 
				
			||||||
 | 
					                id="departmentHead"
 | 
				
			||||||
 | 
					                name="departmentHead"
 | 
				
			||||||
 | 
					                [(ngModel)]="department.departmentHead"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <label>
 | 
				
			||||||
 | 
					              {{ '::status' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <div class="flex align-items-center p-input-icon-right">
 | 
				
			||||||
 | 
					              <p-radioButton
 | 
				
			||||||
 | 
					                name="status"
 | 
				
			||||||
 | 
					                value="Active"
 | 
				
			||||||
 | 
					                [(ngModel)]="department.status"
 | 
				
			||||||
 | 
					                inputId="active"
 | 
				
			||||||
 | 
					              ></p-radioButton>
 | 
				
			||||||
 | 
					              <label for="active" class="ml-2 mr-3">
 | 
				
			||||||
 | 
					                {{ '::active' | abpLocalization }}
 | 
				
			||||||
 | 
					              </label>
 | 
				
			||||||
 | 
					              <p-radioButton
 | 
				
			||||||
 | 
					                name="status"
 | 
				
			||||||
 | 
					                value="Inactive"
 | 
				
			||||||
 | 
					                [(ngModel)]="department.status"
 | 
				
			||||||
 | 
					                inputId="inactive"
 | 
				
			||||||
 | 
					              ></p-radioButton>
 | 
				
			||||||
 | 
					              <label for="inactive" class="ml-2">
 | 
				
			||||||
 | 
					                {{ '::inactive' | abpLocalization }}
 | 
				
			||||||
 | 
					              </label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="field col-md-6"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-11">
 | 
				
			||||||
 | 
					            <label for="description">
 | 
				
			||||||
 | 
					              {{ '::description' | abpLocalization }}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					            <textarea
 | 
				
			||||||
 | 
					              id="description"
 | 
				
			||||||
 | 
					              name="description"
 | 
				
			||||||
 | 
					              [(ngModel)]="department.description"
 | 
				
			||||||
 | 
					              rows="5"
 | 
				
			||||||
 | 
					              cols="30"
 | 
				
			||||||
 | 
					              pInputTextarea
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					            </textarea>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="field col-11 flex justify-content-end">
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              type="submit"
 | 
				
			||||||
 | 
					              [label]="'::save' | abpLocalization"
 | 
				
			||||||
 | 
					              class="p-button-success"
 | 
				
			||||||
 | 
					              [disabled]="departmentForm.invalid"
 | 
				
			||||||
 | 
					            ></button>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              type="button"
 | 
				
			||||||
 | 
					              [label]="'::cancel' | abpLocalization"
 | 
				
			||||||
 | 
					              class="p-button-secondary ml-2"
 | 
				
			||||||
 | 
					              (click)="onClose()"
 | 
				
			||||||
 | 
					            ></button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
							
								
								
									
										21
									
								
								angular/src/app/departments/department-dialog.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								angular/src/app/departments/department-dialog.component.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					.hide_body{
 | 
				
			||||||
 | 
					    scrollbar-width: auto !important;
 | 
				
			||||||
 | 
					    min-height: 150px;
 | 
				
			||||||
 | 
					    max-height: calc(100vh - 13rem);
 | 
				
			||||||
 | 
					    overflow-y: auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .is-valid {
 | 
				
			||||||
 | 
					    border-color: green !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .is-invalid {
 | 
				
			||||||
 | 
					    border-color: red !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					.p-calendar .p-datepicker {
 | 
				
			||||||
 | 
					    z-index: 1050 !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .modal {
 | 
				
			||||||
 | 
					    z-index: 1040; 
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DepartmentDialogComponent } from './department-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('DepartmentDialogComponent', () => {
 | 
				
			||||||
 | 
					  let component: DepartmentDialogComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<DepartmentDialogComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [DepartmentDialogComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(DepartmentDialogComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										107
									
								
								angular/src/app/departments/department-dialog.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								angular/src/app/departments/department-dialog.component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { FormsModule, NgForm } from '@angular/forms';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { ChipModule } from 'primeng/chip';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { InputTextareaModule } from 'primeng/inputtextarea';
 | 
				
			||||||
 | 
					import { RadioButtonModule } from 'primeng/radiobutton';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { CreateDepartmentDto } from '@proxy/dtos';
 | 
				
			||||||
 | 
					import { DepartmentService } from '@proxy/departments';
 | 
				
			||||||
 | 
					import { ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { SharedModule } from '../shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-department-dialog',
 | 
				
			||||||
 | 
					  standalone: true,
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    RadioButtonModule,
 | 
				
			||||||
 | 
					    InputTextareaModule,
 | 
				
			||||||
 | 
					    ChipModule,
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    SharedModule
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  templateUrl: './department-dialog.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './department-dialog.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DepartmentDialogComponent implements OnInit {
 | 
				
			||||||
 | 
					  @Input() visible: boolean = false;
 | 
				
			||||||
 | 
					  @Input() name: string;
 | 
				
			||||||
 | 
					  @Input() isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  @Output() save = new EventEmitter<any>();
 | 
				
			||||||
 | 
					  @Output() close = new EventEmitter<void>();
 | 
				
			||||||
 | 
					  @Input() Id: string;
 | 
				
			||||||
 | 
					  DepartmentDialog: boolean;
 | 
				
			||||||
 | 
					  Departmentdate: Date;
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private DepartmentService: DepartmentService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    if(this.isEditMode){
 | 
				
			||||||
 | 
					      this.fetchDepartmentData();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  department: CreateDepartmentDto = {
 | 
				
			||||||
 | 
					    departmentNo: '',
 | 
				
			||||||
 | 
					    departmentName: '',
 | 
				
			||||||
 | 
					    departmentDate: '',
 | 
				
			||||||
 | 
					    departmentHead: '',
 | 
				
			||||||
 | 
					    description: '',
 | 
				
			||||||
 | 
					    status: '',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fetchDepartmentData() {
 | 
				
			||||||
 | 
					    this.DepartmentService.getDepartmentById(this.Id).subscribe(result => {
 | 
				
			||||||
 | 
					      this.department = result;
 | 
				
			||||||
 | 
					      this.Departmentdate = new Date(result.departmentDate);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  saveDepartment(form: NgForm) {
 | 
				
			||||||
 | 
					    if (form.invalid) {
 | 
				
			||||||
 | 
					      Object.values(form.controls).forEach(control => control.markAsTouched());
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.department.departmentDate = this.Departmentdate.toDateString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.isEditMode) {
 | 
				
			||||||
 | 
					      this.DepartmentService.updateDepartment(this.department).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Department updated successfully', 'Success');
 | 
				
			||||||
 | 
					          this.onClose();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.toaster.error(error, 'Error');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.DepartmentService.createDepartment(this.department).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Department created successfully', 'Success');
 | 
				
			||||||
 | 
					          this.onClose();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.toaster.error(error, 'Error');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  onClose() {
 | 
				
			||||||
 | 
					    this.Id = '';
 | 
				
			||||||
 | 
					    this.close.emit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								angular/src/app/departments/departments-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								angular/src/app/departments/departments-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { RouterModule, Routes } from '@angular/router';
 | 
				
			||||||
 | 
					import { DepartmentsComponent } from './departments.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes: Routes = [
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					      { path: '', component: DepartmentsComponent },
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  imports: [RouterModule.forChild(routes)],
 | 
				
			||||||
 | 
					  exports: [RouterModule]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DepartmentsRoutingModule { }
 | 
				
			||||||
							
								
								
									
										122
									
								
								angular/src/app/departments/departments.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								angular/src/app/departments/departments.component.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					<div>
 | 
				
			||||||
 | 
					    <p-table
 | 
				
			||||||
 | 
					      #dt2
 | 
				
			||||||
 | 
					      dataKey="id"
 | 
				
			||||||
 | 
					      [value]="departments"
 | 
				
			||||||
 | 
					      [paginator]="true"
 | 
				
			||||||
 | 
					      [rows]="10"
 | 
				
			||||||
 | 
					      [totalRecords]="totalRecords"
 | 
				
			||||||
 | 
					      [lazy]="true"
 | 
				
			||||||
 | 
					      (onLazyLoad)="loaddepartments($event)"
 | 
				
			||||||
 | 
					      [rowsPerPageOptions]="[10, 20, 50]"
 | 
				
			||||||
 | 
					      [responsiveLayout]="'scroll'"
 | 
				
			||||||
 | 
					      [globalFilterFields]="['id', 'name', 'status']"
 | 
				
			||||||
 | 
					      [filters]="{ global: { value: '', matchMode: 'contains' } }"
 | 
				
			||||||
 | 
					      class="table table-striped"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <ng-template pTemplate="caption">
 | 
				
			||||||
 | 
					        <div class="flex align-items-center justify-content-between mb-3 gap-3">
 | 
				
			||||||
 | 
					          <h4 class="m-0">{{ '::departmentList' | abpLocalization }}</h4>
 | 
				
			||||||
 | 
					          <div class="flex-grow-1 flex justify-content-center">
 | 
				
			||||||
 | 
					            <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="{{ '::searchKeyword' | abpLocalization }}"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              class="p-button-rounded p-button-secondary ml-2"
 | 
				
			||||||
 | 
					              (click)="loaddepartments($event)"
 | 
				
			||||||
 | 
					              [title]="'::refresh' | abpLocalization"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <i class="pi pi-refresh"></i>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              class="p-button-rounded p-button-success ml-2"
 | 
				
			||||||
 | 
					              (click)="openNewDepartmentDialog()"
 | 
				
			||||||
 | 
					              pTooltip="{{ '::addDepartment' | abpLocalization }}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              tooltipPosition="left"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <i class="pi pi-plus-circle"></i>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              pButton
 | 
				
			||||||
 | 
					              class="p-button-rounded p-button-warning ml-2"
 | 
				
			||||||
 | 
					              (click)="exportDepartments()"
 | 
				
			||||||
 | 
					              [title]="'::export' | abpLocalization"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <i class="pi pi-download"></i>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </ng-template>  
 | 
				
			||||||
 | 
					      <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <th pSortableColumn="departmentNo">
 | 
				
			||||||
 | 
					            {{ '::departmentNumber' | abpLocalization }}
 | 
				
			||||||
 | 
					            <p-sortIcon field="departmentNo" />
 | 
				
			||||||
 | 
					          </th>
 | 
				
			||||||
 | 
					          <th pSortableColumn="departmentName">
 | 
				
			||||||
 | 
					            {{ '::departmentName' | abpLocalization }}
 | 
				
			||||||
 | 
					            <p-sortIcon field="departmentName" />
 | 
				
			||||||
 | 
					          </th>
 | 
				
			||||||
 | 
					          <th pSortableColumn="description">
 | 
				
			||||||
 | 
					            {{ '::description' | abpLocalization }}
 | 
				
			||||||
 | 
					            <p-sortIcon field="description" />
 | 
				
			||||||
 | 
					          </th>
 | 
				
			||||||
 | 
					          <th pSortableColumn="departmentDate">
 | 
				
			||||||
 | 
					            {{ '::date' | abpLocalization }}
 | 
				
			||||||
 | 
					            <p-sortIcon field="departmentDate" />
 | 
				
			||||||
 | 
					          </th>
 | 
				
			||||||
 | 
					          <th pSortableColumn="departmentHead">
 | 
				
			||||||
 | 
					            {{ '::departmentHead' | abpLocalization }}
 | 
				
			||||||
 | 
					            <p-sortIcon field="departmentHead" />
 | 
				
			||||||
 | 
					          </th>
 | 
				
			||||||
 | 
					          <th pSortableColumn="status">
 | 
				
			||||||
 | 
					            {{ '::status' | abpLocalization }}
 | 
				
			||||||
 | 
					            <p-sortIcon field="status" />
 | 
				
			||||||
 | 
					          </th>
 | 
				
			||||||
 | 
					          <th>{{ '::actions' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					      </ng-template>    
 | 
				
			||||||
 | 
					      <ng-template pTemplate="body" let-department>
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <td>{{ department.departmentNo }}</td>
 | 
				
			||||||
 | 
					          <td>{{ department.departmentName }}</td>
 | 
				
			||||||
 | 
					          <td>{{ department.description }}</td>       
 | 
				
			||||||
 | 
					          <td>{{ department.departmentDate | date }}</td>
 | 
				
			||||||
 | 
					          <td>{{ department.departmentHead }}</td>
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            <span class="badge" [ngClass]="department.status === 'Active' ? 'bg-primary' : 'bg-danger'">
 | 
				
			||||||
 | 
					              {{ department.status }}
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td class="d-flex">
 | 
				
			||||||
 | 
					            <button class="btn btn-warning btn-sm ml-1" (click)="editDepartment(department)">
 | 
				
			||||||
 | 
					              <i class="pi pi-pencil"></i>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            <button class="btn btn-danger btn-sm ml-1" (click)="deletedepartment(department.id)">
 | 
				
			||||||
 | 
					              <i class="pi pi-trash"></i>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					      </ng-template>
 | 
				
			||||||
 | 
					    </p-table>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					<app-department-dialog   [Id]="DepartmentIdToEdit"[isEditMode]="isEditMode"
 | 
				
			||||||
 | 
					[visible]="isModalVisible"*ngIf="isModalVisible" 
 | 
				
			||||||
 | 
					[name]="'::department' | abpLocalization"
 | 
				
			||||||
 | 
					(close)="closeDialog()"></app-department-dialog >
 | 
				
			||||||
							
								
								
									
										23
									
								
								angular/src/app/departments/departments.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								angular/src/app/departments/departments.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DepartmentsComponent } from './departments.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('DepartmentsComponent', () => {
 | 
				
			||||||
 | 
					  let component: DepartmentsComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<DepartmentsComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [DepartmentsComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(DepartmentsComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										113
									
								
								angular/src/app/departments/departments.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								angular/src/app/departments/departments.component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					import { Confirmation, ConfirmationService, ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import { DepartmentService } from '@proxy/departments';
 | 
				
			||||||
 | 
					import { PagingSortResultDto } from '@proxy/dto';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-departments',
 | 
				
			||||||
 | 
					  templateUrl: './departments.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './departments.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DepartmentsComponent implements OnInit {
 | 
				
			||||||
 | 
					  totalRecords: number = 0;
 | 
				
			||||||
 | 
					  departments= [];
 | 
				
			||||||
 | 
					  loading: boolean = false;
 | 
				
			||||||
 | 
					  params: PagingSortResultDto;
 | 
				
			||||||
 | 
					  isModalVisible: boolean;
 | 
				
			||||||
 | 
					  isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  DepartmentIdToEdit: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.loaddepartments({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private DepartmentService: DepartmentService,
 | 
				
			||||||
 | 
					    private confirmation: ConfirmationService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					  loaddepartments(event: any) {
 | 
				
			||||||
 | 
					    this.loading = true;
 | 
				
			||||||
 | 
					    let order = event.sortOrder == 1 ? ' asc' : ' desc';
 | 
				
			||||||
 | 
					    event.sortField = event.sortField == undefined ? 'id' : event.sortField;
 | 
				
			||||||
 | 
					    this.params = {
 | 
				
			||||||
 | 
					      skipCount: event.first,
 | 
				
			||||||
 | 
					      maxResultCount: event.rows,
 | 
				
			||||||
 | 
					      sorting: event.sortField + order,
 | 
				
			||||||
 | 
					      search: event.globalFilter == null ? '' : event.globalFilter,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.DepartmentService.getDepartmentList(this.params).subscribe(data => {
 | 
				
			||||||
 | 
					      this.departments = data.items;
 | 
				
			||||||
 | 
					      this.totalRecords = data.totalCount;
 | 
				
			||||||
 | 
					      this.loading = false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  openNewDepartmentDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible=true;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  editDepartment(Department: any) {
 | 
				
			||||||
 | 
					    this.isEditMode = true;
 | 
				
			||||||
 | 
					    this.DepartmentIdToEdit = Department.id;  
 | 
				
			||||||
 | 
					    this.isModalVisible=true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  deletedepartment(id: string) {
 | 
				
			||||||
 | 
					   this.confirmation
 | 
				
			||||||
 | 
					         .warn('Do you really want to delete this Department?', {
 | 
				
			||||||
 | 
					           key: '::AreYouSure',
 | 
				
			||||||
 | 
					           defaultValue: 'Are you sure?',
 | 
				
			||||||
 | 
					         })
 | 
				
			||||||
 | 
					         .subscribe((status: Confirmation.Status) => {
 | 
				
			||||||
 | 
					           if (status == 'confirm') {
 | 
				
			||||||
 | 
					             this.DepartmentService.deleteDepartmentRecord(id).subscribe(() => {
 | 
				
			||||||
 | 
					               this.toaster.success('Deleted successfully', 'Success');
 | 
				
			||||||
 | 
					               this.loaddepartments(this.params);
 | 
				
			||||||
 | 
					             });
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					         });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible = false;
 | 
				
			||||||
 | 
					    this.loaddepartments({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exportDepartments() {
 | 
				
			||||||
 | 
					    this.DepartmentService.getExportDepartmentRecord().subscribe(result => {
 | 
				
			||||||
 | 
					      const binary = atob(result.fileContent);
 | 
				
			||||||
 | 
					      const len = binary.length;
 | 
				
			||||||
 | 
					      const bytes = new Uint8Array(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        bytes[i] = binary.charCodeAt(i);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const blob = new Blob([bytes], { type: 'application/xlsx' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const url = window.URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const link = document.createElement('a');
 | 
				
			||||||
 | 
					      link.href = url;
 | 
				
			||||||
 | 
					      link.download = result.fileName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.appendChild(link);
 | 
				
			||||||
 | 
					      link.click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.removeChild(link);
 | 
				
			||||||
 | 
					      window.URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								angular/src/app/departments/departments.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								angular/src/app/departments/departments.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DepartmentsRoutingModule } from './departments-routing.module';
 | 
				
			||||||
 | 
					import { DepartmentsComponent } from './departments.component';
 | 
				
			||||||
 | 
					import { FormsModule } from '@angular/forms';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { ChipModule } from 'primeng/chip';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { InputTextareaModule } from 'primeng/inputtextarea';
 | 
				
			||||||
 | 
					import { RadioButtonModule } from 'primeng/radiobutton';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { DepartmentDialogComponent } from "./department-dialog.component";
 | 
				
			||||||
 | 
					import { SharedModule } from '../shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  declarations: [DepartmentsComponent],
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    SharedModule,
 | 
				
			||||||
 | 
					    DepartmentsRoutingModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    RadioButtonModule,
 | 
				
			||||||
 | 
					    InputTextareaModule,
 | 
				
			||||||
 | 
					    ChipModule,
 | 
				
			||||||
 | 
					    DepartmentDialogComponent
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DepartmentsModule { }
 | 
				
			||||||
							
								
								
									
										393
									
								
								angular/src/app/doctors/doctor-dialog.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								angular/src/app/doctors/doctor-dialog.component.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,393 @@
 | 
				
			|||||||
 | 
					<div
 | 
				
			||||||
 | 
					  class="modal fade show d-block"
 | 
				
			||||||
 | 
					  tabindex="-1"
 | 
				
			||||||
 | 
					  role="dialog"
 | 
				
			||||||
 | 
					  style="background: rgba(0, 0, 0, 0.5)"
 | 
				
			||||||
 | 
					  *ngIf="visible"
 | 
				
			||||||
 | 
					  aria-label="l('Doctor')"
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					  <div class="modal-dialog modal-lg">
 | 
				
			||||||
 | 
					    <div class="modal-content">
 | 
				
			||||||
 | 
					      <div class="modal-header py-4">
 | 
				
			||||||
 | 
					        <h4 class="text-success mb-0 fs-3 fw-normal">
 | 
				
			||||||
 | 
					          {{ isEditMode ? 'Edit ' : 'Create ' }} Doctor
 | 
				
			||||||
 | 
					        </h4>
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          tabindex="0"
 | 
				
			||||||
 | 
					          type="button"
 | 
				
			||||||
 | 
					          (click)="onClose()"
 | 
				
			||||||
 | 
					          class="btn-close"
 | 
				
			||||||
 | 
					          aria-label="Close"
 | 
				
			||||||
 | 
					        ></button>
 | 
				
			||||||
 | 
					      </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>
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					            <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"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </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"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </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"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </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"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <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-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>
 | 
				
			||||||
 | 
					          <div class="field col-md-5">
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <!-- Button to open the popup -->
 | 
				
			||||||
 | 
					          <div class="col-md-5">
 | 
				
			||||||
 | 
					            <div class="button-container">
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                type="button"
 | 
				
			||||||
 | 
					                label="Select Availability"
 | 
				
			||||||
 | 
					                icon="pi pi-calendar"
 | 
				
			||||||
 | 
					                (click)="openDialog()"
 | 
				
			||||||
 | 
					                class="p-mr-2"
 | 
				
			||||||
 | 
					              ></button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- #incomplete  -->
 | 
				
			||||||
 | 
					<!-- Need to Be Worked on the popup for schedule the time  -->
 | 
				
			||||||
 | 
					          <p-dialog
 | 
				
			||||||
 | 
					            header="Select Days and Times"
 | 
				
			||||||
 | 
					            [(visible)]="displayDialog"
 | 
				
			||||||
 | 
					            modal="true"
 | 
				
			||||||
 | 
					            closable="true"
 | 
				
			||||||
 | 
					            [style]="{ width: '80%', height: '100%' }"
 | 
				
			||||||
 | 
					            [baseZIndex]="10000"
 | 
				
			||||||
 | 
					            styleClass="availability-dialog"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <div class="p-fluid grid">
 | 
				
			||||||
 | 
					              <div class="field col-md-5">
 | 
				
			||||||
 | 
					                <label for="availability">Select Available Days</label>
 | 
				
			||||||
 | 
					                <p-multiSelect
 | 
				
			||||||
 | 
					                  [options]="workScheduleOptions"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selectedDays"
 | 
				
			||||||
 | 
					                  optionLabel="label"
 | 
				
			||||||
 | 
					                  placeholder="Select Days"
 | 
				
			||||||
 | 
					                  (onChange)="onDaysChange($event)"
 | 
				
			||||||
 | 
					                ></p-multiSelect>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <div class="field col-md-1"></div>
 | 
				
			||||||
 | 
					              <div class="field col-md-5">
 | 
				
			||||||
 | 
					                <!-- Display time selection for each selected day -->
 | 
				
			||||||
 | 
					                <div *ngIf="selectedDays && selectedDays.length" class="selected-days-container">
 | 
				
			||||||
 | 
					                  <h3 class="selected-days-header">Set Time for Selected Days</h3>
 | 
				
			||||||
 | 
					                  <div *ngFor="let day of selectedDays" class="day-time-row">
 | 
				
			||||||
 | 
					                    <span class="day-label">{{ day.label }}</span>
 | 
				
			||||||
 | 
					                    <p-dropdown
 | 
				
			||||||
 | 
					                      [options]="timeSlotOptions"
 | 
				
			||||||
 | 
					                      [ngModel]="selectedTimes[day.value]"
 | 
				
			||||||
 | 
					                      (onChange)="onTimeChange(day.value, $event)"
 | 
				
			||||||
 | 
					                      placeholder="Select Time"
 | 
				
			||||||
 | 
					                      style="width: 80%"
 | 
				
			||||||
 | 
					                    ></p-dropdown>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <p-footer>
 | 
				
			||||||
 | 
					              <div class="footer-buttons p-d-flex p-jc-end">
 | 
				
			||||||
 | 
					                <button
 | 
				
			||||||
 | 
					                  pButton
 | 
				
			||||||
 | 
					                  type="button"
 | 
				
			||||||
 | 
					                  label="Save"
 | 
				
			||||||
 | 
					                  icon="pi pi-check"
 | 
				
			||||||
 | 
					                  (click)="saveSelection()"
 | 
				
			||||||
 | 
					                  class="p-button-success p-mr-2"
 | 
				
			||||||
 | 
					                ></button
 | 
				
			||||||
 | 
					                > 
 | 
				
			||||||
 | 
					                <button
 | 
				
			||||||
 | 
					                  pButton
 | 
				
			||||||
 | 
					                  type="button"
 | 
				
			||||||
 | 
					                  label="Cancel"
 | 
				
			||||||
 | 
					                  icon="pi pi-times"
 | 
				
			||||||
 | 
					                  (click)="closeDialog()"
 | 
				
			||||||
 | 
					                  class="p-button-secondary"
 | 
				
			||||||
 | 
					                ></button>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </p-footer>
 | 
				
			||||||
 | 
					          </p-dialog>
 | 
				
			||||||
 | 
					<!-- end  -->
 | 
				
			||||||
 | 
					          <div class="field col-11">
 | 
				
			||||||
 | 
					            <label for="description">Description</label>
 | 
				
			||||||
 | 
					            <textarea
 | 
				
			||||||
 | 
					              id="description"
 | 
				
			||||||
 | 
					              name="description"
 | 
				
			||||||
 | 
					              [(ngModel)]="doctor.description"
 | 
				
			||||||
 | 
					              rows="5"
 | 
				
			||||||
 | 
					              cols="30"
 | 
				
			||||||
 | 
					              pInputTextarea
 | 
				
			||||||
 | 
					            ></textarea>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <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>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
							
								
								
									
										85
									
								
								angular/src/app/doctors/doctor-dialog.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								angular/src/app/doctors/doctor-dialog.component.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					.hide_body{
 | 
				
			||||||
 | 
					    scrollbar-width: auto !important;
 | 
				
			||||||
 | 
					    min-height: 150px;
 | 
				
			||||||
 | 
					    max-height: calc(100vh - 13rem);
 | 
				
			||||||
 | 
					    overflow-y: auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .is-valid {
 | 
				
			||||||
 | 
					    border-color: green !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .is-invalid {
 | 
				
			||||||
 | 
					    border-color: red !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /* Adjust the z-index of the calendar dropdown */
 | 
				
			||||||
 | 
					.p-calendar .p-datepicker {
 | 
				
			||||||
 | 
					    z-index: 1050 !important; /* Make sure it's above other elements */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /* You can also adjust modal z-index if necessary */
 | 
				
			||||||
 | 
					  .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%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .dropdown-item-container {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    justify-content: space-between;
 | 
				
			||||||
 | 
					    padding: 0.5rem 0; /* adjust as needed */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .day-label {
 | 
				
			||||||
 | 
					    flex: 0 0 auto;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .time-options {
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    gap: 0.5rem;
 | 
				
			||||||
 | 
					    justify-content: flex-end;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .time-label {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					/* Style for the container below the multi-select */
 | 
				
			||||||
 | 
					.selected-days-container {
 | 
				
			||||||
 | 
					  margin-top: 1rem;
 | 
				
			||||||
 | 
					  padding: 1rem;
 | 
				
			||||||
 | 
					  border: 1px solid #e0e0e0;
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  background: #fafafa;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Header styling */
 | 
				
			||||||
 | 
					.selected-days-header {
 | 
				
			||||||
 | 
					  margin-bottom: 0.75rem;
 | 
				
			||||||
 | 
					  font-size: 1.1rem;
 | 
				
			||||||
 | 
					  color: #333;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Each day row */
 | 
				
			||||||
 | 
					.day-time-row {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  gap: 1rem;
 | 
				
			||||||
 | 
					  margin-bottom: 0.5rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Fixed width for day label */
 | 
				
			||||||
 | 
					.day-label {
 | 
				
			||||||
 | 
					  width: 100px;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								angular/src/app/doctors/doctor-dialog.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								angular/src/app/doctors/doctor-dialog.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DoctorDialogComponent } from './doctor-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('DoctorDialogComponent', () => {
 | 
				
			||||||
 | 
					  let component: DoctorDialogComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<DoctorDialogComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [DoctorDialogComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(DoctorDialogComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										196
									
								
								angular/src/app/doctors/doctor-dialog.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								angular/src/app/doctors/doctor-dialog.component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,196 @@
 | 
				
			|||||||
 | 
					import { ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 | 
				
			||||||
 | 
					import { FormsModule, NgForm } from '@angular/forms';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors';
 | 
				
			||||||
 | 
					import { CreateDoctorDto } from '@proxy/dtos';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { ChipModule } from 'primeng/chip';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { InputTextareaModule } from 'primeng/inputtextarea';
 | 
				
			||||||
 | 
					import { RadioButtonModule } from 'primeng/radiobutton';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { RatingModule } from 'primeng/rating';
 | 
				
			||||||
 | 
					import { MultiSelectModule } from 'primeng/multiselect';
 | 
				
			||||||
 | 
					import { TimeSlot, WorkSchedule, } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-doctor-dialog',
 | 
				
			||||||
 | 
					  standalone: true,
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    RadioButtonModule,
 | 
				
			||||||
 | 
					    InputTextareaModule,
 | 
				
			||||||
 | 
					    ChipModule,
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    RatingModule,
 | 
				
			||||||
 | 
					    MultiSelectModule,
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  templateUrl: './doctor-dialog.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './doctor-dialog.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DoctorDialogComponent implements OnInit {
 | 
				
			||||||
 | 
					  @Input() visible: boolean = false;
 | 
				
			||||||
 | 
					  @Input() name: string;
 | 
				
			||||||
 | 
					  @Input() isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  @Output() save = new EventEmitter<any>();
 | 
				
			||||||
 | 
					  @Output() close = new EventEmitter<void>();
 | 
				
			||||||
 | 
					  @Input() Id: string;
 | 
				
			||||||
 | 
					  doctorDialog: boolean;
 | 
				
			||||||
 | 
					  JoiningDate: Date;
 | 
				
			||||||
 | 
					  dateofbirth: Date;
 | 
				
			||||||
 | 
					  isSchedulePopupVisible = false;
 | 
				
			||||||
 | 
					  selectedDays: { label: string; value: string }[] = [];
 | 
				
			||||||
 | 
					  selectedTimeSlots: { [key: number]: number | null } = {};
 | 
				
			||||||
 | 
					  displayDialog: boolean = false;
 | 
				
			||||||
 | 
					  selectedDay: any = null;
 | 
				
			||||||
 | 
					  selectedTime: any = null;
 | 
				
			||||||
 | 
					  selectedTimes: { [key: number]: number } = {};
 | 
				
			||||||
 | 
					  workScheduleOptions: { label: string; value: number }[] = [];
 | 
				
			||||||
 | 
					  timeSlotOptions: { label: string; value: number }[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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,
 | 
				
			||||||
 | 
					        rating: 0,
 | 
				
			||||||
 | 
					        clinicLocation: '',
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.initializeWorkScheduleOptions();
 | 
				
			||||||
 | 
					    this.initializeTimeSlotOptions();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  doctor: CreateDoctorDto = {
 | 
				
			||||||
 | 
					    id: '',
 | 
				
			||||||
 | 
					    firstName: '',
 | 
				
			||||||
 | 
					    lastName: '',
 | 
				
			||||||
 | 
					    gender: '',
 | 
				
			||||||
 | 
					    mobile: '',
 | 
				
			||||||
 | 
					    password: '',
 | 
				
			||||||
 | 
					    designation: '',
 | 
				
			||||||
 | 
					    departmentId: '',
 | 
				
			||||||
 | 
					    address: '',
 | 
				
			||||||
 | 
					    email: '',
 | 
				
			||||||
 | 
					    dob: '',
 | 
				
			||||||
 | 
					    education: '',
 | 
				
			||||||
 | 
					    specialization: '',
 | 
				
			||||||
 | 
					    degree: '',
 | 
				
			||||||
 | 
					    joiningDate: '',
 | 
				
			||||||
 | 
					    experience: 0,
 | 
				
			||||||
 | 
					    consultationFee: 0,
 | 
				
			||||||
 | 
					    availability: null,
 | 
				
			||||||
 | 
					    rating: 0,
 | 
				
			||||||
 | 
					    clinicLocation: '',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  openDialog() {
 | 
				
			||||||
 | 
					    this.displayDialog = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  onDaysChange(event: any) {
 | 
				
			||||||
 | 
					    this.selectedDays=event.value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  onTimeChange(dayValue: number, timeValue: number) {
 | 
				
			||||||
 | 
					    this.selectedTimes[dayValue] = timeValue;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.displayDialog = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  initializeWorkScheduleOptions() {
 | 
				
			||||||
 | 
					    this.workScheduleOptions = Object.keys(WorkSchedule)
 | 
				
			||||||
 | 
					      .filter(key => isNaN(Number(key)))
 | 
				
			||||||
 | 
					      .map(key => {
 | 
				
			||||||
 | 
					        const value = WorkSchedule[key as keyof typeof WorkSchedule];
 | 
				
			||||||
 | 
					        return { label: key, value };
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  initializeTimeSlotOptions() {
 | 
				
			||||||
 | 
					    this.timeSlotOptions = Object.keys(TimeSlot)
 | 
				
			||||||
 | 
					      .filter(key => isNaN(Number(key)))
 | 
				
			||||||
 | 
					      .map(key => {
 | 
				
			||||||
 | 
					        const value = TimeSlot[key as keyof typeof TimeSlot];
 | 
				
			||||||
 | 
					        return { label: key, value };
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  saveSelection() {
 | 
				
			||||||
 | 
					    const availability = this.selectedDays.map(day => ({
 | 
				
			||||||
 | 
					      day: day.value,
 | 
				
			||||||
 | 
					      time: this.selectedTimes[day.value] || null,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    this.displayDialog = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fetchDoctorData() {
 | 
				
			||||||
 | 
					    this.DoctorService.getDoctorById(this.Id).subscribe(result => {
 | 
				
			||||||
 | 
					      this.doctor = result;
 | 
				
			||||||
 | 
					      this.JoiningDate = new Date(result.joiningDate);
 | 
				
			||||||
 | 
					      this.dateofbirth = new Date(result.dob);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  saveDoctor(form: NgForm) {
 | 
				
			||||||
 | 
					    if (form.invalid) {
 | 
				
			||||||
 | 
					      Object.values(form.controls).forEach(control => control.markAsTouched());
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.doctor.dob = this.dateofbirth.toDateString();
 | 
				
			||||||
 | 
					    this.doctor.joiningDate = this.JoiningDate.toDateString();
 | 
				
			||||||
 | 
					    if (this.isEditMode) {
 | 
				
			||||||
 | 
					      this.DoctorService.updatDoctor(this.doctor).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Updated Successfully', 'Success');
 | 
				
			||||||
 | 
					          this.onClose();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.toaster.error(error, 'Error');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.DoctorService.createDoctor(this.doctor).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('created successfully', 'Success');
 | 
				
			||||||
 | 
					          this.onClose();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.toaster.error(error, 'Error');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  onClose() {
 | 
				
			||||||
 | 
					    this.Id = '';
 | 
				
			||||||
 | 
					    this.close.emit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								angular/src/app/doctors/doctors-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								angular/src/app/doctors/doctors-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { RouterModule, Routes } from '@angular/router';
 | 
				
			||||||
 | 
					import { DoctorsComponent } from './doctors.component';
 | 
				
			||||||
 | 
					import { ShiftManagementComponent } from './shift-management/shift-management.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes: Routes = [
 | 
				
			||||||
 | 
					  { path: '', component: DoctorsComponent },
 | 
				
			||||||
 | 
					  { path: 'shift-management/:id', component: ShiftManagementComponent },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  imports: [RouterModule.forChild(routes)],
 | 
				
			||||||
 | 
					  exports: [RouterModule],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DoctorsRoutingModule {}
 | 
				
			||||||
							
								
								
									
										119
									
								
								angular/src/app/doctors/doctors.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								angular/src/app/doctors/doctors.component.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					<div>
 | 
				
			||||||
 | 
					  <p-table
 | 
				
			||||||
 | 
					    #dt
 | 
				
			||||||
 | 
					    dataKey="id"
 | 
				
			||||||
 | 
					    [value]="doctors"
 | 
				
			||||||
 | 
					    [paginator]="true"
 | 
				
			||||||
 | 
					    [rows]="10"
 | 
				
			||||||
 | 
					    [totalRecords]="totalRecords"
 | 
				
			||||||
 | 
					    [lazy]="true"
 | 
				
			||||||
 | 
					    (onLazyLoad)="loadDoctors($event)"
 | 
				
			||||||
 | 
					    [rowsPerPageOptions]="[10, 20, 50]"
 | 
				
			||||||
 | 
					    [responsiveLayout]="'scroll'"
 | 
				
			||||||
 | 
					    [globalFilterFields]="['id', 'firstName', 'lastName', 'mobile', 'email', 'specialization']"
 | 
				
			||||||
 | 
					    [filters]="{ global: { value: '', matchMode: 'contains' } }"
 | 
				
			||||||
 | 
					    class="table table-striped"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <ng-template pTemplate="caption">
 | 
				
			||||||
 | 
					      <div class="flex align-items-center justify-content-between mb-3 gap-3">
 | 
				
			||||||
 | 
					        <h4 class="m-0">{{ '::doctorList' | abpLocalization }}</h4>
 | 
				
			||||||
 | 
					        <div class="flex-grow-1 flex justify-content-center">
 | 
				
			||||||
 | 
					          <div class="input-group">
 | 
				
			||||||
 | 
					            <span class="input-group-text"><i class="pi pi-search"></i></span>
 | 
				
			||||||
 | 
					            <input
 | 
				
			||||||
 | 
					              pInputText
 | 
				
			||||||
 | 
					              type="text"
 | 
				
			||||||
 | 
					              class="form-control"
 | 
				
			||||||
 | 
					              (input)="dt.filterGlobal($event.target.value, 'contains')"
 | 
				
			||||||
 | 
					              [(ngModel)]="globalFilter"
 | 
				
			||||||
 | 
					              placeholder="{{ '::searchKeyword' | abpLocalization }}"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            pButton
 | 
				
			||||||
 | 
					            class="p-button-rounded p-button-secondary ml-2"
 | 
				
			||||||
 | 
					            (click)="loadDoctors($event)"
 | 
				
			||||||
 | 
					            [title]="'::refresh' | abpLocalization"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="pi pi-refresh"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            pButton
 | 
				
			||||||
 | 
					            class="p-button-rounded p-button-success ml-2"
 | 
				
			||||||
 | 
					            (click)="openNewDoctorDialog()"
 | 
				
			||||||
 | 
					            pTooltip="{{ '::addDoctor' | abpLocalization }}"
 | 
				
			||||||
 | 
					            tooltipPosition="left"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="pi pi-plus-circle"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button pButton class="p-button-rounded p-button-warning ml-2" (click)="exportDoctors()"
 | 
				
			||||||
 | 
					          [title]="'::export' | abpLocalization"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <i class="pi pi-download"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					    <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <th pSortableColumn="firstName">
 | 
				
			||||||
 | 
					          {{ '::name' | abpLocalization }}
 | 
				
			||||||
 | 
					          <p-sortIcon field="firstName" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="mobile">
 | 
				
			||||||
 | 
					          {{ '::mobile' | abpLocalization }}
 | 
				
			||||||
 | 
					          <p-sortIcon field="mobile" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="email">
 | 
				
			||||||
 | 
					          {{ '::email' | abpLocalization }}
 | 
				
			||||||
 | 
					          <p-sortIcon field="email" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="specialization">
 | 
				
			||||||
 | 
					          {{ '::specialization' | abpLocalization }}
 | 
				
			||||||
 | 
					          <p-sortIcon field="specialization" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="experience">
 | 
				
			||||||
 | 
					          {{ '::experience' | abpLocalization }}
 | 
				
			||||||
 | 
					          <p-sortIcon field="experience" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="rating">
 | 
				
			||||||
 | 
					          {{ '::rating' | abpLocalization }}
 | 
				
			||||||
 | 
					          <p-sortIcon field="rating" />
 | 
				
			||||||
 | 
					        </th>
 | 
				
			||||||
 | 
					        <th>{{ '::actions' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					    <ng-template pTemplate="body" let-doctor>
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <td>{{ '::doctorPrefix' | abpLocalization }} {{ doctor.firstName }} {{ doctor.lastName }}</td>
 | 
				
			||||||
 | 
					        <td>{{ doctor.mobile }}</td>
 | 
				
			||||||
 | 
					        <td>{{ doctor.email }}</td>
 | 
				
			||||||
 | 
					        <td>{{ doctor.specialization }}</td>
 | 
				
			||||||
 | 
					        <td>{{ doctor.experience }} {{ '::years' | abpLocalization }}</td>
 | 
				
			||||||
 | 
					        <td>{{ doctor.rating }}</td>
 | 
				
			||||||
 | 
					        <td class="d-flex">
 | 
				
			||||||
 | 
					          <button class="btn btn-warning btn-sm ml-1" (click)="editDoctor(doctor)">
 | 
				
			||||||
 | 
					            <i class="pi pi-pencil"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button class="btn btn-danger btn-sm ml-1" (click)="deleteDoctor(doctor.id)">
 | 
				
			||||||
 | 
					            <i class="pi pi-trash"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button class="btn btn-warning btn-sm ml-1" (click)="GotoShiftManagement(doctor.id)">
 | 
				
			||||||
 | 
					            <i class="pi pi-arrow-right"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					  </p-table>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<app-doctor-dialog
 | 
				
			||||||
 | 
					  [Id]="DoctorIdToEdit"
 | 
				
			||||||
 | 
					  [isEditMode]="isEditMode"
 | 
				
			||||||
 | 
					  [visible]="isModalVisible"
 | 
				
			||||||
 | 
					  *ngIf="isModalVisible"
 | 
				
			||||||
 | 
					  [name]="'::doctor' | abpLocalization"
 | 
				
			||||||
 | 
					  (close)="closeDialog()"
 | 
				
			||||||
 | 
					></app-doctor-dialog>
 | 
				
			||||||
							
								
								
									
										23
									
								
								angular/src/app/doctors/doctors.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								angular/src/app/doctors/doctors.component.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DoctorsComponent } from './doctors.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('DoctorsComponent', () => {
 | 
				
			||||||
 | 
					  let component: DoctorsComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<DoctorsComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [DoctorsComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(DoctorsComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										112
									
								
								angular/src/app/doctors/doctors.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								angular/src/app/doctors/doctors.component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import { Router } from '@angular/router';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors';
 | 
				
			||||||
 | 
					import { PagingSortResultDto } from '@proxy/dto';
 | 
				
			||||||
 | 
					import { workScheduleOptions } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-doctors',
 | 
				
			||||||
 | 
					  templateUrl: './doctors.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './doctors.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DoctorsComponent implements OnInit {
 | 
				
			||||||
 | 
					  totalRecords: number = 0;
 | 
				
			||||||
 | 
					  doctors = [];
 | 
				
			||||||
 | 
					  loading: boolean = false;
 | 
				
			||||||
 | 
					  params: PagingSortResultDto;
 | 
				
			||||||
 | 
					  isModalVisible: boolean = false;
 | 
				
			||||||
 | 
					  isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  DoctorIdToEdit: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.loadDoctors({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private DoctorService: DoctorService,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private router: Router
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					  workSchedule = Object.keys(workScheduleOptions)
 | 
				
			||||||
 | 
					    .filter(key => !isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: workScheduleOptions[key as unknown as keyof typeof workScheduleOptions],
 | 
				
			||||||
 | 
					      value: Number(key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadDoctors(event: any) {
 | 
				
			||||||
 | 
					    this.loading = true;
 | 
				
			||||||
 | 
					    let order = event.sortOrder == 1 ? ' asc' : ' desc';
 | 
				
			||||||
 | 
					    event.sortField = event.sortField == undefined ? 'id' : event.sortField;
 | 
				
			||||||
 | 
					    this.params = {
 | 
				
			||||||
 | 
					      skipCount: event.first,
 | 
				
			||||||
 | 
					      maxResultCount: event.rows,
 | 
				
			||||||
 | 
					      sorting: event.sortField + order,
 | 
				
			||||||
 | 
					      search: event.globalFilter == null ? '' : event.globalFilter,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.DoctorService.getDoctorList(this.params).subscribe(data => {
 | 
				
			||||||
 | 
					      this.doctors = data.items;
 | 
				
			||||||
 | 
					      this.totalRecords = data.totalCount;
 | 
				
			||||||
 | 
					      this.loading = false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  openNewDoctorDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  editDoctor(Doctor: any) {
 | 
				
			||||||
 | 
					    this.isEditMode = true;
 | 
				
			||||||
 | 
					    this.DoctorIdToEdit = Doctor.id;
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.isModalVisible = false;
 | 
				
			||||||
 | 
					    this.loadDoctors({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exportDoctors() {
 | 
				
			||||||
 | 
					    this.DoctorService.getExportDoctorsRecord().subscribe(result => {
 | 
				
			||||||
 | 
					      const binary = atob(result.fileContent);
 | 
				
			||||||
 | 
					      const len = binary.length;
 | 
				
			||||||
 | 
					      const bytes = new Uint8Array(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        bytes[i] = binary.charCodeAt(i);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const blob = new Blob([bytes], { type: 'application/xlsx' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const url = window.URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const link = document.createElement('a');
 | 
				
			||||||
 | 
					      link.href = url;
 | 
				
			||||||
 | 
					      link.download = result.fileName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.appendChild(link);
 | 
				
			||||||
 | 
					      link.click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.removeChild(link);
 | 
				
			||||||
 | 
					      window.URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  GotoShiftManagement(id:string) {
 | 
				
			||||||
 | 
					    this.router.navigate(['/doctors/shift-management', id]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								angular/src/app/doctors/doctors.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								angular/src/app/doctors/doctors.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { DoctorsRoutingModule } from './doctors-routing.module';
 | 
				
			||||||
 | 
					import { DoctorsComponent } from './doctors.component';
 | 
				
			||||||
 | 
					import { FormsModule } from '@angular/forms';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { ChipModule } from 'primeng/chip';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { InputTextareaModule } from 'primeng/inputtextarea';
 | 
				
			||||||
 | 
					import { RadioButtonModule } from 'primeng/radiobutton';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { DoctorDialogComponent } from './doctor-dialog.component';
 | 
				
			||||||
 | 
					import { ShiftManagementComponent } from './shift-management/shift-management.component';
 | 
				
			||||||
 | 
					import { SharedModule } from '../shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  declarations: [DoctorsComponent,ShiftManagementComponent],
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    DoctorsRoutingModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    RadioButtonModule,
 | 
				
			||||||
 | 
					    InputTextareaModule,
 | 
				
			||||||
 | 
					    ChipModule,
 | 
				
			||||||
 | 
					    DoctorDialogComponent,
 | 
				
			||||||
 | 
					    SharedModule
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DoctorsModule {}
 | 
				
			||||||
@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					<div class="card p-4 shift-management">
 | 
				
			||||||
 | 
					  <h4>Shift Management</h4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div class="field">
 | 
				
			||||||
 | 
					    <p-dropdown
 | 
				
			||||||
 | 
					      [options]="doctors"
 | 
				
			||||||
 | 
					      [(ngModel)]="selectedDoctor"
 | 
				
			||||||
 | 
					      placeholder="Select Doctor"
 | 
				
			||||||
 | 
					      optionLabel="label"
 | 
				
			||||||
 | 
					      optionValue="value"
 | 
				
			||||||
 | 
					      class="w-full"
 | 
				
			||||||
 | 
					      (onChange)="onDoctorSelect($event.value)"
 | 
				
			||||||
 | 
					    ></p-dropdown>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div *ngIf="selectedDoctor" class="shift-grid-container">
 | 
				
			||||||
 | 
					    <div class="shift-column-layout">
 | 
				
			||||||
 | 
					      <!-- Column Layout for Days & Time Slots -->
 | 
				
			||||||
 | 
					      <div *ngFor="let day of selectedDays" class="shift-column">
 | 
				
			||||||
 | 
					        <div class="day-header">
 | 
				
			||||||
 | 
					          <strong>{{ day }}</strong>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <p-dropdown
 | 
				
			||||||
 | 
					          [options]="timeSlotOptions"
 | 
				
			||||||
 | 
					          [(ngModel)]="selectedTimeSlots[day]"
 | 
				
			||||||
 | 
					          optionLabel="label"
 | 
				
			||||||
 | 
					          optionValue="value"
 | 
				
			||||||
 | 
					          placeholder="Select Time Slot"
 | 
				
			||||||
 | 
					          class="w-full"
 | 
				
			||||||
 | 
					        ></p-dropdown>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Buttons -->
 | 
				
			||||||
 | 
					    <div class="button-container">
 | 
				
			||||||
 | 
					      <button
 | 
				
			||||||
 | 
					        pButton
 | 
				
			||||||
 | 
					        type="button"
 | 
				
			||||||
 | 
					        label="Save Shift"
 | 
				
			||||||
 | 
					        class="p-button-success mt-3"
 | 
				
			||||||
 | 
					        (click)="saveShiftData()"
 | 
				
			||||||
 | 
					      ></button>
 | 
				
			||||||
 | 
					      <button
 | 
				
			||||||
 | 
					        pButton
 | 
				
			||||||
 | 
					        type="button"
 | 
				
			||||||
 | 
					        label="Back"
 | 
				
			||||||
 | 
					        class="p-button-primary mt-3"
 | 
				
			||||||
 | 
					        (click)="backToDoctor()"
 | 
				
			||||||
 | 
					      ></button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					.shift-column-layout {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  gap: 20px;
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.shift-column {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  background: #f8f9fa;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  padding: 15px;
 | 
				
			||||||
 | 
					  min-width: 150px;
 | 
				
			||||||
 | 
					  max-width: 180px;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease-in-out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.shift-column:hover {
 | 
				
			||||||
 | 
					  transform: scale(1.05);
 | 
				
			||||||
 | 
					  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.day-header {
 | 
				
			||||||
 | 
					  font-size: 16px;
 | 
				
			||||||
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  margin-bottom: 10px;
 | 
				
			||||||
 | 
					  color: #007bff;
 | 
				
			||||||
 | 
					  text-transform: uppercase;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.dropdown-item {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Center the button (optional) */
 | 
				
			||||||
 | 
					.button-container {
 | 
				
			||||||
 | 
					  margin: 1rem 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Styling for the dialog */
 | 
				
			||||||
 | 
					.availability-dialog .p-dialog-header {
 | 
				
			||||||
 | 
					  background-color: #1976d2;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.availability-dialog .p-dialog-content {
 | 
				
			||||||
 | 
					  padding: 1.5rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.footer-buttons {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: flex-end;
 | 
				
			||||||
 | 
					  gap: 0.5rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Optional: Adjust field spacing */
 | 
				
			||||||
 | 
					.field {
 | 
				
			||||||
 | 
					  margin-bottom: 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,18 +1,18 @@
 | 
				
			|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EditAppointmentComponent } from './edit-appointment.component';
 | 
					import { ShiftManagementComponent } from './shift-management.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('EditAppointmentComponent', () => {
 | 
					describe('ShiftManagementComponent', () => {
 | 
				
			||||||
  let component: EditAppointmentComponent;
 | 
					  let component: ShiftManagementComponent;
 | 
				
			||||||
  let fixture: ComponentFixture<EditAppointmentComponent>;
 | 
					  let fixture: ComponentFixture<ShiftManagementComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  beforeEach(async () => {
 | 
					  beforeEach(async () => {
 | 
				
			||||||
    await TestBed.configureTestingModule({
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
      declarations: [EditAppointmentComponent]
 | 
					      imports: [ShiftManagementComponent]
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .compileComponents();
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fixture = TestBed.createComponent(EditAppointmentComponent);
 | 
					    fixture = TestBed.createComponent(ShiftManagementComponent);
 | 
				
			||||||
    component = fixture.componentInstance;
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
    fixture.detectChanges();
 | 
					    fixture.detectChanges();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@ -0,0 +1,173 @@
 | 
				
			|||||||
 | 
					import { ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core';
 | 
				
			||||||
 | 
					import { ActivatedRoute, Router } from '@angular/router';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors';
 | 
				
			||||||
 | 
					import { CreateUpdateShiftManagementDto } from '@proxy/doctors/dto';
 | 
				
			||||||
 | 
					import { TimeSlot, WorkSchedule } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					import { ShiftManagementService } from '@proxy/shift-management';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-shift-management',
 | 
				
			||||||
 | 
					  templateUrl: './shift-management.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './shift-management.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class ShiftManagementComponent implements OnInit {
 | 
				
			||||||
 | 
					  doctors = [];
 | 
				
			||||||
 | 
					  selectedDoctor: string | null = null;
 | 
				
			||||||
 | 
					  selectedDoctorName = '';
 | 
				
			||||||
 | 
					  selectedDoctorEmail = '';
 | 
				
			||||||
 | 
					  selectedDoctorPhone = '';
 | 
				
			||||||
 | 
					  selectedDoctorSpecialty = '';
 | 
				
			||||||
 | 
					  selectedDays = [];
 | 
				
			||||||
 | 
					  selectedTimeSlots: { [key: string]: TimeSlot } = {};
 | 
				
			||||||
 | 
					  DoctorID: string;
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private DoctorService: DoctorService,
 | 
				
			||||||
 | 
					    private shiftService: ShiftManagementService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService,
 | 
				
			||||||
 | 
					    private router: Router,
 | 
				
			||||||
 | 
					    private route: ActivatedRoute
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.getdoctorlist();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      this.DoctorID = this.route.snapshot.paramMap.get('id');
 | 
				
			||||||
 | 
					      this.onDoctorSelect(this.DoctorID);
 | 
				
			||||||
 | 
					    }, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getdoctorlist() {
 | 
				
			||||||
 | 
					    this.DoctorService.get().subscribe(result => {
 | 
				
			||||||
 | 
					      const doctors = result;
 | 
				
			||||||
 | 
					      this.doctors = doctors.map(doctor => ({
 | 
				
			||||||
 | 
					        label: `Dr. ${doctor.firstName} ${doctor.lastName}`,
 | 
				
			||||||
 | 
					        value: doctor.id,
 | 
				
			||||||
 | 
					        availability: doctor.availability,
 | 
				
			||||||
 | 
					        email: doctor.email,
 | 
				
			||||||
 | 
					        phoneNo: doctor.mobile,
 | 
				
			||||||
 | 
					        specialist: doctor.specialization,
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  shiftData: CreateUpdateShiftManagementDto = {
 | 
				
			||||||
 | 
					    doctorId: this.selectedDoctor,
 | 
				
			||||||
 | 
					    shifts: {} as Record<WorkSchedule, TimeSlot>,
 | 
				
			||||||
 | 
					    isActive: true,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  workScheduleOptions = Object.keys(WorkSchedule)
 | 
				
			||||||
 | 
					    .filter(key => isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: key.replace(/([A-Z])/g, ' $1').trim(),
 | 
				
			||||||
 | 
					      value: WorkSchedule[key as keyof typeof WorkSchedule],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getTimeRangeLabel(value: TimeSlot): string {
 | 
				
			||||||
 | 
					    const timeRanges = {
 | 
				
			||||||
 | 
					      [TimeSlot.TenToSeven]: { start: 10, end: 19 },
 | 
				
			||||||
 | 
					      [TimeSlot.NineToFive]: { start: 9, end: 17 },
 | 
				
			||||||
 | 
					      [TimeSlot.EightToFour]: { start: 8, end: 16 },
 | 
				
			||||||
 | 
					      [TimeSlot.SevenToFour]: { start: 7, end: 16 },
 | 
				
			||||||
 | 
					      [TimeSlot.SixToThree]: { start: 6, end: 15 },
 | 
				
			||||||
 | 
					      [TimeSlot.TwelveToNine]: { start: 12, end: 21 },
 | 
				
			||||||
 | 
					      [TimeSlot.TenToSix]: { start: 10, end: 18 },
 | 
				
			||||||
 | 
					      [TimeSlot.ElevenToEight]: { start: 11, end: 20 },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { start, end } = timeRanges[value];
 | 
				
			||||||
 | 
					    const formatTime = (hour: number): string => {
 | 
				
			||||||
 | 
					      const period = hour >= 12 ? 'PM' : 'AM';
 | 
				
			||||||
 | 
					      const formattedHour = hour % 12 || 12;
 | 
				
			||||||
 | 
					      return `${formattedHour}:00 ${period}`;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return `${formatTime(start)} - ${formatTime(end)}`;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  timeSlotOptions = Object.keys(TimeSlot)
 | 
				
			||||||
 | 
					    .filter(key => isNaN(Number(key)))
 | 
				
			||||||
 | 
					    .map(key => ({
 | 
				
			||||||
 | 
					      label: this.getTimeRangeLabel(TimeSlot[key as keyof typeof TimeSlot]),
 | 
				
			||||||
 | 
					      value: TimeSlot[key as keyof typeof TimeSlot],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onDoctorSelect(doctorId: string) {
 | 
				
			||||||
 | 
					    const selectedDoctor = this.doctors.find(doctor => doctor.value === doctorId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (selectedDoctor) {
 | 
				
			||||||
 | 
					      this.selectedDoctorName = selectedDoctor.label;
 | 
				
			||||||
 | 
					      this.selectedDoctorEmail = selectedDoctor.email;
 | 
				
			||||||
 | 
					      this.selectedDoctorPhone = selectedDoctor.phoneNo;
 | 
				
			||||||
 | 
					      this.selectedDoctorSpecialty = selectedDoctor.specialist;
 | 
				
			||||||
 | 
					      this.shiftService.getShiftsByDoctorId(doctorId).subscribe(data => {
 | 
				
			||||||
 | 
					        if (data && data.shifts && Object.keys(data.shifts).length > 0) {
 | 
				
			||||||
 | 
					          this.selectedTimeSlots = {};
 | 
				
			||||||
 | 
					          this.selectedDays = Object.keys(data.shifts).map(key => {
 | 
				
			||||||
 | 
					            return this.daysOfWeek[WorkSchedule[key as keyof typeof WorkSchedule] - 1];
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          for (const [day, timeSlot] of Object.entries(data.shifts)) {
 | 
				
			||||||
 | 
					            const dayEnumKey = WorkSchedule[day as keyof typeof WorkSchedule];
 | 
				
			||||||
 | 
					            if (dayEnumKey !== undefined) {
 | 
				
			||||||
 | 
					              this.selectedTimeSlots[this.daysOfWeek[dayEnumKey - 1]] = timeSlot;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          this.selectedDays = this.getDaysFromSchedule(selectedDoctor.availability);
 | 
				
			||||||
 | 
					          this.selectedDays.forEach(day => {
 | 
				
			||||||
 | 
					            this.selectedTimeSlots[day] = TimeSlot.NineToFive;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  daysOfWeek = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getDaysFromSchedule(scheduleValue: WorkSchedule): string[] {
 | 
				
			||||||
 | 
					    let days: string[] = [];
 | 
				
			||||||
 | 
					    if (scheduleValue >= 1 && scheduleValue <= 7) {
 | 
				
			||||||
 | 
					      days.push(this.daysOfWeek[scheduleValue - 1]);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const startDayIndex = (scheduleValue - 8) % 7;
 | 
				
			||||||
 | 
					      const endDayIndex = (startDayIndex + 4) % 7;
 | 
				
			||||||
 | 
					      for (let i = 0; i < 5; i++) {
 | 
				
			||||||
 | 
					        days.push(this.daysOfWeek[(startDayIndex + i) % 7]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return days;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  saveShiftData() {
 | 
				
			||||||
 | 
					    if (!this.selectedDoctor) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.selectedDays;
 | 
				
			||||||
 | 
					    const shiftData: CreateUpdateShiftManagementDto = {
 | 
				
			||||||
 | 
					      doctorId: this.selectedDoctor,
 | 
				
			||||||
 | 
					      shifts: Object.keys(this.selectedTimeSlots).reduce((acc, day) => {
 | 
				
			||||||
 | 
					        const timeSlot = this.selectedTimeSlots[day]; // Get selected time slot
 | 
				
			||||||
 | 
					        const dayEnumKey = WorkSchedule[day as keyof typeof WorkSchedule]; // Convert string to WorkSchedule enum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (timeSlot !== undefined && dayEnumKey !== undefined) {
 | 
				
			||||||
 | 
					          acc[dayEnumKey] = timeSlot; // Store correctly in shifts
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return acc;
 | 
				
			||||||
 | 
					      }, {} as Record<WorkSchedule, TimeSlot>),
 | 
				
			||||||
 | 
					      isActive: true,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.shiftService.createOrUpdateShift(shiftData).subscribe({
 | 
				
			||||||
 | 
					      next: response => {
 | 
				
			||||||
 | 
					        this.toaster.success('Updated Successfully', 'Success');
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      error: err => {
 | 
				
			||||||
 | 
					        this.toaster.error(err, 'Error');
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  backToDoctor() {
 | 
				
			||||||
 | 
					    this.router.navigate(['/doctors']);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { IdentityModule } from '@abp/ng.identity';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { CustomRolesComponent } from './custom-roles/custom-roles.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  declarations: [],
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    IdentityModule,
 | 
				
			||||||
 | 
					    TableModule, 
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    CustomRolesComponent
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  exports:[
 | 
				
			||||||
 | 
					    CustomRolesComponent
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CustomIdentityModule { }
 | 
				
			||||||
@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					<abp-page [title]="'AbpIdentity::Roles' | abpLocalization" [toolbar]="data.items">
 | 
				
			||||||
 | 
					  <div id="identity-roles-wrapper" class="card">
 | 
				
			||||||
 | 
					    <div class="card-body">
 | 
				
			||||||
 | 
					      <!-- <abp-extensible-table
 | 
				
			||||||
 | 
					          [data]="data.items"
 | 
				
			||||||
 | 
					          [recordsTotal]="data.totalCount"
 | 
				
			||||||
 | 
					          [list]="list"
 | 
				
			||||||
 | 
					        ></abp-extensible-table> -->
 | 
				
			||||||
 | 
					      <div class="flex justify-content-between align-items-center mb-3">
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          pButton
 | 
				
			||||||
 | 
					          icon="pi pi-plus"
 | 
				
			||||||
 | 
					          label="{{ '::addRoles' | abpLocalization }}"
 | 
				
			||||||
 | 
					          class="p-button-success"
 | 
				
			||||||
 | 
					          (click)="add()"
 | 
				
			||||||
 | 
					        ></button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <p-table [value]="data.items" [paginator]="true" [rows]="5" responsiveLayout="scroll">
 | 
				
			||||||
 | 
					        <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					          <tr>
 | 
				
			||||||
 | 
					            <th pSortableColumn="name">
 | 
				
			||||||
 | 
					              {{ 'AbpIdentity::RoleName' | abpLocalization }}
 | 
				
			||||||
 | 
					              <p-sortIcon field="name"></p-sortIcon>
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ng-template pTemplate="body" let-role>
 | 
				
			||||||
 | 
					          <tr>
 | 
				
			||||||
 | 
					            <td>{{ role.name }}</td>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <td>
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                icon="pi pi-pencil"
 | 
				
			||||||
 | 
					                class="p-button-text p-button-primary"
 | 
				
			||||||
 | 
					                (click)="edit(role.id)"
 | 
				
			||||||
 | 
					                title="{{ 'AbpIdentity::Edit' | abpLocalization }}"
 | 
				
			||||||
 | 
					              ></button>
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                icon="pi pi-trash"
 | 
				
			||||||
 | 
					                class="p-button-text p-button-danger"
 | 
				
			||||||
 | 
					                (click)="delete(role.id, role.name)"
 | 
				
			||||||
 | 
					                title="{{ 'AbpIdentity::Delete' | abpLocalization }}"
 | 
				
			||||||
 | 
					              ></button>
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                icon="pi pi-lock"
 | 
				
			||||||
 | 
					                class="p-button-text p-button-success"
 | 
				
			||||||
 | 
					                (click)="openPermissionsModal(role.name)"
 | 
				
			||||||
 | 
					                title="{{ 'AbpIdentity::Permissions' | abpLocalization }}"
 | 
				
			||||||
 | 
					              ></button>
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </ng-template>
 | 
				
			||||||
 | 
					      </p-table>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <abp-modal [(visible)]="isModalVisible" [busy]="modalBusy">
 | 
				
			||||||
 | 
					    <ng-template #abpHeader>
 | 
				
			||||||
 | 
					      <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}</h3>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- <ng-template #abpBody>
 | 
				
			||||||
 | 
					        <form [formGroup]="form" (ngSubmit)="save()" validateOnSubmit>
 | 
				
			||||||
 | 
					          <abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					      </ng-template> -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template #abpBody>
 | 
				
			||||||
 | 
					      <form #roleForm="ngForm" (ngSubmit)="save()" validateOnSubmit>
 | 
				
			||||||
 | 
					        <!-- Name Field -->
 | 
				
			||||||
 | 
					        <div class="form-group">
 | 
				
			||||||
 | 
					          <label for="name">{{ 'AbpIdentity::Name' | abpLocalization }}</label>
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            id="name"
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            class="form-control"
 | 
				
			||||||
 | 
					            [(ngModel)]="selected.name"
 | 
				
			||||||
 | 
					            name="name"
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					            #nameCtrl="ngModel"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <small class="text-danger" *ngIf="nameCtrl.invalid && nameCtrl.touched">
 | 
				
			||||||
 | 
					            {{ 'AbpIdentity::NameIsRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					          </small>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Is Default Checkbox -->
 | 
				
			||||||
 | 
					        <div class="form-check">
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            id="isDefault"
 | 
				
			||||||
 | 
					            type="checkbox"
 | 
				
			||||||
 | 
					            class="form-check-input"
 | 
				
			||||||
 | 
					            [(ngModel)]="selected.isDefault"
 | 
				
			||||||
 | 
					            name="isDefault"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <label for="isDefault" class="form-check-label">
 | 
				
			||||||
 | 
					            {{ 'AbpIdentity::Default' | abpLocalization }}
 | 
				
			||||||
 | 
					          </label>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Is Public Checkbox -->
 | 
				
			||||||
 | 
					        <div class="form-check">
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            id="isPublic"
 | 
				
			||||||
 | 
					            type="checkbox"
 | 
				
			||||||
 | 
					            class="form-check-input"
 | 
				
			||||||
 | 
					            [(ngModel)]="selected.isPublic"
 | 
				
			||||||
 | 
					            name="isPublic"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <label for="isPublic" class="form-check-label">
 | 
				
			||||||
 | 
					            {{ 'AbpIdentity::Public' | abpLocalization }}
 | 
				
			||||||
 | 
					          </label>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <br />
 | 
				
			||||||
 | 
					        <abp-button iconClass="fa fa-check" [disabled]="roleForm.invalid" (click)="save()">{{
 | 
				
			||||||
 | 
					          'AbpIdentity::Save' | abpLocalization
 | 
				
			||||||
 | 
					        }}</abp-button>
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template #abpFooter>
 | 
				
			||||||
 | 
					      <button type="button" class="btn btn-outline-primary" abpClose>
 | 
				
			||||||
 | 
					        {{ 'AbpIdentity::Cancel' | abpLocalization }}
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					      <!-- <abp-button iconClass="fa fa-check" [disabled]="roleForm?.invalid" (click)="save()">{{
 | 
				
			||||||
 | 
					          'AbpIdentity::Save' | abpLocalization
 | 
				
			||||||
 | 
					          }}</abp-button> -->
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					  </abp-modal>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <abp-permission-management
 | 
				
			||||||
 | 
					    #abpPermissionManagement="abpPermissionManagement"
 | 
				
			||||||
 | 
					    *abpReplaceableTemplate="
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        inputs: {
 | 
				
			||||||
 | 
					          providerName: { value: 'R' },
 | 
				
			||||||
 | 
					          providerKey: { value: providerKey },
 | 
				
			||||||
 | 
					          visible: { value: visiblePermissions, twoWay: true },
 | 
				
			||||||
 | 
					          hideBadges: { value: true }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        outputs: { visibleChange: onVisiblePermissionChange },
 | 
				
			||||||
 | 
					        componentKey: permissionManagementKey
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      let init = initTemplate
 | 
				
			||||||
 | 
					    "
 | 
				
			||||||
 | 
					    (abpInit)="init(abpPermissionManagement)"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					  </abp-permission-management>
 | 
				
			||||||
 | 
					</abp-page>
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { CustomRolesComponent } from './custom-roles.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('CustomRolesComponent', () => {
 | 
				
			||||||
 | 
					  let component: CustomRolesComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<CustomRolesComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [CustomRolesComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(CustomRolesComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,215 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ExtensibleModule,
 | 
				
			||||||
 | 
					  EXTENSIONS_IDENTIFIER,
 | 
				
			||||||
 | 
					  FormPropData,
 | 
				
			||||||
 | 
					  generateFormFromProps,
 | 
				
			||||||
 | 
					} from '@abp/ng.components/extensible';
 | 
				
			||||||
 | 
					import { PageModule } from '@abp/ng.components/page';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  CoreModule,
 | 
				
			||||||
 | 
					  ListResultDto,
 | 
				
			||||||
 | 
					  ListService,
 | 
				
			||||||
 | 
					  LocalizationModule,
 | 
				
			||||||
 | 
					  PagedAndSortedResultRequestDto,
 | 
				
			||||||
 | 
					  PagedResultDto,
 | 
				
			||||||
 | 
					} from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { IdentityRoleCreateDto, IdentityRoleDto, IdentityRoleService, IdentityRoleUpdateDto } from '@abp/ng.identity/proxy';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ThemeSharedModule,
 | 
				
			||||||
 | 
					  ConfirmationService,
 | 
				
			||||||
 | 
					  ToasterService,
 | 
				
			||||||
 | 
					  Confirmation,
 | 
				
			||||||
 | 
					} from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { Component, inject, Injector, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import { FormControl, FormGroup, FormsModule, UntypedFormGroup, Validators } from '@angular/forms';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { finalize } from 'rxjs';
 | 
				
			||||||
 | 
					import { ePermissionManagementComponents } from '@abp/ng.permission-management';
 | 
				
			||||||
 | 
					import { NgxDatatableModule } from '@swimlane/ngx-datatable';
 | 
				
			||||||
 | 
					import { eIdentityComponents } from '@abp/ng.identity';
 | 
				
			||||||
 | 
					import { PermissionManagementModule } from '@abp/ng.permission-management';
 | 
				
			||||||
 | 
					import {  NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
 | 
				
			||||||
 | 
					import { MenuItem } from 'primeng/api';
 | 
				
			||||||
 | 
					import { Dropdown, DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { SharedModule } from 'src/app/shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-custom-roles',
 | 
				
			||||||
 | 
					  standalone: true,
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    PageModule,
 | 
				
			||||||
 | 
					    LocalizationModule,
 | 
				
			||||||
 | 
					    ThemeSharedModule,
 | 
				
			||||||
 | 
					    NgxDatatableModule,
 | 
				
			||||||
 | 
					    ExtensibleModule,
 | 
				
			||||||
 | 
					    PermissionManagementModule,
 | 
				
			||||||
 | 
					    CoreModule,
 | 
				
			||||||
 | 
					    NgbNavModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    SharedModule
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  templateUrl: './custom-roles.component.html',
 | 
				
			||||||
 | 
					  providers: [
 | 
				
			||||||
 | 
					    ListService,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      provide: EXTENSIONS_IDENTIFIER,
 | 
				
			||||||
 | 
					      useValue: eIdentityComponents.Roles,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  styleUrl: './custom-roles.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CustomRolesComponent implements OnInit {
 | 
				
			||||||
 | 
					  protected readonly list = inject(ListService<PagedAndSortedResultRequestDto>);
 | 
				
			||||||
 | 
					  protected readonly confirmationService = inject(ConfirmationService);
 | 
				
			||||||
 | 
					  protected readonly toasterService = inject(ToasterService);
 | 
				
			||||||
 | 
					  private readonly injector = inject(Injector);
 | 
				
			||||||
 | 
					  protected readonly service = inject(IdentityRoleService);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data: PagedResultDto<IdentityRoleDto> = { items: [], totalCount: 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  form!: UntypedFormGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  selected?: IdentityRoleDto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  isModalVisible!: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  visiblePermissions = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  providerKey?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  modalBusy = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onVisiblePermissionChange = (event: boolean) => {
 | 
				
			||||||
 | 
					    this.visiblePermissions = event;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					    this.hookToQuery();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // buildForm() {
 | 
				
			||||||
 | 
					  //   const data = new FormPropData(this.injector, this.selected);
 | 
				
			||||||
 | 
					  //   this.form = generateFormFromProps(data);
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					  buildForm() {
 | 
				
			||||||
 | 
					    this.form = new FormGroup({
 | 
				
			||||||
 | 
					      name: new FormControl(this.selected?.name || '', Validators.required),
 | 
				
			||||||
 | 
					      isDefault: new FormControl(this.selected?.isDefault || false),
 | 
				
			||||||
 | 
					      isPublic: new FormControl(this.selected?.isPublic || false)
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					  openModal() {
 | 
				
			||||||
 | 
					    this.buildForm();
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  add() {
 | 
				
			||||||
 | 
					    debugger
 | 
				
			||||||
 | 
					    // this.selected = {} as IdentityRoleDto;
 | 
				
			||||||
 | 
					    // this.openModal();
 | 
				
			||||||
 | 
					    this.selected = { name: '', isDefault: false, isPublic: false } as IdentityRoleDto;
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  edit(id: string) {
 | 
				
			||||||
 | 
					    debugger
 | 
				
			||||||
 | 
					    // this.service.get(id).subscribe(res => {
 | 
				
			||||||
 | 
					    //   this.selected = res;
 | 
				
			||||||
 | 
					    //   this.openModal();
 | 
				
			||||||
 | 
					    // });
 | 
				
			||||||
 | 
					    this.service.get(id).subscribe(res => {
 | 
				
			||||||
 | 
					      this.selected = res;
 | 
				
			||||||
 | 
					      this.isModalVisible = true;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // save() {
 | 
				
			||||||
 | 
					  //   debugger
 | 
				
			||||||
 | 
					  //   if (!this.form.valid) return;
 | 
				
			||||||
 | 
					  //   this.modalBusy = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //   const { id } = this.selected || {};
 | 
				
			||||||
 | 
					  //   (id
 | 
				
			||||||
 | 
					  //     ? this.service.update(id, { ...this.selected, ...this.form.value })
 | 
				
			||||||
 | 
					  //     : this.service.create(this.form.value)
 | 
				
			||||||
 | 
					  //   )
 | 
				
			||||||
 | 
					  //     .pipe(finalize(() => (this.modalBusy = false)))
 | 
				
			||||||
 | 
					  //     .subscribe(() => {
 | 
				
			||||||
 | 
					  //       this.isModalVisible = false;
 | 
				
			||||||
 | 
					  //       this.toasterService.success('AbpUi::SavedSuccessfully');
 | 
				
			||||||
 | 
					  //       this.list.get();
 | 
				
			||||||
 | 
					  //     });
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					  save() {
 | 
				
			||||||
 | 
					    debugger
 | 
				
			||||||
 | 
					    if (!this.selected?.name) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    this.modalBusy = true;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    const { id, name, isDefault, isPublic, concurrencyStamp } = this.selected;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    const roleDto = {
 | 
				
			||||||
 | 
					      name,
 | 
				
			||||||
 | 
					      isDefault,
 | 
				
			||||||
 | 
					      isPublic,
 | 
				
			||||||
 | 
					      concurrencyStamp
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    const saveObservable = id
 | 
				
			||||||
 | 
					      ? this.service.update(id, roleDto)  // Update call
 | 
				
			||||||
 | 
					      : this.service.create(roleDto);    // Create call
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    saveObservable
 | 
				
			||||||
 | 
					      .pipe(finalize(() => (this.modalBusy = false)))  
 | 
				
			||||||
 | 
					      .subscribe(() => {
 | 
				
			||||||
 | 
					        this.isModalVisible = false;
 | 
				
			||||||
 | 
					        this.toasterService.success('AbpUi::SavedSuccessfully');
 | 
				
			||||||
 | 
					        this.list.get();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  delete(id: string, name: string) {
 | 
				
			||||||
 | 
					    this.confirmationService
 | 
				
			||||||
 | 
					      .warn('AbpIdentity::RoleDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', {
 | 
				
			||||||
 | 
					        messageLocalizationParams: [name],
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .subscribe((status: Confirmation.Status) => {
 | 
				
			||||||
 | 
					        if (status === Confirmation.Status.confirm) {
 | 
				
			||||||
 | 
					          this.toasterService.success('AbpUi::DeletedSuccessfully');
 | 
				
			||||||
 | 
					          this.service.delete(id).subscribe(() => this.list.get());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private hookToQuery() {
 | 
				
			||||||
 | 
					    this.list.hookToQuery(query => this.service.getList(query)).subscribe(res => (this.data = res));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  openPermissionsModal(providerKey: string) {
 | 
				
			||||||
 | 
					    this.providerKey = providerKey;
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      this.visiblePermissions = true;
 | 
				
			||||||
 | 
					    }, 0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  sort(data: any) {
 | 
				
			||||||
 | 
					    const { prop, dir } = data.sorts[0];
 | 
				
			||||||
 | 
					    this.list.sortKey = prop;
 | 
				
			||||||
 | 
					    this.list.sortOrder = dir;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,355 @@
 | 
				
			|||||||
 | 
					<!-- <div>
 | 
				
			||||||
 | 
					  <h3>Total Users: {{ data.totalCount }}</h3>
 | 
				
			||||||
 | 
					  <ul>
 | 
				
			||||||
 | 
					    <li *ngFor="let user of data.items">
 | 
				
			||||||
 | 
					      <strong>{{ user.userName }}</strong> ({{ user.email }})
 | 
				
			||||||
 | 
					    </li>
 | 
				
			||||||
 | 
					  </ul>
 | 
				
			||||||
 | 
					</div> -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<abp-page [title]="'AbpIdentity::Users' | abpLocalization" [toolbar]="data.items">
 | 
				
			||||||
 | 
					  <div id="identity-roles-wrapper" class="card">
 | 
				
			||||||
 | 
					    <div class="card-body">
 | 
				
			||||||
 | 
					      <div id="data-tables-table-filter" class="data-tables-filter mb-3">
 | 
				
			||||||
 | 
					        <div class="flex justify-content-between align-items-center mb-3">
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            pButton
 | 
				
			||||||
 | 
					            icon="pi pi-plus"
 | 
				
			||||||
 | 
					            label="{{ '::addUser' | abpLocalization }}"
 | 
				
			||||||
 | 
					            class="p-button-success"
 | 
				
			||||||
 | 
					            (click)="add()"
 | 
				
			||||||
 | 
					          ></button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="input-group">
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            type="search"
 | 
				
			||||||
 | 
					            class="form-control"
 | 
				
			||||||
 | 
					            [placeholder]="'AbpUi::PagerSearch' | abpLocalization"
 | 
				
			||||||
 | 
					            [(ngModel)]="list.filter"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <!--   
 | 
				
			||||||
 | 
					        <abp-extensible-table
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					          [data]="data.items"
 | 
				
			||||||
 | 
					          [recordsTotal]="data.totalCount"
 | 
				
			||||||
 | 
					          [list]="list"
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					        ></abp-extensible-table> -->
 | 
				
			||||||
 | 
					      <p-table
 | 
				
			||||||
 | 
					        [value]="data.items"
 | 
				
			||||||
 | 
					        [tableStyle]="{ 'min-width': '60rem' }"
 | 
				
			||||||
 | 
					        [paginator]="true"
 | 
				
			||||||
 | 
					        [rows]="5"
 | 
				
			||||||
 | 
					        responsiveLayout="scroll"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					          <tr>
 | 
				
			||||||
 | 
					            <th pSortableColumn="userName">
 | 
				
			||||||
 | 
					              {{ '::username' | abpLocalization }}
 | 
				
			||||||
 | 
					              <p-sortIcon field="userName"></p-sortIcon>
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th pSortableColumn="name">
 | 
				
			||||||
 | 
					              {{ '::firstName' | abpLocalization }}
 | 
				
			||||||
 | 
					              <p-sortIcon field="name"></p-sortIcon>
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th pSortableColumn="surname">
 | 
				
			||||||
 | 
					              {{ '::lastName' | abpLocalization }}
 | 
				
			||||||
 | 
					              <p-sortIcon field="surname"></p-sortIcon>
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th pSortableColumn="email">
 | 
				
			||||||
 | 
					              {{ '::email' | abpLocalization }}
 | 
				
			||||||
 | 
					              <p-sortIcon field="email"></p-sortIcon>
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th pSortableColumn="phoneNumber">
 | 
				
			||||||
 | 
					              {{ '::phoneNumber' | abpLocalization }}
 | 
				
			||||||
 | 
					              <p-sortIcon field="phoneNumber"></p-sortIcon>
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th>{{ '::status' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					            <th>{{ '::actions' | abpLocalization }}</th>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ng-template pTemplate="body" let-user>
 | 
				
			||||||
 | 
					          <tr>
 | 
				
			||||||
 | 
					            <td>{{ user.userName }}</td>
 | 
				
			||||||
 | 
					            <td>{{ user.name }}</td>
 | 
				
			||||||
 | 
					            <td>{{ user.surname }}</td>
 | 
				
			||||||
 | 
					            <td>{{ user.email }}</td>
 | 
				
			||||||
 | 
					            <td>{{ user.phoneNumber }}</td>
 | 
				
			||||||
 | 
					            <td>
 | 
				
			||||||
 | 
					              <p-tag
 | 
				
			||||||
 | 
					                [value]="user.isActive ? 'Active' : 'Inactive'"
 | 
				
			||||||
 | 
					                [severity]="user.isActive ? 'success' : 'danger'"
 | 
				
			||||||
 | 
					              ></p-tag>
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					            <td>
 | 
				
			||||||
 | 
					              <div class="btn-group" dropdown placement="bottom left" container="body">
 | 
				
			||||||
 | 
					                <p-splitButton
 | 
				
			||||||
 | 
					                  label="{{ '::actions' | abpLocalization }}"
 | 
				
			||||||
 | 
					                  icon="pi pi-cog"
 | 
				
			||||||
 | 
					                  class="p-button-sm p-button-primary"
 | 
				
			||||||
 | 
					                  [model]="actionItems"
 | 
				
			||||||
 | 
					                  (onClick)="editUser(user.id)"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                </p-splitButton>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <!-- <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                icon="pi pi-pencil"
 | 
				
			||||||
 | 
					                class="p-button-text p-button-primary"
 | 
				
			||||||
 | 
					                (click)="edit(user.id)"
 | 
				
			||||||
 | 
					              ></button>
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                icon="pi pi-trash"
 | 
				
			||||||
 | 
					                class="p-button-text p-button-danger"
 | 
				
			||||||
 | 
					                (click)="delete(user.id, user.userName)"
 | 
				
			||||||
 | 
					              ></button>
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                pButton
 | 
				
			||||||
 | 
					                icon="pi pi-lock"
 | 
				
			||||||
 | 
					                class="p-button-text p-button-success"
 | 
				
			||||||
 | 
					                (click)="openPermissionsModal(user.id, user.userName)"
 | 
				
			||||||
 | 
					              ></button> -->
 | 
				
			||||||
 | 
					              <!-- <div class="btn-group" dropdown placement="bottom left" container="body">
 | 
				
			||||||
 | 
					                <button
 | 
				
			||||||
 | 
					                  id="dropdownButton"
 | 
				
			||||||
 | 
					                  type="button"
 | 
				
			||||||
 | 
					                  class="btn btn-primary btn-sm dropdown-toggle"
 | 
				
			||||||
 | 
					                  dropdownToggle
 | 
				
			||||||
 | 
					                  aria-controls="dropdownMenu"
 | 
				
			||||||
 | 
					                  (click)="toggleDropdown()"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <i class="fa fa-cog"></i>
 | 
				
			||||||
 | 
					                  <span class="caret"></span>
 | 
				
			||||||
 | 
					                  Actions
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					                <ul
 | 
				
			||||||
 | 
					                  id="dropdownMenu"
 | 
				
			||||||
 | 
					                  #dropdownMenu
 | 
				
			||||||
 | 
					                  class="dropdown-menu"
 | 
				
			||||||
 | 
					                  role="menu"
 | 
				
			||||||
 | 
					                  aria-labelledby="dropdownButton"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <li role="menuitem" tabindex="0">
 | 
				
			||||||
 | 
					                    <a
 | 
				
			||||||
 | 
					                      #firstDropdownItem
 | 
				
			||||||
 | 
					                      class="dropdown-item"
 | 
				
			||||||
 | 
					                      href="javascript:;"
 | 
				
			||||||
 | 
					                      (click)="edit(user.id)"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      Edit
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                  </li>
 | 
				
			||||||
 | 
					                 
 | 
				
			||||||
 | 
					                </ul>
 | 
				
			||||||
 | 
					              </div> -->
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </ng-template>
 | 
				
			||||||
 | 
					      </p-table>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <abp-modal [(visible)]="isModalVisible" [busy]="modalBusy">
 | 
				
			||||||
 | 
					    <ng-template #abpHeader>
 | 
				
			||||||
 | 
					      <h3>
 | 
				
			||||||
 | 
					        {{ (selected?.id ? 'AbpIdentity::EditUser' : 'AbpIdentity::NewUser') | abpLocalization }}
 | 
				
			||||||
 | 
					      </h3>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template #abpBody>
 | 
				
			||||||
 | 
					      <form #userForm="ngForm" (ngSubmit)="save(userForm)">
 | 
				
			||||||
 | 
					        <!-- User Information Tab -->
 | 
				
			||||||
 | 
					        <ul ngbNav #nav="ngbNav" class="nav-tabs">
 | 
				
			||||||
 | 
					          <li ngbNavItem>
 | 
				
			||||||
 | 
					            <a ngbNavLink>{{ 'AbpIdentity::UserInformations' | abpLocalization }}</a>
 | 
				
			||||||
 | 
					            <ng-template ngbNavContent>
 | 
				
			||||||
 | 
					              <div class="form-group">
 | 
				
			||||||
 | 
					                <label for="userName">
 | 
				
			||||||
 | 
					                  {{ '::userName' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="userName"
 | 
				
			||||||
 | 
					                  type="text"
 | 
				
			||||||
 | 
					                  class="form-control"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.userName"
 | 
				
			||||||
 | 
					                  name="userName"
 | 
				
			||||||
 | 
					                  required
 | 
				
			||||||
 | 
					                  #userName="ngModel"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <div *ngIf="userName.invalid && userName.touched" class="text-danger">
 | 
				
			||||||
 | 
					                  {{ '::userNameIsRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <div class="form-group" *ngIf="!selected.id">
 | 
				
			||||||
 | 
					                <label for="password">
 | 
				
			||||||
 | 
					                  {{ '::password' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="password"
 | 
				
			||||||
 | 
					                  type="password"
 | 
				
			||||||
 | 
					                  class="form-control"
 | 
				
			||||||
 | 
					                  [(ngModel)]="password"
 | 
				
			||||||
 | 
					                  name="password"
 | 
				
			||||||
 | 
					                  required
 | 
				
			||||||
 | 
					                  #passwordField="ngModel"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <div *ngIf="passwordField.invalid && passwordField.touched" class="text-danger">
 | 
				
			||||||
 | 
					                  {{ '::passwordIsRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <div class="form-group">
 | 
				
			||||||
 | 
					                <label for="name">
 | 
				
			||||||
 | 
					                  {{ '::firstName' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="name"
 | 
				
			||||||
 | 
					                  type="text"
 | 
				
			||||||
 | 
					                  class="form-control"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.name"
 | 
				
			||||||
 | 
					                  name="name"
 | 
				
			||||||
 | 
					                  #name="ngModel"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <div class="form-group">
 | 
				
			||||||
 | 
					                <label for="surname">
 | 
				
			||||||
 | 
					                  {{ '::lastName' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="surname"
 | 
				
			||||||
 | 
					                  type="text"
 | 
				
			||||||
 | 
					                  class="form-control"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.surname"
 | 
				
			||||||
 | 
					                  name="surname"
 | 
				
			||||||
 | 
					                  #surname="ngModel"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <!-- Email -->
 | 
				
			||||||
 | 
					              <div class="form-group">
 | 
				
			||||||
 | 
					                <label for="email">
 | 
				
			||||||
 | 
					                  {{ '::email' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="email"
 | 
				
			||||||
 | 
					                  type="email"
 | 
				
			||||||
 | 
					                  class="form-control"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.email"
 | 
				
			||||||
 | 
					                  name="email"
 | 
				
			||||||
 | 
					                  required
 | 
				
			||||||
 | 
					                  #email="ngModel"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <div *ngIf="email.invalid && email.touched" class="text-danger">
 | 
				
			||||||
 | 
					                  {{ '::validEmailIsRequired' | abpLocalization }}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <div class="form-group">
 | 
				
			||||||
 | 
					                <label for="phoneNumber">
 | 
				
			||||||
 | 
					                  {{ '::phoneNumber' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="phoneNumber"
 | 
				
			||||||
 | 
					                  type="text"
 | 
				
			||||||
 | 
					                  class="form-control"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.phoneNumber"
 | 
				
			||||||
 | 
					                  name="phoneNumber"
 | 
				
			||||||
 | 
					                  #phoneNumber="ngModel"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <div class="form-check">
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="isActive"
 | 
				
			||||||
 | 
					                  type="checkbox"
 | 
				
			||||||
 | 
					                  class="form-check-input"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.isActive"
 | 
				
			||||||
 | 
					                  name="isActive"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <label for="isActive" class="form-check-label">
 | 
				
			||||||
 | 
					                  {{ '::active' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <div class="form-check">
 | 
				
			||||||
 | 
					                <input
 | 
				
			||||||
 | 
					                  id="lockoutEnabled"
 | 
				
			||||||
 | 
					                  type="checkbox"
 | 
				
			||||||
 | 
					                  class="form-check-input"
 | 
				
			||||||
 | 
					                  [(ngModel)]="selected.lockoutEnabled"
 | 
				
			||||||
 | 
					                  name="lockoutEnabled"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <label for="lockoutEnabled" class="form-check-label">
 | 
				
			||||||
 | 
					                  {{ '::lockoutEnabled' | abpLocalization }}
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </ng-template>
 | 
				
			||||||
 | 
					          </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <li ngbNavItem>
 | 
				
			||||||
 | 
					            <a ngbNavLink>{{ 'AbpIdentity::Roles' | abpLocalization }}</a>
 | 
				
			||||||
 | 
					            <ng-template ngbNavContent>
 | 
				
			||||||
 | 
					              <div *ngFor="let role of roles; let i = index">
 | 
				
			||||||
 | 
					                <div class="form-check mb-2">
 | 
				
			||||||
 | 
					                  <label class="form-check-label">
 | 
				
			||||||
 | 
					                    <input
 | 
				
			||||||
 | 
					                      type="checkbox"
 | 
				
			||||||
 | 
					                      class="form-check-input"
 | 
				
			||||||
 | 
					                      [(ngModel)]="role.selected"
 | 
				
			||||||
 | 
					                      name="role-{{ i }}"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    {{ role.name }}
 | 
				
			||||||
 | 
					                  </label>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </ng-template>
 | 
				
			||||||
 | 
					          </li>
 | 
				
			||||||
 | 
					        </ul>
 | 
				
			||||||
 | 
					        <div class="mt-2 fade-in-top" [ngbNavOutlet]="nav"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="mt-3">
 | 
				
			||||||
 | 
					          <button type="submit" class="btn btn-primary" [disabled]="userForm.invalid">
 | 
				
			||||||
 | 
					            {{ '::save' | abpLocalization }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template #abpFooter>
 | 
				
			||||||
 | 
					      <button type="button" class="btn btn-outline-primary" abpClose>
 | 
				
			||||||
 | 
					        {{ '::cancel' | abpLocalization }}
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					      <!-- <abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{{
 | 
				
			||||||
 | 
					          'AbpIdentity::Save' | abpLocalization
 | 
				
			||||||
 | 
					        }}</abp-button> -->
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					  </abp-modal>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <abp-permission-management
 | 
				
			||||||
 | 
					    #abpPermissionManagement="abpPermissionManagement"
 | 
				
			||||||
 | 
					    *abpReplaceableTemplate="
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        inputs: {
 | 
				
			||||||
 | 
					          providerName: { value: 'U' },
 | 
				
			||||||
 | 
					          providerKey: { value: providerKey },
 | 
				
			||||||
 | 
					          visible: { value: visiblePermissions, twoWay: true }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        outputs: { visibleChange: onVisiblePermissionChange },
 | 
				
			||||||
 | 
					        componentKey: permissionManagementKey
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      let init = initTemplate
 | 
				
			||||||
 | 
					    "
 | 
				
			||||||
 | 
					    [entityDisplayName]="entityDisplayName"
 | 
				
			||||||
 | 
					    (abpInit)="init(abpPermissionManagement)"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					  </abp-permission-management>
 | 
				
			||||||
 | 
					</abp-page>
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { CustomUsersComponent } from './custom-users.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('CustomUsersComponent', () => {
 | 
				
			||||||
 | 
					  let component: CustomUsersComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<CustomUsersComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      imports: [CustomUsersComponent]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(CustomUsersComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -0,0 +1,396 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  FormPropData,
 | 
				
			||||||
 | 
					  EXTENSIONS_IDENTIFIER,
 | 
				
			||||||
 | 
					  generateFormFromProps,
 | 
				
			||||||
 | 
					  ExtensibleModule,
 | 
				
			||||||
 | 
					} from '@abp/ng.components/extensible';
 | 
				
			||||||
 | 
					import { PageModule } from '@abp/ng.components/page';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  CoreModule,
 | 
				
			||||||
 | 
					  ListResultDto,
 | 
				
			||||||
 | 
					  ListService,
 | 
				
			||||||
 | 
					  LocalizationModule,
 | 
				
			||||||
 | 
					  PagedResultDto,
 | 
				
			||||||
 | 
					} from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { eIdentityComponents } from '@abp/ng.identity';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  GetIdentityUsersInput,
 | 
				
			||||||
 | 
					  IdentityRoleDto,
 | 
				
			||||||
 | 
					  IdentityUserDto,
 | 
				
			||||||
 | 
					  IdentityUserService,
 | 
				
			||||||
 | 
					  IdentityUserUpdateDto,
 | 
				
			||||||
 | 
					} from '@abp/ng.identity/proxy';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Component,
 | 
				
			||||||
 | 
					  ElementRef,
 | 
				
			||||||
 | 
					  HostListener,
 | 
				
			||||||
 | 
					  inject,
 | 
				
			||||||
 | 
					  Injector,
 | 
				
			||||||
 | 
					  OnInit,
 | 
				
			||||||
 | 
					  TemplateRef,
 | 
				
			||||||
 | 
					  TrackByFunction,
 | 
				
			||||||
 | 
					  ViewChild,
 | 
				
			||||||
 | 
					} from '@angular/core';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  AbstractControl,
 | 
				
			||||||
 | 
					  FormsModule,
 | 
				
			||||||
 | 
					  NgForm,
 | 
				
			||||||
 | 
					  UntypedFormArray,
 | 
				
			||||||
 | 
					  UntypedFormBuilder,
 | 
				
			||||||
 | 
					  UntypedFormGroup,
 | 
				
			||||||
 | 
					} from '@angular/forms';
 | 
				
			||||||
 | 
					import { ButtonModule } from 'primeng/button';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Confirmation,
 | 
				
			||||||
 | 
					  eFormComponets,
 | 
				
			||||||
 | 
					  ThemeSharedModule,
 | 
				
			||||||
 | 
					  ToasterService,
 | 
				
			||||||
 | 
					  ConfirmationService,
 | 
				
			||||||
 | 
					} from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { finalize, switchMap, tap } from 'rxjs';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ePermissionManagementComponents,
 | 
				
			||||||
 | 
					  PermissionManagementModule,
 | 
				
			||||||
 | 
					} from '@abp/ng.permission-management';
 | 
				
			||||||
 | 
					import { NgxDatatableModule } from '@swimlane/ngx-datatable';
 | 
				
			||||||
 | 
					import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
 | 
				
			||||||
 | 
					import { PaginatorModule } from 'primeng/paginator';
 | 
				
			||||||
 | 
					import { TagModule } from 'primeng/tag'; // For active/inactive status
 | 
				
			||||||
 | 
					import { SplitButtonModule } from 'primeng/splitbutton';
 | 
				
			||||||
 | 
					import { SharedModule } from 'src/app/shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-custom-users',
 | 
				
			||||||
 | 
					  standalone: true,
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    ButtonModule,
 | 
				
			||||||
 | 
					    PageModule,
 | 
				
			||||||
 | 
					    LocalizationModule,
 | 
				
			||||||
 | 
					    ThemeSharedModule,
 | 
				
			||||||
 | 
					    NgxDatatableModule,
 | 
				
			||||||
 | 
					    ExtensibleModule,
 | 
				
			||||||
 | 
					    PermissionManagementModule,
 | 
				
			||||||
 | 
					    CoreModule,
 | 
				
			||||||
 | 
					    NgbNavModule,
 | 
				
			||||||
 | 
					    PaginatorModule,
 | 
				
			||||||
 | 
					    TagModule,SplitButtonModule,SharedModule
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  templateUrl: './custom-users.component.html',
 | 
				
			||||||
 | 
					  providers: [
 | 
				
			||||||
 | 
					    ListService,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      provide: EXTENSIONS_IDENTIFIER,
 | 
				
			||||||
 | 
					      useValue: eIdentityComponents.Users,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  styleUrl: './custom-users.component.scss',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CustomUsersComponent implements OnInit {
 | 
				
			||||||
 | 
					  protected readonly list = inject(ListService<GetIdentityUsersInput>);
 | 
				
			||||||
 | 
					  protected readonly confirmationService = inject(ConfirmationService);
 | 
				
			||||||
 | 
					  protected readonly service = inject(IdentityUserService);
 | 
				
			||||||
 | 
					  protected readonly toasterService = inject(ToasterService);
 | 
				
			||||||
 | 
					  private readonly fb = inject(UntypedFormBuilder);
 | 
				
			||||||
 | 
					  private readonly injector = inject(Injector);
 | 
				
			||||||
 | 
					  @ViewChild('firstDropdownItem') firstDropdownItem: ElementRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data: PagedResultDto<IdentityUserDto> = { items: [], totalCount: 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ViewChild('modalContent', { static: false })
 | 
				
			||||||
 | 
					  modalContent!: TemplateRef<any>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  form!: UntypedFormGroup;
 | 
				
			||||||
 | 
					  password:string;
 | 
				
			||||||
 | 
					  selected?: IdentityUserDto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  selectedUserRoles?: IdentityRoleDto[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // roles?: IdentityRoleDto[];
 | 
				
			||||||
 | 
					  roles: (IdentityRoleDto & { selected: boolean })[] = []; // Use intersection type to add 'selected'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  visiblePermissions = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  providerKey?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  isModalVisible?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  modalBusy = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  entityDisplayName: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  inputKey = eFormComponets.FormCheckboxComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
 | 
				
			||||||
 | 
					  isDropdownOpen = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toggleDropdown() {
 | 
				
			||||||
 | 
					    this.isDropdownOpen = !this.isDropdownOpen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // After the dropdown is shown, focus the first item in the dropdown
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      if (this.firstDropdownItem) {
 | 
				
			||||||
 | 
					        this.firstDropdownItem.nativeElement.focus();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, 100); // Delay to ensure dropdown is rendered
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closeDropdown() {
 | 
				
			||||||
 | 
					    this.isDropdownOpen = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  actionItems = [
 | 
				
			||||||
 | 
					    { label: 'Edit', icon: 'pi pi-pencil', command: () => this.edit("") },
 | 
				
			||||||
 | 
					    { label: 'Delete', icon: 'pi pi-trash', command: () => this.delete("","") },
 | 
				
			||||||
 | 
					  //  { label: 'Permissions', icon: 'pi pi-shield', command: () => this.openPermissionsModal("") },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onVisiblePermissionChange = (event: boolean) => {
 | 
				
			||||||
 | 
					    debugger
 | 
				
			||||||
 | 
					    this.visiblePermissions = event;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get roleGroups(): UntypedFormGroup[] {
 | 
				
			||||||
 | 
					    return ((this.form.get('roleNames') as UntypedFormArray)?.controls as UntypedFormGroup[]) || [];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					    this.hookToQuery();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  formValid() {
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // buildForm() {
 | 
				
			||||||
 | 
					  //   debugger
 | 
				
			||||||
 | 
					  //   const data = new FormPropData(this.injector, this.selected);
 | 
				
			||||||
 | 
					  //   this.form = generateFormFromProps(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //   this.service.getAssignableRoles().subscribe(({ items }) => {
 | 
				
			||||||
 | 
					  //     this.roles = items;
 | 
				
			||||||
 | 
					  //     if (this.roles) {
 | 
				
			||||||
 | 
					  //       this.form.addControl(
 | 
				
			||||||
 | 
					  //         'roleNames',
 | 
				
			||||||
 | 
					  //         this.fb.array(
 | 
				
			||||||
 | 
					  //           this.roles.map(role =>
 | 
				
			||||||
 | 
					  //             this.fb.group({
 | 
				
			||||||
 | 
					  //               [role.name as string]: [
 | 
				
			||||||
 | 
					  //                 this.selected?.id
 | 
				
			||||||
 | 
					  //                   ? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id)
 | 
				
			||||||
 | 
					  //                   : role.isDefault,
 | 
				
			||||||
 | 
					  //               ],
 | 
				
			||||||
 | 
					  //             }),
 | 
				
			||||||
 | 
					  //           ),
 | 
				
			||||||
 | 
					  //         ),
 | 
				
			||||||
 | 
					  //       );
 | 
				
			||||||
 | 
					  //     }
 | 
				
			||||||
 | 
					  //   });
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // openModal() {
 | 
				
			||||||
 | 
					  //   this.buildForm();
 | 
				
			||||||
 | 
					  //   this.isModalVisible = true;
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // add() {
 | 
				
			||||||
 | 
					  //   debugger
 | 
				
			||||||
 | 
					  //   this.selected = {} as IdentityUserDto;
 | 
				
			||||||
 | 
					  //   this.selectedUserRoles = [] as IdentityRoleDto[];
 | 
				
			||||||
 | 
					  //   this.openModal();
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // edit(id: string) {
 | 
				
			||||||
 | 
					  //   debugger
 | 
				
			||||||
 | 
					  //   this.service
 | 
				
			||||||
 | 
					  //     .get(id)
 | 
				
			||||||
 | 
					  //     .pipe(
 | 
				
			||||||
 | 
					  //       tap(user => (this.selected = user)),
 | 
				
			||||||
 | 
					  //       switchMap(() => this.service.getRoles(id)),
 | 
				
			||||||
 | 
					  //     )
 | 
				
			||||||
 | 
					  //     .subscribe(userRole => {
 | 
				
			||||||
 | 
					  //   debugger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //       this.selectedUserRoles = userRole.items || [];
 | 
				
			||||||
 | 
					  //       this.openModal();
 | 
				
			||||||
 | 
					  //     });
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // save() {
 | 
				
			||||||
 | 
					  //   if (!this.form.valid || this.modalBusy) return;
 | 
				
			||||||
 | 
					  //   this.modalBusy = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //   const { roleNames = [] } = this.form.value;
 | 
				
			||||||
 | 
					  //   const mappedRoleNames =
 | 
				
			||||||
 | 
					  //     roleNames
 | 
				
			||||||
 | 
					  //       .filter((role: { [key: string]: any }) => !!role[Object.keys(role)[0]])
 | 
				
			||||||
 | 
					  //       .map((role: { [key: string]: any }) => Object.keys(role)[0]) || [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //   const { id } = this.selected || {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //   (id
 | 
				
			||||||
 | 
					  //     ? this.service.update(id, {
 | 
				
			||||||
 | 
					  //         ...this.selected,
 | 
				
			||||||
 | 
					  //         ...this.form.value,
 | 
				
			||||||
 | 
					  //         roleNames: mappedRoleNames,
 | 
				
			||||||
 | 
					  //       })
 | 
				
			||||||
 | 
					  //     : this.service.create({ ...this.form.value, roleNames: mappedRoleNames })
 | 
				
			||||||
 | 
					  //   )
 | 
				
			||||||
 | 
					  //     .pipe(finalize(() => (this.modalBusy = false)))
 | 
				
			||||||
 | 
					  //     .subscribe(() => {
 | 
				
			||||||
 | 
					  //       this.isModalVisible = false;
 | 
				
			||||||
 | 
					  //       this.toasterService.success('AbpUi::SavedSuccessfully');
 | 
				
			||||||
 | 
					  //       this.list.get();
 | 
				
			||||||
 | 
					  //     });
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					  buildForm() {
 | 
				
			||||||
 | 
					    this.service.getAssignableRoles().subscribe(({ items }) => {
 | 
				
			||||||
 | 
					      this.roles = items.map(role => ({
 | 
				
			||||||
 | 
					        ...role,
 | 
				
			||||||
 | 
					        selected: this.selectedUserRoles.some(userRole => userRole.id === role.id),
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Initialize the selected roles based on existing data for selected user
 | 
				
			||||||
 | 
					      if (this.selected?.id) {
 | 
				
			||||||
 | 
					        this.roles.forEach(role => {
 | 
				
			||||||
 | 
					          role.selected = this.selectedUserRoles.some(userRole => userRole.id === role.id);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // Default values when creating a new user
 | 
				
			||||||
 | 
					        this.roles.forEach(role => {
 | 
				
			||||||
 | 
					          role.selected = role.isDefault;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  openModal() {
 | 
				
			||||||
 | 
					    this.loadRoles(); // Load roles when modal opens
 | 
				
			||||||
 | 
					    this.isModalVisible = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  loadRoles() {
 | 
				
			||||||
 | 
					    this.service.getAssignableRoles().subscribe(({ items }) => {
 | 
				
			||||||
 | 
					      this.roles = items.map(role => ({
 | 
				
			||||||
 | 
					        ...role, // spread IdentityRoleDto properties
 | 
				
			||||||
 | 
					        selected: false, // Initially no role is selected
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  add() {
 | 
				
			||||||
 | 
					    this.selected = {} as IdentityUserDto;
 | 
				
			||||||
 | 
					    this.selectedUserRoles = [] as IdentityRoleDto[];
 | 
				
			||||||
 | 
					    this.password = ''; // Store password separately
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.openModal();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  edit(id: string) {
 | 
				
			||||||
 | 
					    this.service
 | 
				
			||||||
 | 
					      .get(id)
 | 
				
			||||||
 | 
					      .pipe(finalize(() => this.buildForm()))
 | 
				
			||||||
 | 
					      .subscribe(user => {
 | 
				
			||||||
 | 
					        this.selected = user;
 | 
				
			||||||
 | 
					        this.service.getRoles(id).subscribe(userRoles => {
 | 
				
			||||||
 | 
					          this.selectedUserRoles = userRoles.items || [];
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    this.openModal();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Save user data (either create or update)
 | 
				
			||||||
 | 
					  save(form: NgForm) {
 | 
				
			||||||
 | 
					    debugger;
 | 
				
			||||||
 | 
					    if (this.modalBusy || form.invalid) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.modalBusy = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Prepare roleNames array
 | 
				
			||||||
 | 
					 // Prepare roleNames array
 | 
				
			||||||
 | 
					 const selectedRoleNames = this.roles
 | 
				
			||||||
 | 
					 .filter(role => role.selected) // Only include selected roles
 | 
				
			||||||
 | 
					 .map(role => role.name); // Extract role names
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create user payload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userPayload: any = {
 | 
				
			||||||
 | 
					      userName: this.selected.userName,
 | 
				
			||||||
 | 
					      name: this.selected.name,
 | 
				
			||||||
 | 
					      surname: this.selected.surname,
 | 
				
			||||||
 | 
					      email: this.selected.email,
 | 
				
			||||||
 | 
					      phoneNumber: this.selected.phoneNumber,
 | 
				
			||||||
 | 
					      isActive: this.selected.isActive,
 | 
				
			||||||
 | 
					      lockoutEnabled: this.selected.lockoutEnabled,
 | 
				
			||||||
 | 
					      roleNames: selectedRoleNames, // Include selected roles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    // Only include password if creating a new user
 | 
				
			||||||
 | 
					    if (!this.selected.id && this.password) {
 | 
				
			||||||
 | 
					      userPayload.password = this.password;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Handle create or update
 | 
				
			||||||
 | 
					    const saveObservable = this.selected.id
 | 
				
			||||||
 | 
					      ? this.service.update(this.selected.id, userPayload) // Update if id exists
 | 
				
			||||||
 | 
					      : this.service.create(userPayload); // Create if no id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    saveObservable.pipe(finalize(() => (this.modalBusy = false))).subscribe(() => {
 | 
				
			||||||
 | 
					      this.isModalVisible = false;
 | 
				
			||||||
 | 
					      this.toasterService.success('AbpUi::SavedSuccessfully');
 | 
				
			||||||
 | 
					      this.list.get(); // Reload the list if needed
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private getRoleNames() {
 | 
				
			||||||
 | 
					    return this.roles.filter(role => role.selected).map(role => role.name);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  delete(id: string, userName: string) {
 | 
				
			||||||
 | 
					    this.confirmationService
 | 
				
			||||||
 | 
					      .warn('AbpIdentity::UserDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', {
 | 
				
			||||||
 | 
					        messageLocalizationParams: [userName],
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .subscribe((status: Confirmation.Status) => {
 | 
				
			||||||
 | 
					        if (status === Confirmation.Status.confirm) {
 | 
				
			||||||
 | 
					          this.service.delete(id).subscribe(() => {
 | 
				
			||||||
 | 
					            this.toasterService.success('AbpUi::DeletedSuccessfully');
 | 
				
			||||||
 | 
					            this.list.get();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  sort(data: any) {
 | 
				
			||||||
 | 
					    const { prop, dir } = data.sorts[0];
 | 
				
			||||||
 | 
					    this.list.sortKey = prop;
 | 
				
			||||||
 | 
					    this.list.sortOrder = dir;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // private hookToQuery() {
 | 
				
			||||||
 | 
					  //   this.list.hookToQuery(query => this.service.getList(query)).subscribe(res => (this.data = res));
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					  private hookToQuery() {
 | 
				
			||||||
 | 
					    this.list
 | 
				
			||||||
 | 
					      .hookToQuery(query => {
 | 
				
			||||||
 | 
					        console.log('Query:', query); // Log the query
 | 
				
			||||||
 | 
					        return this.service.getList(query);
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .subscribe(res => {
 | 
				
			||||||
 | 
					        debugger;
 | 
				
			||||||
 | 
					        this.data = res;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  openPermissionsModal(providerKey: string, entityDisplayName?: string) {
 | 
				
			||||||
 | 
					    debugger;
 | 
				
			||||||
 | 
					    this.providerKey = providerKey;
 | 
				
			||||||
 | 
					    this.entityDisplayName = entityDisplayName;
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      this.visiblePermissions = true;
 | 
				
			||||||
 | 
					    }, 0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,335 @@
 | 
				
			|||||||
 | 
					<!-- <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']"
 | 
				
			||||||
 | 
					        [filters]="{ global: { value: '', matchMode: 'contains' } }" class="table table-striped">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ng-template pTemplate="caption">
 | 
				
			||||||
 | 
					            <div class="flex">
 | 
				
			||||||
 | 
					                <h2 class="mr-auto">Patient List</h2>
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <button *ngIf="createpermission" pButton class="p-button-rounded p-button-success ml-2"
 | 
				
			||||||
 | 
					                        (click)="openNewPatientDialog()">
 | 
				
			||||||
 | 
					                        <i class="pi pi-plus-circle"></i>
 | 
				
			||||||
 | 
					                    </button>
 | 
				
			||||||
 | 
					                    <button pButton class="p-button-rounded p-button-warning ml-2" (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>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <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 ? 'male' : 'female'">
 | 
				
			||||||
 | 
					                        {{ gender[patient.gender] }}
 | 
				
			||||||
 | 
					                    </span>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>{{ patient.admissionDate | date }}</td>
 | 
				
			||||||
 | 
					                <td>{{ patient.bloodGroup }}</td>
 | 
				
			||||||
 | 
					                <td>{{ patient.mobile }}</td>
 | 
				
			||||||
 | 
					                <td>{{ patient.email }}</td>
 | 
				
			||||||
 | 
					                <td>{{ status[patient.status] }}</td>
 | 
				
			||||||
 | 
					                <td class="d-flex">
 | 
				
			||||||
 | 
					                    <button *ngIf="createpermission" pButton 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 ml-1" (click)="editPatient(patient)"><i
 | 
				
			||||||
 | 
					                            class="pi pi-pencil"></i></button>
 | 
				
			||||||
 | 
					                    <button *ngIf="deletepermission" class="btn btn-danger btn-sm ml-1"
 | 
				
			||||||
 | 
					                        (click)="deletePatient(patient.id)"><i class="pi pi-trash"></i></button>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ng-template pTemplate="emptymessage">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td colspan="10">No Patients found.</td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </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="patientCardId">Card ID <p-sortIcon field="patientCardId" /></th>
 | 
				
			||||||
 | 
					                    <th pSortableColumn="name">Full Name <p-sortIcon field="name" /></th>
 | 
				
			||||||
 | 
					                    <th pSortableColumn="gender">Gender <p-sortIcon field="gender" /></th>
 | 
				
			||||||
 | 
					                    <th pSortableColumn="bloodGroup">Blood Group <p-sortIcon field="bloodGroup" /></th>
 | 
				
			||||||
 | 
					                    <th>Mobile</th>
 | 
				
			||||||
 | 
					                    <th>Age</th>
 | 
				
			||||||
 | 
					                    <th>Email</th>
 | 
				
			||||||
 | 
					                    <th pSortableColumn="insuranceProvider">Insurance <p-sortIcon field="insuranceProvider" /></th>
 | 
				
			||||||
 | 
					                    <th>Actions</th>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					            </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <ng-template pTemplate="body" let-patient>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <td class="hidden">{{ patient.id }}</td>
 | 
				
			||||||
 | 
					                    <td>{{patient.patientCardId}}</td>
 | 
				
			||||||
 | 
					                    <td>{{ patient.name }}</td>
 | 
				
			||||||
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        <span class="badge" [ngClass]="patient.gender === 1 ? 'bg-primary' : 'bg-pink'">
 | 
				
			||||||
 | 
					                            {{ gender[patient.gender] }}
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td>{{ patient.bloodGroup }}</td>
 | 
				
			||||||
 | 
					                    <td>{{ patient.mobile }}</td>
 | 
				
			||||||
 | 
					                    <td>{{patient.age}}</td>
 | 
				
			||||||
 | 
					                    <td>{{ patient.email }}</td>
 | 
				
			||||||
 | 
					                    <td>{{patient.insuranceProvider}}</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: '80%', height: 'auto'}" class="modern-dialog">
 | 
				
			||||||
 | 
					        <form #patientrecord="ngForm" (ngSubmit)="savePatient(patientrecord)">
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="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>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="p-fluid grid">
 | 
				
			||||||
 | 
					                <div class="col-6">
 | 
				
			||||||
 | 
					                    <div class="field">
 | 
				
			||||||
 | 
					                        <label for="image"><i class="pi pi-image"></i> Profile Image</label>
 | 
				
			||||||
 | 
					                        <input class="d-flex" type="file" id="image" name="image" accept=".jpg,.png"
 | 
				
			||||||
 | 
					                            (change)="profileimageupload($event)" />
 | 
				
			||||||
 | 
					                    </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 class="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> -->
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <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>
 | 
				
			||||||
 | 
					            <div class="p-fluid grid">
 | 
				
			||||||
 | 
					                <!-- 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>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="col-6">
 | 
				
			||||||
 | 
					                    <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 class="p-fluid grid"> -->
 | 
				
			||||||
 | 
					            <!-- <div class="col-6">
 | 
				
			||||||
 | 
					                    <div class="field">
 | 
				
			||||||
 | 
					                        <label for="admissionDate"><i class="pi pi-calendar"></i> Admission Date</label>
 | 
				
			||||||
 | 
					                        <p-calendar appendTo="body" 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">
 | 
				
			||||||
 | 
					                <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>
 | 
				
			||||||
 | 
					            <!-- Insurance Provider -->
 | 
				
			||||||
 | 
					            <div class="p-fluid grid">
 | 
				
			||||||
 | 
					                <div class="col-6">
 | 
				
			||||||
 | 
					                    <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>
 | 
				
			||||||
 | 
					                <div class="col-6">
 | 
				
			||||||
 | 
					                    <div class="field">
 | 
				
			||||||
 | 
					                        <label for="patientCardId"><i class="pi pi-credit-card"></i> Card ID</label>
 | 
				
			||||||
 | 
					                        <input id="patientCardId" name="patientCardId" type="text" pInputText
 | 
				
			||||||
 | 
					                            [(ngModel)]="selectedPatient.patientCardId" required
 | 
				
			||||||
 | 
					                            placeholder="Enter patient card Id" #patientCardId="ngModel" />
 | 
				
			||||||
 | 
					                        <small *ngIf="patientCardId.invalid && patientCardId.touched" class="p-error">
 | 
				
			||||||
 | 
					                            Card Id is required.
 | 
				
			||||||
 | 
					                        </small>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="text-right">
 | 
				
			||||||
 | 
					                <button type="submit" pButton class="btn btn-primary"
 | 
				
			||||||
 | 
					                    [disabled]="(patientrecord.invalid || !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>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					.table-header {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    justify-content: space-between;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .badge {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    padding: 0.2rem 0.6rem;
 | 
				
			||||||
 | 
					    border-radius: 0.5rem;
 | 
				
			||||||
 | 
					    color: white;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    font-size: 0.8rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .male {
 | 
				
			||||||
 | 
					    background-color: green;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .female {
 | 
				
			||||||
 | 
					    background-color: purple;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .pdf-icon {
 | 
				
			||||||
 | 
					    color: red;
 | 
				
			||||||
 | 
					    font-size: 1.2rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .bg-pink {
 | 
				
			||||||
 | 
					    background-color: #ff4081 !important;
 | 
				
			||||||
 | 
					    color: white;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.gap-1 {
 | 
				
			||||||
 | 
					    gap: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
							
								
								
									
										259
									
								
								angular/src/app/patients/all-patients/all-patients.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								angular/src/app/patients/all-patients/all-patients.component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,259 @@
 | 
				
			|||||||
 | 
					import { PermissionService } from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { Confirmation, ConfirmationService, ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { HttpClient, HttpEventType, HttpParams, HttpRequest } from '@angular/common/http';
 | 
				
			||||||
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import { NgForm } from '@angular/forms';
 | 
				
			||||||
 | 
					import { Router } from '@angular/router';
 | 
				
			||||||
 | 
					import { PagingSortResultDto } from '@proxy/dto';
 | 
				
			||||||
 | 
					import { Gender } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					import { PatientService } from '@proxy/patients';
 | 
				
			||||||
 | 
					import { PatientDto, CreateUpdatePatientDto } from '@proxy/patients/dto';
 | 
				
			||||||
 | 
					import { environment } from 'src/environments/environment';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-all-patients',
 | 
				
			||||||
 | 
					  templateUrl: './all-patients.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './all-patients.component.scss',
 | 
				
			||||||
 | 
					  providers: [PatientService, ConfirmationService, ToasterService, PermissionService],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AllPatientsComponent implements OnInit {
 | 
				
			||||||
 | 
					  globalFilter: string = '';
 | 
				
			||||||
 | 
					  patients: PatientDto[];
 | 
				
			||||||
 | 
					  totalRecords: number = 0;
 | 
				
			||||||
 | 
					  loading: boolean = false;
 | 
				
			||||||
 | 
					  patientDialog: boolean = false;
 | 
				
			||||||
 | 
					  selectedPatient: CreateUpdatePatientDto;
 | 
				
			||||||
 | 
					  isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  patientDialogTitle: string = '';
 | 
				
			||||||
 | 
					  params: PagingSortResultDto;
 | 
				
			||||||
 | 
					  gender: any;
 | 
				
			||||||
 | 
					  selectedgender: any = 0;
 | 
				
			||||||
 | 
					  selectadmissionDate: Date = new Date();
 | 
				
			||||||
 | 
					  selectdischargeDate: Date = new Date();
 | 
				
			||||||
 | 
					  createpermission: boolean;
 | 
				
			||||||
 | 
					  editpermission: boolean;
 | 
				
			||||||
 | 
					  deletepermission: boolean;
 | 
				
			||||||
 | 
					  imgpath: string = '';
 | 
				
			||||||
 | 
					  guid: string = '00000000-0000-0000-0000-000000000000';
 | 
				
			||||||
 | 
					  uploadProgress = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private patientService: PatientService,
 | 
				
			||||||
 | 
					    private http: HttpClient,
 | 
				
			||||||
 | 
					    private confirmation: ConfirmationService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService,
 | 
				
			||||||
 | 
					    private permissionChecker: PermissionService,
 | 
				
			||||||
 | 
					    private router: Router
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					    this.createpermission = this.permissionChecker.getGrantedPolicy(
 | 
				
			||||||
 | 
					      'HospitalManagementSystem.Patient.Create'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.editpermission = this.permissionChecker.getGrantedPolicy(
 | 
				
			||||||
 | 
					      'HospitalManagementSystem.Patient.Edit'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.deletepermission = this.permissionChecker.getGrantedPolicy(
 | 
				
			||||||
 | 
					      'HospitalManagementSystem.Patient.Delete'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.gender = Gender;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.resetselectpatient();
 | 
				
			||||||
 | 
					    this.loadPatient({
 | 
				
			||||||
 | 
					      first: 0,
 | 
				
			||||||
 | 
					      rows: 10,
 | 
				
			||||||
 | 
					      sortField: 'id',
 | 
				
			||||||
 | 
					      sortOrder: 1,
 | 
				
			||||||
 | 
					      globalFilter: null,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  resetselectpatient() {
 | 
				
			||||||
 | 
					    this.selectedPatient = {
 | 
				
			||||||
 | 
					      name: '',
 | 
				
			||||||
 | 
					      gender: Gender.Male,
 | 
				
			||||||
 | 
					      mobile: '',
 | 
				
			||||||
 | 
					      email: '',
 | 
				
			||||||
 | 
					      age: 0,
 | 
				
			||||||
 | 
					      address: '',
 | 
				
			||||||
 | 
					      bloodGroup: '',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    this.imgpath = '';
 | 
				
			||||||
 | 
					    this.selectedgender = 0;
 | 
				
			||||||
 | 
					    this.uploadProgress = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadPatient(event: any) {
 | 
				
			||||||
 | 
					    this.loading = true;
 | 
				
			||||||
 | 
					    let order = event.sortOrder == 1 ? ' asc' : ' desc';
 | 
				
			||||||
 | 
					    event.sortField = event.sortField == undefined ? 'id' : event.sortField;
 | 
				
			||||||
 | 
					    this.params = {
 | 
				
			||||||
 | 
					      skipCount: event.first,
 | 
				
			||||||
 | 
					      maxResultCount: event.rows,
 | 
				
			||||||
 | 
					      sorting: event.sortField + order,
 | 
				
			||||||
 | 
					      search: event.globalFilter == null ? '' : event.globalFilter,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.patientService.getPatientList(this.params).subscribe(data => {
 | 
				
			||||||
 | 
					      this.patients = data.items;
 | 
				
			||||||
 | 
					      this.totalRecords = data.totalCount;
 | 
				
			||||||
 | 
					      this.loading = false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exportPatient() {
 | 
				
			||||||
 | 
					    this.patientService.getExportPatientData().subscribe(result => {
 | 
				
			||||||
 | 
					      const binary = atob(result.fileContent);
 | 
				
			||||||
 | 
					      const len = binary.length;
 | 
				
			||||||
 | 
					      const bytes = new Uint8Array(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        bytes[i] = binary.charCodeAt(i);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const blob = new Blob([bytes], { type: 'application/xlsx' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const url = window.URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const link = document.createElement('a');
 | 
				
			||||||
 | 
					      link.href = url;
 | 
				
			||||||
 | 
					      link.download = result.fileName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.appendChild(link);
 | 
				
			||||||
 | 
					      link.click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.removeChild(link);
 | 
				
			||||||
 | 
					      window.URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  openNewPatientDialog() {
 | 
				
			||||||
 | 
					    this.patientDialogTitle = 'New Patient';
 | 
				
			||||||
 | 
					    this.resetselectpatient();
 | 
				
			||||||
 | 
					    this.selectedgender = 0;
 | 
				
			||||||
 | 
					    this.patientDialog = true;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addnewrecord(id: any) {
 | 
				
			||||||
 | 
					    this.router.navigate(['/patients/patient-record', id]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  profileimageupload(event: Event) {
 | 
				
			||||||
 | 
					    const input = event.target as HTMLInputElement;
 | 
				
			||||||
 | 
					    if (input.files.length > 0) {
 | 
				
			||||||
 | 
					      const tag = 'Image';
 | 
				
			||||||
 | 
					      const formdata = new FormData();
 | 
				
			||||||
 | 
					      formdata.append('file', input.files[0]);
 | 
				
			||||||
 | 
					      this.UploadFileData(tag, formdata);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.uploadProgress = 0;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UploadFileData(tag: string, formdata: FormData) {
 | 
				
			||||||
 | 
					    const req = new HttpRequest(
 | 
				
			||||||
 | 
					      'POST',
 | 
				
			||||||
 | 
					      environment.apis.default.url + '/api/app/shared/upload-file',
 | 
				
			||||||
 | 
					      formdata,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        reportProgress: true,
 | 
				
			||||||
 | 
					        responseType: 'text',
 | 
				
			||||||
 | 
					        params: new HttpParams().set('tagName', tag),
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.http.request(req).subscribe(
 | 
				
			||||||
 | 
					      event => {
 | 
				
			||||||
 | 
					        if (event.type === HttpEventType.UploadProgress) {
 | 
				
			||||||
 | 
					          this.uploadProgress = Math.round((event.loaded / event.total!) * 100);
 | 
				
			||||||
 | 
					        } else if (event.type === HttpEventType.Response) {
 | 
				
			||||||
 | 
					          this.uploadProgress = 100;
 | 
				
			||||||
 | 
					          this.selectedPatient.imageID = event.body.toString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      error => {
 | 
				
			||||||
 | 
					        this.uploadProgress = 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  editPatient(Patient: any) {
 | 
				
			||||||
 | 
					    this.resetselectpatient();
 | 
				
			||||||
 | 
					    this.patientDialogTitle = 'Edit Patient';
 | 
				
			||||||
 | 
					    this.patientService.getPatientById(Patient.id).subscribe(result => {
 | 
				
			||||||
 | 
					      this.selectedPatient = result;
 | 
				
			||||||
 | 
					      this.imgpath = result.imagepath != null ? result.imagepath.split('\\')[3] : '';
 | 
				
			||||||
 | 
					      this.selectedgender = this.selectedPatient.gender;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.patientDialog = true;
 | 
				
			||||||
 | 
					    this.isEditMode = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deletePatient(id: any) {
 | 
				
			||||||
 | 
					    this.confirmation
 | 
				
			||||||
 | 
					      .warn('Do you really want to delete this patient?', {
 | 
				
			||||||
 | 
					        key: '::AreYouSure',
 | 
				
			||||||
 | 
					        defaultValue: 'Are you sure?',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .subscribe((status: Confirmation.Status) => {
 | 
				
			||||||
 | 
					        // your code here
 | 
				
			||||||
 | 
					        if (status == 'confirm') {
 | 
				
			||||||
 | 
					          this.patientService.deletePatient(id).subscribe(() => {
 | 
				
			||||||
 | 
					            this.toaster.success('Patient deleted successfully', 'Success');
 | 
				
			||||||
 | 
					            this.loadPatient(this.params);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  savePatient(form: NgForm) {
 | 
				
			||||||
 | 
					    if (form.invalid) {
 | 
				
			||||||
 | 
					      Object.values(form.controls).forEach(control => control.markAsTouched());
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.selectedPatient.gender = this.selectedgender;
 | 
				
			||||||
 | 
					    this.selectedPatient.imageID = this.selectedPatient.imageID
 | 
				
			||||||
 | 
					      ? this.selectedPatient.imageID.replace('"', '').replace('"', '')
 | 
				
			||||||
 | 
					      : this.guid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.isEditMode) {
 | 
				
			||||||
 | 
					      this.patientService.updatePatient(this.selectedPatient.id, this.selectedPatient).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Patient updated successfully', 'Success');
 | 
				
			||||||
 | 
					          this.patientDialog = false;
 | 
				
			||||||
 | 
					          this.loadPatient({
 | 
				
			||||||
 | 
					            first: 0,
 | 
				
			||||||
 | 
					            rows: 10,
 | 
				
			||||||
 | 
					            sortField: 'id',
 | 
				
			||||||
 | 
					            sortOrder: 1,
 | 
				
			||||||
 | 
					            globalFilter: null,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.closeDialog();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.patientService.createPatient(this.selectedPatient).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Patient created successfully', 'Success');
 | 
				
			||||||
 | 
					          this.patientDialog = false;
 | 
				
			||||||
 | 
					          this.loadPatient({
 | 
				
			||||||
 | 
					            first: 0,
 | 
				
			||||||
 | 
					            rows: 10,
 | 
				
			||||||
 | 
					            sortField: 'id',
 | 
				
			||||||
 | 
					            sortOrder: 1,
 | 
				
			||||||
 | 
					            globalFilter: null,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.closeDialog();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.patientDialog = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,252 @@
 | 
				
			|||||||
 | 
					<div class="patient-container">
 | 
				
			||||||
 | 
					  <div class="patient-card">
 | 
				
			||||||
 | 
					    <div class="patient-image">
 | 
				
			||||||
 | 
					      <img [src]="patientImageUrl" alt="Patient Image">
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="patient-info">
 | 
				
			||||||
 | 
					      <h2 class="patient-name">{{ patientdto?.name }}</h2>
 | 
				
			||||||
 | 
					      <div class="patient-details">
 | 
				
			||||||
 | 
					        <div class="info-item">
 | 
				
			||||||
 | 
					          <strong>Age:</strong> {{ patientdto?.age }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="info-item">
 | 
				
			||||||
 | 
					          <strong>Gender:</strong> {{ gender[patientdto?.gender] }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="info-item">
 | 
				
			||||||
 | 
					          <strong>Mobile:</strong> {{ patientdto?.mobile }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="info-item">
 | 
				
			||||||
 | 
					          <strong>Email:</strong> {{ patientdto?.email }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="info-item">
 | 
				
			||||||
 | 
					          <strong>Blood Group:</strong> {{ patientdto?.bloodGroup }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="info-item">
 | 
				
			||||||
 | 
					          <strong>Card ID:</strong> {{ patientdto?.patientCardId }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<div>
 | 
				
			||||||
 | 
					  <button class="btn btn-sm btn-primary mb-2" (click)="backtopatient()">
 | 
				
			||||||
 | 
					    <i class="pi pi-arrow-left"></i> Back
 | 
				
			||||||
 | 
					  </button>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<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 justify-content-between align-items-center">
 | 
				
			||||||
 | 
					        <h3>{{'::PatientHeader' | abpLocalization}}</h3>
 | 
				
			||||||
 | 
					        <div class="flex gap-2">
 | 
				
			||||||
 | 
					          <button *ngIf="createpermission" pButton class="btn btn-success btn-sm" (click)="openNewPatientDialog()">
 | 
				
			||||||
 | 
					            <i class="pi pi-plus-circle"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button pButton class="btn btn-warning btn-sm" (click)="exportPatient()">
 | 
				
			||||||
 | 
					            <i class="pi pi-download"></i>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template pTemplate="header">
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <th class="hidden" pSortableColumn="id">Patient ID <p-sortIcon field="id" /></th>
 | 
				
			||||||
 | 
					        <th>Full Name</th>
 | 
				
			||||||
 | 
					        <th>Gender</th>
 | 
				
			||||||
 | 
					        <th>Doctor</th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="dateOfAdmission">Date of Admission <p-sortIcon field="dateOfAdmission" /></th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="dischargeDate">Discharge Date <p-sortIcon field="dischargeDate" /></th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="nextFollowUp">Next Follow-Up <p-sortIcon field="nextFollowUp" /></th>
 | 
				
			||||||
 | 
					        <th pSortableColumn="diagnosis">Diagnosis <p-sortIcon field="diagnosis" /></th>
 | 
				
			||||||
 | 
					        <th>Lab Reports</th>
 | 
				
			||||||
 | 
					        <th>Medications</th>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <th pSortableColumn="status">Status <p-sortIcon field="status" /></th>
 | 
				
			||||||
 | 
					        <th>Actions</th>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ng-template pTemplate="body" let-patientrecord>
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <td class="hidden">{{ patientrecord.id }}</td>
 | 
				
			||||||
 | 
					        <td>{{ patientrecord.patients.name }}</td>
 | 
				
			||||||
 | 
					        <td>
 | 
				
			||||||
 | 
					          <span class="badge" [ngClass]="patientrecord.patients.gender === 1 ? 'male' : 'female'">
 | 
				
			||||||
 | 
					            {{ gender[patientrecord.patients.gender] }}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td><span *ngIf="patientrecord.doctorAssigned !== null">{{'Dr. ' + patientrecord.doctorAssigned?.firstName + ' '
 | 
				
			||||||
 | 
					            +
 | 
				
			||||||
 | 
					            patientrecord.doctorAssigned?.lastName}}</span></td>
 | 
				
			||||||
 | 
					        <td>{{ patientrecord.dateOfAdmission | date }}</td>
 | 
				
			||||||
 | 
					        <td>{{ patientrecord.dischargeDate | date }}</td>
 | 
				
			||||||
 | 
					        <td>{{ patientrecord.nextFollowUp | date }}</td>
 | 
				
			||||||
 | 
					        <td>{{ patientrecord.diagnosis }}</td>
 | 
				
			||||||
 | 
					        <td><i class="pi pi-file-pdf text-danger"></i></td>
 | 
				
			||||||
 | 
					        <td><i class="pi pi-file-pdf text-primary"></i></td>
 | 
				
			||||||
 | 
					        <td>
 | 
				
			||||||
 | 
					          <span class="badge"
 | 
				
			||||||
 | 
					            [ngClass]="patientrecord.status === 1 ? 'bg-success' : (patientrecord.status === 2 ? 'bg-primary':'bg-danger')">
 | 
				
			||||||
 | 
					            {{ status[patientrecord.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="9">No Patients found.</td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </ng-template>
 | 
				
			||||||
 | 
					  </p-table>
 | 
				
			||||||
 | 
					  <div class="mt-2">Total Records: {{totalRecords}}</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<div>
 | 
				
			||||||
 | 
					  <p-dialog *ngIf="patientDialog" header="{{patientDialogTitle}}" [(visible)]="patientDialog" [modal]="true"
 | 
				
			||||||
 | 
					    [closable]="true" [style]="{width: '70%', height: 'auto'}">
 | 
				
			||||||
 | 
					    <form #patientrecord="ngForm" (ngSubmit)="savePatient(patientrecord)" novalidate>
 | 
				
			||||||
 | 
					      <div class="p-fluid grid">
 | 
				
			||||||
 | 
					        <div class="col-6">
 | 
				
			||||||
 | 
					          <div class="field">
 | 
				
			||||||
 | 
					            <label for="admissionDate"><i class="pi pi-calendar"></i> Admission Date <span
 | 
				
			||||||
 | 
					                class="text-danger">*</span></label>
 | 
				
			||||||
 | 
					            <p-calendar appendTo="body" 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="col-6">
 | 
				
			||||||
 | 
					          <div class="field">
 | 
				
			||||||
 | 
					            <label for="nextFollowUp"><i class="pi pi-calendar-plus"></i> Next Follow-Up Date</label>
 | 
				
			||||||
 | 
					            <p-calendar appendTo="body" id="nextFollowUp" name="nextFollowUp" [(ngModel)]="selectnextFollowUp"
 | 
				
			||||||
 | 
					              showIcon></p-calendar>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="p-fluid grid">
 | 
				
			||||||
 | 
					        <div class="col-6">
 | 
				
			||||||
 | 
					          <div class="field">
 | 
				
			||||||
 | 
					            <label for="dischargeDate"><i class="pi pi-calendar"></i> Discharge Date</label>
 | 
				
			||||||
 | 
					            <p-calendar appendTo="body" id="dischargeDate" name="dischargeDate" [(ngModel)]="selectdischargeDate"
 | 
				
			||||||
 | 
					              showIcon></p-calendar>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="col-6">
 | 
				
			||||||
 | 
					          <div class="field">
 | 
				
			||||||
 | 
					            <label for="status">Status <span class="text-danger">*</span></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>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="p-fluid grid">
 | 
				
			||||||
 | 
					        <div class="col-6">
 | 
				
			||||||
 | 
					          <div class="field">
 | 
				
			||||||
 | 
					            <label for="doctorAssignedID">Consulting Doctor <span class="text-danger">*</span></label>
 | 
				
			||||||
 | 
					            <p-dropdown id="doctorAssignedID" name="doctorAssignedID"
 | 
				
			||||||
 | 
					              [(ngModel)]="selectedPatientRecord.doctorAssignedID" [options]="doctorOptions" placeholder="Select Doctor"
 | 
				
			||||||
 | 
					              optionLabel="label" optionValue="value" required></p-dropdown>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <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)]="selectedPatientRecord.diagnosis"></textarea>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="p-fluid">
 | 
				
			||||||
 | 
					        <div class="field">
 | 
				
			||||||
 | 
					          <label for="treatmentPlan"><i class="pi pi-heartbeat"></i> Treatment Plan</label>
 | 
				
			||||||
 | 
					          <textarea style="width: 100%; background-color: #fff; color: black;" id="treatmentPlan" name="treatmentPlan"
 | 
				
			||||||
 | 
					            pInputTextarea rows="5" cols="30" [(ngModel)]="selectedPatientRecord.treatmentPlan"></textarea>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="p-fluid">
 | 
				
			||||||
 | 
					        <div class="field">
 | 
				
			||||||
 | 
					          <label for="doctorNotes"><i class="pi pi-heartbeat"></i> Doctor Notes</label>
 | 
				
			||||||
 | 
					          <textarea style="width: 100%; background-color: #fff; color: black;" id="doctorNotes" name="doctorNotes"
 | 
				
			||||||
 | 
					            pInputTextarea rows="5" cols="30" [(ngModel)]="selectedPatientRecord.doctorNotes"></textarea>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <hr>
 | 
				
			||||||
 | 
					      <h3 class="mb-4">Documents</h3>
 | 
				
			||||||
 | 
					      <!-- 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 class="d-flex" 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 class="d-flex" 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 class="d-flex" 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>
 | 
				
			||||||
 | 
					      <!-- Buttons -->
 | 
				
			||||||
 | 
					      <div class="p-dialog-footer flex justify-content-end">
 | 
				
			||||||
 | 
					        <button type="submit" pButton class="btn btn-primary"
 | 
				
			||||||
 | 
					          [disabled]="patientrecord.invalid || selectedstatus === 0">
 | 
				
			||||||
 | 
					          <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>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					.table-header {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    justify-content: space-between;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .badge {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    padding: 0.2rem 0.6rem;
 | 
				
			||||||
 | 
					    border-radius: 0.5rem;
 | 
				
			||||||
 | 
					    color: white;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    font-size: 0.8rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .male {
 | 
				
			||||||
 | 
					    background-color: green;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .female {
 | 
				
			||||||
 | 
					    background-color: #ff4081 !important;
 | 
				
			||||||
 | 
					    color: white;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .pdf-icon {
 | 
				
			||||||
 | 
					    color: red;
 | 
				
			||||||
 | 
					    font-size: 1.2rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .patient-container {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    justify-content: center;
 | 
				
			||||||
 | 
					    margin-bottom: 20px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .patient-card {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    max-width: 800px;
 | 
				
			||||||
 | 
					    background: #ffffff;
 | 
				
			||||||
 | 
					    border-radius: 12px;
 | 
				
			||||||
 | 
					    padding: 20px;
 | 
				
			||||||
 | 
					    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
 | 
				
			||||||
 | 
					    border-left: 5px solid #007bff;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .patient-image img {
 | 
				
			||||||
 | 
					    width: 100px;
 | 
				
			||||||
 | 
					    height: 100px;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    object-fit: cover;
 | 
				
			||||||
 | 
					    border: 3px solid #007bff;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .patient-info {
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					    margin-left: 20px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .patient-name {
 | 
				
			||||||
 | 
					    font-size: 22px;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    color: #333;
 | 
				
			||||||
 | 
					    margin-bottom: 8px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .patient-details {
 | 
				
			||||||
 | 
					    display: grid;
 | 
				
			||||||
 | 
					    grid-template-columns: repeat(2, minmax(150px, 1fr));
 | 
				
			||||||
 | 
					    gap: 8px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  .info-item {
 | 
				
			||||||
 | 
					    font-size: 14px;
 | 
				
			||||||
 | 
					    background: #f8f9fa;
 | 
				
			||||||
 | 
					    padding: 6px 12px;
 | 
				
			||||||
 | 
					    border-radius: 6px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
@ -0,0 +1,357 @@
 | 
				
			|||||||
 | 
					import { Component, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					import { NgForm } from '@angular/forms';
 | 
				
			||||||
 | 
					import { PagingSortResultDto } from '@proxy/dto';
 | 
				
			||||||
 | 
					import { Gender, Status } from '@proxy/global-enum';
 | 
				
			||||||
 | 
					import { PatientService } from '@proxy/patients';
 | 
				
			||||||
 | 
					import { CreateUpdatePatientRecordDto, PatientDto, PatientRecordDto } from '@proxy/patients/dto';
 | 
				
			||||||
 | 
					import { PermissionService } from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { ActivatedRoute, Router } from '@angular/router';
 | 
				
			||||||
 | 
					import { environment } from 'src/environments/environment';
 | 
				
			||||||
 | 
					import { Confirmation, ConfirmationService, ToasterService } from '@abp/ng.theme.shared';
 | 
				
			||||||
 | 
					import { HttpClient, HttpEventType, HttpParams, HttpRequest } from '@angular/common/http';
 | 
				
			||||||
 | 
					import { DoctorService } from '@proxy/doctors/doctor.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'app-patient-record',
 | 
				
			||||||
 | 
					  templateUrl: './patient-record.component.html',
 | 
				
			||||||
 | 
					  styleUrl: './patient-record.component.scss',
 | 
				
			||||||
 | 
					  providers: [
 | 
				
			||||||
 | 
					    PatientService,
 | 
				
			||||||
 | 
					    ConfirmationService,
 | 
				
			||||||
 | 
					    DoctorService,
 | 
				
			||||||
 | 
					    ToasterService,
 | 
				
			||||||
 | 
					    PermissionService,
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class PatientRecordComponent implements OnInit {
 | 
				
			||||||
 | 
					  globalFilter: string = '';
 | 
				
			||||||
 | 
					  patientrecords: PatientRecordDto[];
 | 
				
			||||||
 | 
					  totalRecords: number = 0;
 | 
				
			||||||
 | 
					  loading: boolean = false;
 | 
				
			||||||
 | 
					  patientDialog: boolean = false;
 | 
				
			||||||
 | 
					  selectedPatientRecord: CreateUpdatePatientRecordDto;
 | 
				
			||||||
 | 
					  patientdto: PatientDto;
 | 
				
			||||||
 | 
					  isEditMode: boolean = false;
 | 
				
			||||||
 | 
					  patientDialogTitle: string = '';
 | 
				
			||||||
 | 
					  params: PagingSortResultDto;
 | 
				
			||||||
 | 
					  status: any;
 | 
				
			||||||
 | 
					  gender: any;
 | 
				
			||||||
 | 
					  statuslist: any;
 | 
				
			||||||
 | 
					  selectdateOfAdmission: Date = new Date();
 | 
				
			||||||
 | 
					  selectnextFollowUp: Date = new Date();
 | 
				
			||||||
 | 
					  selectdischargeDate: Date = new Date();
 | 
				
			||||||
 | 
					  selectedstatus = 0;
 | 
				
			||||||
 | 
					  createpermission: boolean;
 | 
				
			||||||
 | 
					  editpermission: boolean;
 | 
				
			||||||
 | 
					  deletepermission: boolean;
 | 
				
			||||||
 | 
					  patientId: any;
 | 
				
			||||||
 | 
					  patientImageUrl: string;
 | 
				
			||||||
 | 
					  labReportUrlpath: string;
 | 
				
			||||||
 | 
					  medicationHistoryUrlpath: string;
 | 
				
			||||||
 | 
					  medicationUrlpath: string;
 | 
				
			||||||
 | 
					  guid: string = '00000000-0000-0000-0000-000000000000';
 | 
				
			||||||
 | 
					  uploadProgress1 = 0;
 | 
				
			||||||
 | 
					  uploadProgress2 = 0;
 | 
				
			||||||
 | 
					  uploadProgress3 = 0;
 | 
				
			||||||
 | 
					  doctorOptions = [];
 | 
				
			||||||
 | 
					  doctorname = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private patientService: PatientService,
 | 
				
			||||||
 | 
					    private confirmation: ConfirmationService,
 | 
				
			||||||
 | 
					    private permissionChecker: PermissionService,
 | 
				
			||||||
 | 
					    private DoctorService: DoctorService,
 | 
				
			||||||
 | 
					    private toaster: ToasterService,
 | 
				
			||||||
 | 
					    private route: ActivatedRoute,
 | 
				
			||||||
 | 
					    private router: Router,
 | 
				
			||||||
 | 
					    private http: HttpClient
 | 
				
			||||||
 | 
					  ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					    this.patientId = this.route.snapshot.paramMap.get('id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.createpermission = this.permissionChecker.getGrantedPolicy(
 | 
				
			||||||
 | 
					      'HospitalManagementSystem.Patient.Create'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.editpermission = this.permissionChecker.getGrantedPolicy(
 | 
				
			||||||
 | 
					      'HospitalManagementSystem.Patient.Edit'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.deletepermission = this.permissionChecker.getGrantedPolicy(
 | 
				
			||||||
 | 
					      'HospitalManagementSystem.Patient.Delete'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.status = Status;
 | 
				
			||||||
 | 
					    this.gender = Gender;
 | 
				
			||||||
 | 
					    this.patientService.getStatusDropdown().subscribe(result => {
 | 
				
			||||||
 | 
					      this.statuslist = result;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.resetselectpatient();
 | 
				
			||||||
 | 
					    this.getdoctorlist();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  resetselectpatient() {
 | 
				
			||||||
 | 
					    this.selectedPatientRecord = {
 | 
				
			||||||
 | 
					      patientId: this.patientId,
 | 
				
			||||||
 | 
					      dateOfAdmission: '',
 | 
				
			||||||
 | 
					      // labReportUrl: '',
 | 
				
			||||||
 | 
					      // medicationUrl: '',
 | 
				
			||||||
 | 
					      // medicationHistoryUrl: '',
 | 
				
			||||||
 | 
					      nextFollowUp: '',
 | 
				
			||||||
 | 
					      diagnosis: '',
 | 
				
			||||||
 | 
					      treatmentPlan: '',
 | 
				
			||||||
 | 
					      doctorNotes: '',
 | 
				
			||||||
 | 
					      status: Status.InTreatment,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    this.labReportUrlpath = '';
 | 
				
			||||||
 | 
					    this.medicationUrlpath = '';
 | 
				
			||||||
 | 
					    this.medicationHistoryUrlpath = '';
 | 
				
			||||||
 | 
					    this.selectdateOfAdmission = new Date();
 | 
				
			||||||
 | 
					    this.selectnextFollowUp = new Date();
 | 
				
			||||||
 | 
					    this.selectdischargeDate = new Date();
 | 
				
			||||||
 | 
					    this.selectedstatus = 0;
 | 
				
			||||||
 | 
					    this.uploadProgress1 = 0;
 | 
				
			||||||
 | 
					    this.uploadProgress2 = 0;
 | 
				
			||||||
 | 
					    this.uploadProgress3 = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadPatient(event: any, id: any) {
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.patientId = this.patientId;
 | 
				
			||||||
 | 
					    this.loading = true;
 | 
				
			||||||
 | 
					    let order = event.sortOrder == 1 ? ' asc' : ' desc';
 | 
				
			||||||
 | 
					    event.sortField = event.sortField == undefined ? 'id' : event.sortField;
 | 
				
			||||||
 | 
					    this.params = {
 | 
				
			||||||
 | 
					      skipCount: event.first,
 | 
				
			||||||
 | 
					      maxResultCount: event.rows,
 | 
				
			||||||
 | 
					      sorting: event.sortField + order,
 | 
				
			||||||
 | 
					      search: event.globalFilter == null ? '' : event.globalFilter,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    this.patientService.getPatientById(this.patientId).subscribe(result => {
 | 
				
			||||||
 | 
					      this.patientdto = result;
 | 
				
			||||||
 | 
					      this.patientImageUrl =
 | 
				
			||||||
 | 
					        environment.apis.default.url +
 | 
				
			||||||
 | 
					        (result.imagepath !== null ? result.imagepath : '/images/default-profile.png');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.patientService.getPatientRecordList(this.params, id).subscribe(data => {
 | 
				
			||||||
 | 
					      this.patientrecords = data.items;
 | 
				
			||||||
 | 
					      this.totalRecords = data.totalCount;
 | 
				
			||||||
 | 
					      this.loading = false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getdoctorlist() {
 | 
				
			||||||
 | 
					    this.DoctorService.get().subscribe(result => {
 | 
				
			||||||
 | 
					      const doctors = result;
 | 
				
			||||||
 | 
					      this.doctorOptions = doctors.map(doctor => ({
 | 
				
			||||||
 | 
					        label: `Dr. ${doctor.firstName} ${doctor.lastName}`, // Combine first and last name
 | 
				
			||||||
 | 
					        value: doctor.id, // Use the ID as the value
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  backtopatient() {
 | 
				
			||||||
 | 
					    this.router.navigate(['/patients/all-patients']);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  exportPatient() {
 | 
				
			||||||
 | 
					    this.patientService.getExportPatientRecord(this.patientId).subscribe(result => {
 | 
				
			||||||
 | 
					      const binary = atob(result.fileContent);
 | 
				
			||||||
 | 
					      const len = binary.length;
 | 
				
			||||||
 | 
					      const bytes = new Uint8Array(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        bytes[i] = binary.charCodeAt(i);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const blob = new Blob([bytes], { type: 'application/xlsx' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const url = window.URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const link = document.createElement('a');
 | 
				
			||||||
 | 
					      link.href = url;
 | 
				
			||||||
 | 
					      link.download = result.fileName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.appendChild(link);
 | 
				
			||||||
 | 
					      link.click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      document.body.removeChild(link);
 | 
				
			||||||
 | 
					      window.URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  openNewPatientDialog() {
 | 
				
			||||||
 | 
					    this.patientDialogTitle = 'New Patient Record';
 | 
				
			||||||
 | 
					    this.resetselectpatient();
 | 
				
			||||||
 | 
					    this.patientDialog = true;
 | 
				
			||||||
 | 
					    this.isEditMode = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  editPatient(Patient: any) {
 | 
				
			||||||
 | 
					    this.resetselectpatient();
 | 
				
			||||||
 | 
					    this.patientDialogTitle = 'Edit Patient';
 | 
				
			||||||
 | 
					    this.patientService.getPatientRecordById(Patient.id).subscribe(result => {
 | 
				
			||||||
 | 
					      this.selectedPatientRecord = result;
 | 
				
			||||||
 | 
					      this.selectedPatientRecord.patientId = this.patientId;
 | 
				
			||||||
 | 
					      this.selectdateOfAdmission = new Date(this.selectedPatientRecord.dateOfAdmission);
 | 
				
			||||||
 | 
					      this.selectnextFollowUp = new Date(this.selectedPatientRecord.nextFollowUp);
 | 
				
			||||||
 | 
					      this.selectdischargeDate = new Date(this.selectedPatientRecord.dischargeDate);
 | 
				
			||||||
 | 
					      this.selectedstatus = this.selectedPatientRecord.status;
 | 
				
			||||||
 | 
					      this.selectedPatientRecord.doctorAssignedID = result.doctorAssigned.id;
 | 
				
			||||||
 | 
					      this.labReportUrlpath = result.labReportUrl != null ? result.labReportUrl.split('\\')[3] : '';
 | 
				
			||||||
 | 
					      this.medicationUrlpath =
 | 
				
			||||||
 | 
					        result.medicationUrl != null ? result.medicationUrl.split('\\')[3] : '';
 | 
				
			||||||
 | 
					      this.medicationHistoryUrlpath =
 | 
				
			||||||
 | 
					        result.medicationHistoryUrl != null ? result.medicationHistoryUrl.split('\\')[3] : '';
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.patientDialog = true;
 | 
				
			||||||
 | 
					    this.isEditMode = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deletePatient(id: any) {
 | 
				
			||||||
 | 
					    this.confirmation
 | 
				
			||||||
 | 
					      .warn('Do you really want to delete this record ?', {
 | 
				
			||||||
 | 
					        key: '::AreYouSure',
 | 
				
			||||||
 | 
					        defaultValue: 'Are you sure?',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .subscribe((status: Confirmation.Status) => {
 | 
				
			||||||
 | 
					        // your code here
 | 
				
			||||||
 | 
					        if (status == 'confirm') {
 | 
				
			||||||
 | 
					          this.patientService.deletePatientRecord(id).subscribe(() => {
 | 
				
			||||||
 | 
					            this.loadPatient(this.params, this.patientId);
 | 
				
			||||||
 | 
					            this.toaster.success('Patient deleted successfully', 'Success');
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleUpload(event: Event, tag: string): void {
 | 
				
			||||||
 | 
					    const input = event.target as HTMLInputElement;
 | 
				
			||||||
 | 
					    if (input.files.length > 0) {
 | 
				
			||||||
 | 
					      const formdata = new FormData();
 | 
				
			||||||
 | 
					      formdata.append('file', input.files[0]);
 | 
				
			||||||
 | 
					      this.UploadFileData(tag, formdata);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.uploadProgress1 = 0;
 | 
				
			||||||
 | 
					      this.uploadProgress2 = 0;
 | 
				
			||||||
 | 
					      this.uploadProgress3 = 0;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UploadFileData(tag: string, formdata: FormData) {
 | 
				
			||||||
 | 
					    const req = new HttpRequest(
 | 
				
			||||||
 | 
					      'POST',
 | 
				
			||||||
 | 
					      environment.apis.default.url + '/api/app/shared/upload-file',
 | 
				
			||||||
 | 
					      formdata,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        reportProgress: true,
 | 
				
			||||||
 | 
					        responseType: 'text',
 | 
				
			||||||
 | 
					        params: new HttpParams().set('tagName', tag),
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.http.request(req).subscribe(
 | 
				
			||||||
 | 
					      event => {
 | 
				
			||||||
 | 
					        if (event.type === HttpEventType.UploadProgress) {
 | 
				
			||||||
 | 
					          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.selectedPatientRecord.labReportUrlID = event.body.toString();
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            case 'Medication':
 | 
				
			||||||
 | 
					              this.uploadProgress2 = 100;
 | 
				
			||||||
 | 
					              this.selectedPatientRecord.medicationUrlID = event.body.toString();
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            case 'Medication-History':
 | 
				
			||||||
 | 
					              this.uploadProgress3 = 100;
 | 
				
			||||||
 | 
					              this.selectedPatientRecord.medicationHistoryUrlID = event.body.toString();
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      error => {
 | 
				
			||||||
 | 
					        this.uploadProgress1 = 100;
 | 
				
			||||||
 | 
					        this.uploadProgress2 = 100;
 | 
				
			||||||
 | 
					        this.uploadProgress3 = 100;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  savePatient(form: NgForm) {
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.patientId = this.patientId;
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.status = this.selectedPatientRecord.status;
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.dateOfAdmission = this.selectdateOfAdmission.toDateString();
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.nextFollowUp = this.selectnextFollowUp.toDateString();
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.dischargeDate = this.selectdischargeDate.toDateString();
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.status = this.selectedstatus;
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.labReportUrlID = this.selectedPatientRecord.labReportUrlID
 | 
				
			||||||
 | 
					      ? this.selectedPatientRecord.labReportUrlID.replace('"', '').replace('"', '')
 | 
				
			||||||
 | 
					      : this.guid;
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.medicationUrlID = this.selectedPatientRecord.medicationUrlID
 | 
				
			||||||
 | 
					      ? this.selectedPatientRecord.medicationUrlID.replace('"', '').replace('"', '')
 | 
				
			||||||
 | 
					      : this.guid;
 | 
				
			||||||
 | 
					    this.selectedPatientRecord.medicationHistoryUrlID = this.selectedPatientRecord
 | 
				
			||||||
 | 
					      .medicationHistoryUrlID
 | 
				
			||||||
 | 
					      ? this.selectedPatientRecord.medicationHistoryUrlID.replace('"', '').replace('"', '')
 | 
				
			||||||
 | 
					      : this.guid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.isEditMode) {
 | 
				
			||||||
 | 
					      this.patientService
 | 
				
			||||||
 | 
					        .updatePatientRecord(this.selectedPatientRecord.id, this.selectedPatientRecord)
 | 
				
			||||||
 | 
					        .subscribe(
 | 
				
			||||||
 | 
					          result => {
 | 
				
			||||||
 | 
					            this.toaster.success('Patient updated successfully', 'Success');
 | 
				
			||||||
 | 
					            this.patientDialog = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.loadPatient(
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                first: 0,
 | 
				
			||||||
 | 
					                rows: 10,
 | 
				
			||||||
 | 
					                sortField: 'id',
 | 
				
			||||||
 | 
					                sortOrder: 1,
 | 
				
			||||||
 | 
					                globalFilter: null,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              this.patientId
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          error => {
 | 
				
			||||||
 | 
					            this.closeDialog();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.patientService.createPatientRecord(this.selectedPatientRecord).subscribe(
 | 
				
			||||||
 | 
					        () => {
 | 
				
			||||||
 | 
					          this.toaster.success('Patient created successfully', 'Success');
 | 
				
			||||||
 | 
					          this.patientDialog = false;
 | 
				
			||||||
 | 
					          this.loadPatient(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              first: 0,
 | 
				
			||||||
 | 
					              rows: 10,
 | 
				
			||||||
 | 
					              sortField: 'id',
 | 
				
			||||||
 | 
					              sortOrder: 1,
 | 
				
			||||||
 | 
					              globalFilter: null,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            this.patientId
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        error => {
 | 
				
			||||||
 | 
					          this.closeDialog();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closeDialog() {
 | 
				
			||||||
 | 
					    this.patientDialog = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								angular/src/app/patients/patients-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								angular/src/app/patients/patients-routing.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { RouterModule, Routes } from '@angular/router';
 | 
				
			||||||
 | 
					import { AllPatientsComponent } from './all-patients/all-patients.component';
 | 
				
			||||||
 | 
					import { PatientRecordComponent } from './patient-record/patient-record.component';
 | 
				
			||||||
 | 
					import { authGuard, permissionGuard } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes: Routes = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: '',
 | 
				
			||||||
 | 
					    children: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        path: 'patient-record/:id',
 | 
				
			||||||
 | 
					        component: PatientRecordComponent,
 | 
				
			||||||
 | 
					        // canActivate: [authGuard, permissionGuard],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      { path: 'all-patients', component: AllPatientsComponent },
 | 
				
			||||||
 | 
					      // { path: 'create-new/:id', component: FaqCreateComponent },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  imports: [RouterModule.forChild(routes)],
 | 
				
			||||||
 | 
					  exports: [RouterModule],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class PatientsRoutingModule {}
 | 
				
			||||||
							
								
								
									
										37
									
								
								angular/src/app/patients/patients.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								angular/src/app/patients/patients.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PatientsRoutingModule } from './patients-routing.module';
 | 
				
			||||||
 | 
					import { AllPatientsComponent } from './all-patients/all-patients.component';
 | 
				
			||||||
 | 
					import { PatientRecordComponent } from './patient-record/patient-record.component';
 | 
				
			||||||
 | 
					import { TableModule } from 'primeng/table';
 | 
				
			||||||
 | 
					import { IconFieldModule } from 'primeng/iconfield';
 | 
				
			||||||
 | 
					import { InputIconModule } from 'primeng/inputicon';
 | 
				
			||||||
 | 
					import { FormsModule } from '@angular/forms';
 | 
				
			||||||
 | 
					import { InputTextModule } from 'primeng/inputtext';
 | 
				
			||||||
 | 
					import { PaginatorModule } from 'primeng/paginator';
 | 
				
			||||||
 | 
					import { DialogModule } from 'primeng/dialog';
 | 
				
			||||||
 | 
					import { DropdownModule } from 'primeng/dropdown';
 | 
				
			||||||
 | 
					import { FileUploadModule } from 'primeng/fileupload';
 | 
				
			||||||
 | 
					import { CalendarModule } from 'primeng/calendar';
 | 
				
			||||||
 | 
					import { SharedModule } from '../shared/shared.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					  declarations: [AllPatientsComponent, PatientRecordComponent],
 | 
				
			||||||
 | 
					  imports: [
 | 
				
			||||||
 | 
					    CommonModule,
 | 
				
			||||||
 | 
					    PatientsRoutingModule,
 | 
				
			||||||
 | 
					    TableModule,
 | 
				
			||||||
 | 
					    InputIconModule,
 | 
				
			||||||
 | 
					    IconFieldModule,
 | 
				
			||||||
 | 
					    FormsModule,
 | 
				
			||||||
 | 
					    InputTextModule,
 | 
				
			||||||
 | 
					    PaginatorModule,
 | 
				
			||||||
 | 
					    DialogModule,
 | 
				
			||||||
 | 
					    DropdownModule,
 | 
				
			||||||
 | 
					    FileUploadModule,
 | 
				
			||||||
 | 
					    CalendarModule,
 | 
				
			||||||
 | 
					    SharedModule
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class PatientsModule {}
 | 
				
			||||||
							
								
								
									
										17
									
								
								angular/src/app/proxy/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								angular/src/app/proxy/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# Proxy Generation Output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This directory includes the output of the latest proxy generation.
 | 
				
			||||||
 | 
					The files and folders in it will be overwritten when proxy generation is run again.
 | 
				
			||||||
 | 
					Therefore, please do not place your own content in this folder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, `generate-proxy.json` works like a lock file.
 | 
				
			||||||
 | 
					It includes information used by the proxy generator, so please do not delete or modify it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Finally, the name of the files and folders should not be changed for two reasons:
 | 
				
			||||||
 | 
					- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content.
 | 
				
			||||||
 | 
					- ABP Suite generates files which include imports from this folder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> **Important Notice:** If you are building a module and are planning to publish to npm,
 | 
				
			||||||
 | 
					> some of the generated proxies are likely to be exported from public-api.ts file. In such a case,
 | 
				
			||||||
 | 
					> please make sure you export files directly and not from barrel exports. In other words,
 | 
				
			||||||
 | 
					> do not include index.ts exports in your public-api.ts exports.
 | 
				
			||||||
							
								
								
									
										2
									
								
								angular/src/app/proxy/abp/application/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								angular/src/app/proxy/abp/application/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					import * as Services from './services';
 | 
				
			||||||
 | 
					export { Services };
 | 
				
			||||||
@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './models';
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ListResultDto<T> {
 | 
				
			||||||
 | 
					  items: T[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface PagedResultDto<T> extends ListResultDto<T> {
 | 
				
			||||||
 | 
					  totalCount: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								angular/src/app/proxy/abp/application/services/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								angular/src/app/proxy/abp/application/services/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					import * as Dto from './dto';
 | 
				
			||||||
 | 
					export { Dto };
 | 
				
			||||||
							
								
								
									
										2
									
								
								angular/src/app/proxy/abp/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								angular/src/app/proxy/abp/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					import * as Application from './application';
 | 
				
			||||||
 | 
					export { Application };
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/appoinments/dto/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/appoinments/dto/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './models';
 | 
				
			||||||
							
								
								
									
										46
									
								
								angular/src/app/proxy/appoinments/dto/models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								angular/src/app/proxy/appoinments/dto/models.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import type { Gender } from '../../global-enum/gender.enum';
 | 
				
			||||||
 | 
					import type { appointmentStatus } from '../../global-enum/appointment-status.enum';
 | 
				
			||||||
 | 
					import type { visitType } from '../../global-enum/visit-type.enum';
 | 
				
			||||||
 | 
					import type { paymentStatus } from '../../global-enum/payment-status.enum';
 | 
				
			||||||
 | 
					import type { DoctorDto } from '../../doctors/dto/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface AppointmentDto {
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					  firstName?: string;
 | 
				
			||||||
 | 
					  lastName?: string;
 | 
				
			||||||
 | 
					  gender: Gender;
 | 
				
			||||||
 | 
					  mobile?: string;
 | 
				
			||||||
 | 
					  address?: string;
 | 
				
			||||||
 | 
					  email?: string;
 | 
				
			||||||
 | 
					  dob?: string;
 | 
				
			||||||
 | 
					  doctorId?: string;
 | 
				
			||||||
 | 
					  dateOfAppointment?: string;
 | 
				
			||||||
 | 
					  timeOfAppointment?: string;
 | 
				
			||||||
 | 
					  injuryORContion?: string;
 | 
				
			||||||
 | 
					  note?: string;
 | 
				
			||||||
 | 
					  insuranceProvider?: string;
 | 
				
			||||||
 | 
					  appointmentStatus: appointmentStatus;
 | 
				
			||||||
 | 
					  visitType: visitType;
 | 
				
			||||||
 | 
					  paymentStatus: paymentStatus;
 | 
				
			||||||
 | 
					  doctor: DoctorDto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CreateOrUpdateAppointmentDto {
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					  firstName?: string;
 | 
				
			||||||
 | 
					  lastName?: string;
 | 
				
			||||||
 | 
					  gender: Gender;
 | 
				
			||||||
 | 
					  mobile?: string;
 | 
				
			||||||
 | 
					  address?: string;
 | 
				
			||||||
 | 
					  email?: string;
 | 
				
			||||||
 | 
					  dob?: string;
 | 
				
			||||||
 | 
					  doctorId?: string;
 | 
				
			||||||
 | 
					  dateOfAppointment?: string;
 | 
				
			||||||
 | 
					  timeOfAppointment?: string;
 | 
				
			||||||
 | 
					  injuryORContion?: string;
 | 
				
			||||||
 | 
					  note?: string;
 | 
				
			||||||
 | 
					  insuranceProvider?: string;
 | 
				
			||||||
 | 
					  appointmentStatus: appointmentStatus;
 | 
				
			||||||
 | 
					  visitType: visitType;
 | 
				
			||||||
 | 
					  paymentStatus: paymentStatus;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								angular/src/app/proxy/appoinments/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								angular/src/app/proxy/appoinments/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					import * as Dto from './dto';
 | 
				
			||||||
 | 
					export { Dto };
 | 
				
			||||||
							
								
								
									
										74
									
								
								angular/src/app/proxy/appointments/appointment.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								angular/src/app/proxy/appointments/appointment.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					import { RestService, Rest } from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import type { PagedResultDto } from '../abp/application/services/dto/models';
 | 
				
			||||||
 | 
					import type { AppointmentDto, CreateOrUpdateAppointmentDto } from '../appoinments/dto/models';
 | 
				
			||||||
 | 
					import type { FileDownloadDto, PagingSortResultDto } from '../dto/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Injectable({
 | 
				
			||||||
 | 
					  providedIn: 'root',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AppointmentService {
 | 
				
			||||||
 | 
					  apiName = 'Default';
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  createAppointment = (input: CreateOrUpdateAppointmentDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'POST',
 | 
				
			||||||
 | 
					      url: '/api/app/appointment/appointment',
 | 
				
			||||||
 | 
					      body: input,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteAppointmentRecord = (id: string, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'DELETE',
 | 
				
			||||||
 | 
					      url: `/api/app/appointment/${id}/appointment-record`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get = (config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, string>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      responseType: 'text',
 | 
				
			||||||
 | 
					      url: '/api/app/appointment',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getAppointmentById = (id: string, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, AppointmentDto>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: `/api/app/appointment/${id}/appointment-by-id`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getAppointmentList = (input: PagingSortResultDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, PagedResultDto<AppointmentDto>>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/appointment/appointment-list',
 | 
				
			||||||
 | 
					      params: { search: input.search, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getExportAppointmentRecord = (config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, FileDownloadDto>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/appointment/export-appointment-record',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  updateAppointment = (input: CreateOrUpdateAppointmentDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'PUT',
 | 
				
			||||||
 | 
					      url: '/api/app/appointment/appointment',
 | 
				
			||||||
 | 
					      body: input,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private restService: RestService) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/appointments/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/appointments/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './appointment.service';
 | 
				
			||||||
							
								
								
									
										65
									
								
								angular/src/app/proxy/departments/department.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								angular/src/app/proxy/departments/department.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					import { RestService, Rest } from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import type { PagedResultDto } from '../abp/application/services/dto/models';
 | 
				
			||||||
 | 
					import type { FileDownloadDto, PagingSortResultDto } from '../dto/models';
 | 
				
			||||||
 | 
					import type { CreateDepartmentDto, DepartmentDto } from '../dtos/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Injectable({
 | 
				
			||||||
 | 
					  providedIn: 'root',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DepartmentService {
 | 
				
			||||||
 | 
					  apiName = 'Default';
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  createDepartment = (input: CreateDepartmentDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'POST',
 | 
				
			||||||
 | 
					      url: '/api/app/department/department',
 | 
				
			||||||
 | 
					      body: input,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteDepartmentRecord = (id: string, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'DELETE',
 | 
				
			||||||
 | 
					      url: `/api/app/department/${id}/department-record`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getDepartmentById = (id: string, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, DepartmentDto>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: `/api/app/department/${id}/department-by-id`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getDepartmentList = (input: PagingSortResultDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, PagedResultDto<DepartmentDto>>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/department/department-list',
 | 
				
			||||||
 | 
					      params: { search: input.search, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getExportDepartmentRecord = (config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, FileDownloadDto>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/department/export-department-record',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  updateDepartment = (input: CreateDepartmentDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'PUT',
 | 
				
			||||||
 | 
					      url: '/api/app/department/department',
 | 
				
			||||||
 | 
					      body: input,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private restService: RestService) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/departments/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/departments/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './department.service';
 | 
				
			||||||
							
								
								
									
										74
									
								
								angular/src/app/proxy/doctors/doctor.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								angular/src/app/proxy/doctors/doctor.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					import type { DoctorDto } from './dto/models';
 | 
				
			||||||
 | 
					import { RestService, Rest } from '@abp/ng.core';
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import type { PagedResultDto } from '../abp/application/services/dto/models';
 | 
				
			||||||
 | 
					import type { FileDownloadDto, PagingSortResultDto } from '../dto/models';
 | 
				
			||||||
 | 
					import type { CreateDoctorDto } from '../dtos/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Injectable({
 | 
				
			||||||
 | 
					  providedIn: 'root',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class DoctorService {
 | 
				
			||||||
 | 
					  apiName = 'Default';
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  createDoctor = (input: CreateDoctorDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'POST',
 | 
				
			||||||
 | 
					      url: '/api/app/doctor/doctor',
 | 
				
			||||||
 | 
					      body: input,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteDoctorRecord = (id: string, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'DELETE',
 | 
				
			||||||
 | 
					      url: `/api/app/doctor/${id}/doctor-record`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get = (config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, DoctorDto[]>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/doctor',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getDoctorById = (id: string, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, DoctorDto>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: `/api/app/doctor/${id}/doctor-by-id`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getDoctorList = (input: PagingSortResultDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, PagedResultDto<DoctorDto>>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/doctor/doctor-list',
 | 
				
			||||||
 | 
					      params: { search: input.search, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getExportDoctorsRecord = (config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, FileDownloadDto>({
 | 
				
			||||||
 | 
					      method: 'GET',
 | 
				
			||||||
 | 
					      url: '/api/app/doctor/export-doctors-record',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  updatDoctor = (input: CreateDoctorDto, config?: Partial<Rest.Config>) =>
 | 
				
			||||||
 | 
					    this.restService.request<any, void>({
 | 
				
			||||||
 | 
					      method: 'POST',
 | 
				
			||||||
 | 
					      url: '/api/app/doctor/updat-doctor',
 | 
				
			||||||
 | 
					      body: input,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { apiName: this.apiName,...config });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private restService: RestService) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/doctors/dto/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/doctors/dto/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './models';
 | 
				
			||||||
							
								
								
									
										39
									
								
								angular/src/app/proxy/doctors/dto/models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								angular/src/app/proxy/doctors/dto/models.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import type { FullAuditedEntity } from '../../volo/abp/domain/entities/auditing/models';
 | 
				
			||||||
 | 
					import type { WorkSchedule } from '../../global-enum/work-schedule.enum';
 | 
				
			||||||
 | 
					import type { FullAuditedEntityDto } from '@abp/ng.core';
 | 
				
			||||||
 | 
					import type { TimeSlot } from '../../global-enum/time-slot.enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface DoctorDto extends FullAuditedEntity<string> {
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					  firstName?: string;
 | 
				
			||||||
 | 
					  lastName?: string;
 | 
				
			||||||
 | 
					  gender?: string;
 | 
				
			||||||
 | 
					  mobile?: string;
 | 
				
			||||||
 | 
					  designation?: string;
 | 
				
			||||||
 | 
					  departmentId?: string;
 | 
				
			||||||
 | 
					  address?: string;
 | 
				
			||||||
 | 
					  email?: string;
 | 
				
			||||||
 | 
					  dob?: string;
 | 
				
			||||||
 | 
					  education?: string;
 | 
				
			||||||
 | 
					  specialization?: string;
 | 
				
			||||||
 | 
					  degree?: string;
 | 
				
			||||||
 | 
					  joiningDate?: string;
 | 
				
			||||||
 | 
					  experience?: number;
 | 
				
			||||||
 | 
					  consultationFee?: number;
 | 
				
			||||||
 | 
					  availability: WorkSchedule[];
 | 
				
			||||||
 | 
					  rating?: number;
 | 
				
			||||||
 | 
					  clinicLocation?: string;
 | 
				
			||||||
 | 
					  shifts: ShiftManagementDto[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ShiftManagementDto extends FullAuditedEntityDto<string> {
 | 
				
			||||||
 | 
					  doctorId?: string;
 | 
				
			||||||
 | 
					  shifts: Record<WorkSchedule, TimeSlot>;
 | 
				
			||||||
 | 
					  isActive: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CreateUpdateShiftManagementDto {
 | 
				
			||||||
 | 
					  doctorId?: string;
 | 
				
			||||||
 | 
					  shifts: Record<WorkSchedule, TimeSlot>;
 | 
				
			||||||
 | 
					  isActive: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								angular/src/app/proxy/doctors/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								angular/src/app/proxy/doctors/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					import * as Dto from './dto';
 | 
				
			||||||
 | 
					export * from './doctor.service';
 | 
				
			||||||
 | 
					export { Dto };
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/documents/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/documents/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './models';
 | 
				
			||||||
							
								
								
									
										11
									
								
								angular/src/app/proxy/documents/models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								angular/src/app/proxy/documents/models.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import type { AuditedAggregateRoot } from '../volo/abp/domain/entities/auditing/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface EntityDocument extends AuditedAggregateRoot<string> {
 | 
				
			||||||
 | 
					  originalFileName?: string;
 | 
				
			||||||
 | 
					  generatedFileName?: string;
 | 
				
			||||||
 | 
					  fileSize?: string;
 | 
				
			||||||
 | 
					  filePath?: string;
 | 
				
			||||||
 | 
					  fileType?: string;
 | 
				
			||||||
 | 
					  tagName?: string;
 | 
				
			||||||
 | 
					  uploadDate?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/dto/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/dto/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './models';
 | 
				
			||||||
							
								
								
									
										15
									
								
								angular/src/app/proxy/dto/models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								angular/src/app/proxy/dto/models.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					import type { PagedAndSortedResultRequestDto } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface DropDownItems {
 | 
				
			||||||
 | 
					  label?: string;
 | 
				
			||||||
 | 
					  value: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface FileDownloadDto {
 | 
				
			||||||
 | 
					  fileName?: string;
 | 
				
			||||||
 | 
					  fileContent?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface PagingSortResultDto extends PagedAndSortedResultRequestDto {
 | 
				
			||||||
 | 
					  search?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								angular/src/app/proxy/dtos/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								angular/src/app/proxy/dtos/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from './models';
 | 
				
			||||||
							
								
								
									
										44
									
								
								angular/src/app/proxy/dtos/models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								angular/src/app/proxy/dtos/models.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import type { WorkSchedule } from '../global-enum/work-schedule.enum';
 | 
				
			||||||
 | 
					import type { FullAuditedEntity } from '../volo/abp/domain/entities/auditing/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CreateDepartmentDto {
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					  departmentNo?: string;
 | 
				
			||||||
 | 
					  departmentName?: string;
 | 
				
			||||||
 | 
					  departmentDate?: string;
 | 
				
			||||||
 | 
					  departmentHead?: string;
 | 
				
			||||||
 | 
					  description?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CreateDoctorDto {
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					  firstName?: string;
 | 
				
			||||||
 | 
					  lastName?: string;
 | 
				
			||||||
 | 
					  gender?: string;
 | 
				
			||||||
 | 
					  mobile?: string;
 | 
				
			||||||
 | 
					  password?: string;
 | 
				
			||||||
 | 
					  designation?: string;
 | 
				
			||||||
 | 
					  departmentId?: string;
 | 
				
			||||||
 | 
					  address?: string;
 | 
				
			||||||
 | 
					  email?: string;
 | 
				
			||||||
 | 
					  dob?: string;
 | 
				
			||||||
 | 
					  education?: string;
 | 
				
			||||||
 | 
					  specialization?: string;
 | 
				
			||||||
 | 
					  degree?: string;
 | 
				
			||||||
 | 
					  joiningDate?: string;
 | 
				
			||||||
 | 
					  experience?: number;
 | 
				
			||||||
 | 
					  consultationFee?: number;
 | 
				
			||||||
 | 
					  availability: WorkSchedule[];
 | 
				
			||||||
 | 
					  rating?: number;
 | 
				
			||||||
 | 
					  clinicLocation?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface DepartmentDto extends FullAuditedEntity<string> {
 | 
				
			||||||
 | 
					  departmentNo?: string;
 | 
				
			||||||
 | 
					  departmentName?: string;
 | 
				
			||||||
 | 
					  departmentDate?: string;
 | 
				
			||||||
 | 
					  departmentHead?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  description?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13473
									
								
								angular/src/app/proxy/generate-proxy.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13473
									
								
								angular/src/app/proxy/generate-proxy.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { mapEnumToOptions } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum appointmentStatus {
 | 
				
			||||||
 | 
					  Scheduled = 1,
 | 
				
			||||||
 | 
					  Completed = 2,
 | 
				
			||||||
 | 
					  Canceled = 3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const appointmentStatusOptions = mapEnumToOptions(appointmentStatus);
 | 
				
			||||||
							
								
								
									
										8
									
								
								angular/src/app/proxy/global-enum/gender.enum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								angular/src/app/proxy/global-enum/gender.enum.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import { mapEnumToOptions } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum Gender {
 | 
				
			||||||
 | 
					  Male = 1,
 | 
				
			||||||
 | 
					  Female = 2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const genderOptions = mapEnumToOptions(Gender);
 | 
				
			||||||
							
								
								
									
										7
									
								
								angular/src/app/proxy/global-enum/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								angular/src/app/proxy/global-enum/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					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';
 | 
				
			||||||
							
								
								
									
										9
									
								
								angular/src/app/proxy/global-enum/payment-status.enum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								angular/src/app/proxy/global-enum/payment-status.enum.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { mapEnumToOptions } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum paymentStatus {
 | 
				
			||||||
 | 
					  Paid = 1,
 | 
				
			||||||
 | 
					  Pending = 2,
 | 
				
			||||||
 | 
					  Unpaid = 3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const paymentStatusOptions = mapEnumToOptions(paymentStatus);
 | 
				
			||||||
							
								
								
									
										9
									
								
								angular/src/app/proxy/global-enum/status.enum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								angular/src/app/proxy/global-enum/status.enum.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { mapEnumToOptions } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum Status {
 | 
				
			||||||
 | 
					  Recovered = 1,
 | 
				
			||||||
 | 
					  Observation = 2,
 | 
				
			||||||
 | 
					  InTreatment = 3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const statusOptions = mapEnumToOptions(Status);
 | 
				
			||||||
							
								
								
									
										14
									
								
								angular/src/app/proxy/global-enum/time-slot.enum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								angular/src/app/proxy/global-enum/time-slot.enum.ts
									
									
									
									
									
										Normal file
									
								
							@ -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);
 | 
				
			||||||
							
								
								
									
										8
									
								
								angular/src/app/proxy/global-enum/visit-type.enum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								angular/src/app/proxy/global-enum/visit-type.enum.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import { mapEnumToOptions } from '@abp/ng.core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum visitType {
 | 
				
			||||||
 | 
					  NewPatient = 1,
 | 
				
			||||||
 | 
					  Followup = 2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const visitTypeOptions = mapEnumToOptions(visitType);
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user