diff --git a/src/app/services/user-setup.service.ts b/src/app/services/user-setup.service.ts index 99c0faa..3ee7018 100644 --- a/src/app/services/user-setup.service.ts +++ b/src/app/services/user-setup.service.ts @@ -4,6 +4,7 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { URIKey } from '../utils/uri-enums'; import { URIService } from '../app.uri'; import { HttpURIService } from '../app.http.uri.service'; +import { HttpParams } from '@angular/common/http'; @Injectable({ providedIn: 'root' @@ -12,15 +13,11 @@ export class UserSetupService { private usersSubject = new BehaviorSubject([]); private currentPageSubject = new BehaviorSubject(1); private totalCountSubject = new BehaviorSubject(0); - private searchTextSubject = new BehaviorSubject(''); private itemsPerPageSubject = new BehaviorSubject(5); - private paginatedUsersSubject = new BehaviorSubject([]); users$ = this.usersSubject.asObservable(); currentPage$ = this.currentPageSubject.asObservable(); totalCount$ = this.totalCountSubject.asObservable(); - searchText$ = this.searchTextSubject.asObservable(); itemsPerPage$ = this.itemsPerPageSubject.asObservable(); - paginatedUsers$ = this.paginatedUsersSubject.asObservable(); constructor(private httpURIService: HttpURIService, private uriService: URIService) { } @@ -34,7 +31,7 @@ loadUsers(): void { const users = Array.isArray(res) ? res : res?.data; this.usersSubject.next(users ?? []); this.totalCountSubject.next(users.length); - this.applyPagination(); + }, error: (err) => console.error(err) }); @@ -42,36 +39,10 @@ loadUsers(): void { }); } - private applyPagination(): void { - const allUsers = this.usersSubject.value; - const searchText = this.searchTextSubject.value.toLowerCase(); - const currentPage = this.currentPageSubject.value; - const itemsPerPage = this.itemsPerPageSubject.value; - - let filtered = allUsers.filter(user => - user.userId.toLowerCase().includes(searchText) || - user.userFullname.toLowerCase().includes(searchText) || - user.email.toLowerCase().includes(searchText) - ); - - const totalCount = filtered.length; - const startIndex = (currentPage - 1) * itemsPerPage; - const paginatedUsers = filtered.slice(startIndex, startIndex + itemsPerPage); - - this.paginatedUsersSubject.next(paginatedUsers); - this.totalCountSubject.next(totalCount); - } - - setSearchText(searchText: string): void { - this.searchTextSubject.next(searchText); - this.currentPageSubject.next(1); - this.applyPagination(); - } - setItemsPerPage(itemsPerPage: number): void { this.itemsPerPageSubject.next(itemsPerPage); this.currentPageSubject.next(1); - this.applyPagination(); + } nextPage(): void { @@ -79,7 +50,6 @@ loadUsers(): void { const currentPage = this.currentPageSubject.value; if (currentPage < totalPages) { this.currentPageSubject.next(currentPage + 1); - this.applyPagination(); } } @@ -87,7 +57,7 @@ loadUsers(): void { const currentPage = this.currentPageSubject.value; if (currentPage > 1) { this.currentPageSubject.next(currentPage - 1); - this.applyPagination(); + } } @@ -95,7 +65,7 @@ loadUsers(): void { const totalPages = this.getTotalPages(); if (page > 0 && page <= totalPages) { this.currentPageSubject.next(page); - this.applyPagination(); + } } @@ -109,4 +79,17 @@ loadUsers(): void { return this.httpURIService.requestPOST(URIKey.CREATE_USER, payload); } + +getUserById(userId: any){ + const params = new HttpParams().set('userId', userId) + + return this.httpURIService.requestGET(URIKey.GET_USER_BY_ID, params); +} + +deleteUser(userId: any){ + const params = new HttpParams().set('userId', userId) + console.log("params success",params) + return this.httpURIService.requestDELETE(URIKey.DELETE_USER, params) +} + } \ No newline at end of file diff --git a/src/app/shared/pipes/userFilterPipe.ts b/src/app/shared/pipes/userFilterPipe.ts new file mode 100644 index 0000000..7bb23cd --- /dev/null +++ b/src/app/shared/pipes/userFilterPipe.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { SetupUser } from '../../models/user'; + +@Pipe({ + name: 'userFilter', + standalone: true +}) +export class UserFilterPipe implements PipeTransform { + transform(users: SetupUser[], searchText: string): SetupUser[] { + if (!users || !searchText.trim()) { + return users; + } + + const search = searchText.toLowerCase(); + + return users.filter(user => + user.userId.toLowerCase().includes(search) || + user.userFullname.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); + } +} \ No newline at end of file diff --git a/src/app/user-management/change-password/change-password.component.html b/src/app/user-management/change-password/change-password.component.html index a194aec..644826d 100644 --- a/src/app/user-management/change-password/change-password.component.html +++ b/src/app/user-management/change-password/change-password.component.html @@ -88,7 +88,7 @@
-
+
@@ -100,14 +100,16 @@
- +
+ {{ 'fieldRequired' | translate }} +
@@ -122,6 +124,7 @@ +
+ {{ newPasswordError$ | translate }} +
@@ -145,6 +151,7 @@ +
+ {{ confirmPasswordError$ | translate }} +
@@ -163,7 +173,8 @@
diff --git a/src/app/user-management/change-password/change-password.component.ts b/src/app/user-management/change-password/change-password.component.ts index fb7f0bd..423cdd4 100644 --- a/src/app/user-management/change-password/change-password.component.ts +++ b/src/app/user-management/change-password/change-password.component.ts @@ -1,10 +1,10 @@ import { CommonModule } from '@angular/common'; -import { Component, ViewChild } from '@angular/core'; -import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { AbstractControl, FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; import { PasswordHideShowComponent } from '../../shared/components/password-hide-show/password-hide-show.component'; -import { StorageService } from '../../shared/services/storage.service'; -import { Router } from '@angular/router'; +import { HttpURIService } from '../../app.http.uri.service'; +import { URIKey } from '../../utils/uri-enums'; @Component({ selector: 'app-change-password', @@ -13,15 +13,12 @@ import { Router } from '@angular/router'; styleUrl: './change-password.component.scss' }) -export class ChangePasswordComponent{ +export class ChangePasswordComponent implements OnInit{ isFirstLogin = false; - loginForm!: FormGroup; + changePasswordForm!: FormGroup; currentLanguage = new FormControl(); httpService: any; - constructor(private storageService: StorageService, private router: Router){} -onLangChange() { -throw new Error('Method not implemented.'); -} + passwordType: string = 'password'; passwordType1: string = 'password'; passwordType2: string = 'password'; @@ -29,6 +26,7 @@ passwordType2: string = 'password'; @ViewChild('psh') passwordHideShow?: PasswordHideShowComponent; @ViewChild('psh1') passwordHideShow1 ?: PasswordHideShowComponent; @ViewChild('psh2') passwordHideShow2 ?: PasswordHideShowComponent; +constructor(private fb: FormBuilder, private httpURIService: HttpURIService){} togglePasswordType() { this.passwordType = this.passwordHideShow?.showPassword ? 'password' : 'text'; @@ -40,31 +38,53 @@ passwordType2: string = 'password'; this.passwordType2 = this.passwordHideShow2?.showPassword ? 'password' : 'text'; } - ngOnInit(): void { - // Call the method to check if first-time login - this.checkIfFirstTimeChangePasswordOrNot(); + passwordMatchValidator(group: AbstractControl): ValidationErrors | null { + const newPassword = group.get('enterNewPassword')?.value; + const confirmPassword = group.get('confirmPassword')?.value; + return newPassword === confirmPassword ? null : { passwordMismatch: true }; + } + + ngOnInit(): void { + this.changePasswordForm = this.fb.group({ + oldPassword: ['', Validators.required], + enterNewPassword: ['',[ Validators.required, Validators.minLength(6)]], + confirmPassword: ['', [Validators.required, Validators.minLength(6)]] + }, + { + validators: this.passwordMatchValidator + } + ) + } + get newPasswordError$() { + const control = this.changePasswordForm.get('newPassword'); + if (!control || !control.touched) return null; + + if (control.hasError('required')) return 'fieldRequired'; + if (control.hasError('minlength')) return 'passwordTooShort'; + return null; + } + + get confirmPasswordError$() { + const control = this.changePasswordForm.get('confirmPassword'); + if (!control || !control.touched) return null; + + if (control.hasError('required')) return 'fieldRequired'; + if (control.hasError('minlength')) return 'passwordTooShort'; + if (this.changePasswordForm.hasError('passwordMismatch')) return 'passwordsDoNotMatch'; + + return null; } - checkIfFirstTimeChangePasswordOrNot() { - const fromMenu = history.state?.['fromMenu']; + onSubmit(){ + if(this.changePasswordForm.invalid){return} - if (fromMenu) { - this.isFirstLogin = false; - } else { - try { - const currentUser: any = JSON.parse(this.storageService.getItem('user') || '{}'); - - // Check if user exists and has isFirstLogin flag - if (currentUser?.user?.isFirstLogin) { - this.isFirstLogin = true; - } else { - this.isFirstLogin = false; - } - } catch (error) { - console.error('Error parsing user data:', error); - this.isFirstLogin = false; - } + const payload = { + oldPassword: this.changePasswordForm.value.oldPassword, + newPassword: this.changePasswordForm.value.enterNewPassword } + + this.httpURIService.requestPOST(URIKey.CHANGE_PASSWORD_URI, payload) + .subscribe(); } } diff --git a/src/app/user-management/reset-password/reset-password.component.html b/src/app/user-management/reset-password/reset-password.component.html index 077c8bc..0c3ccaf 100644 --- a/src/app/user-management/reset-password/reset-password.component.html +++ b/src/app/user-management/reset-password/reset-password.component.html @@ -22,27 +22,30 @@ {{'resetPassword' | translate}}
- +
-
@@ -53,9 +56,10 @@ {{ 'enterNewPassword' | translate }}* -
- +
+
- + +
+
+ {{ newPasswordError | translate }}
- +
@@ -77,22 +84,20 @@ {{ 'confirmPassword' | translate }}* -
+
+
- +
+
+ {{ confirmPasswordError | translate }} +
+
@@ -103,14 +108,12 @@
-
-
- - +
diff --git a/src/app/user-management/reset-password/reset-password.component.ts b/src/app/user-management/reset-password/reset-password.component.ts index a0272d2..c810314 100644 --- a/src/app/user-management/reset-password/reset-password.component.ts +++ b/src/app/user-management/reset-password/reset-password.component.ts @@ -1,26 +1,88 @@ -import { Component, ViewChild } from '@angular/core'; +import { Component, ViewChild, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators, AbstractControl, ValidationErrors, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; +import { CommonModule } from '@angular/common'; import { PasswordHideShowComponent } from '../../shared/components/password-hide-show/password-hide-show.component'; +import { URIKey } from '../../utils/uri-enums'; +import { HttpURIService } from '../../app.http.uri.service'; @Component({ selector: 'app-reset-password', - imports: [TranslateModule, PasswordHideShowComponent], + imports: [TranslateModule, PasswordHideShowComponent, CommonModule, ReactiveFormsModule], templateUrl: './reset-password.component.html', styleUrl: './reset-password.component.scss' }) -export class ResetPasswordComponent { -passwordType1: string = 'password'; -passwordType2: string = 'password'; +export class ResetPasswordComponent implements OnInit{ + resetPasswordForm!: FormGroup + passwordType1: string = 'password'; + passwordType2: string = 'password'; + @ViewChild('psh1') passwordHideShow1?: PasswordHideShowComponent; + @ViewChild('psh2') passwordHideShow2?: PasswordHideShowComponent; + + constructor(private fb: FormBuilder, private httpURIService: HttpURIService){} -@ViewChild('psh1') passwordHideShow1 ?: PasswordHideShowComponent; -@ViewChild('psh2') passwordHideShow2 ?: PasswordHideShowComponent; - + ngOnInit(): void { + this.resetPasswordForm = this.fb.group({ + userId: ['', Validators.required], + newPassword: ['', [Validators.required, Validators.minLength(6)]], + confirmPassword: ['', [Validators.required, Validators.minLength(6)]] + }, + { + validators: this.passwordMatchValidator + } + ); + this.resetPasswordForm.get('newPassword')?.valueChanges.subscribe(()=>{ + this.resetPasswordForm.get('confirmPassword')?.updateValueAndValidity(); + }); + + } togglePasswordType1() { this.passwordType1 = this.passwordHideShow1?.showPassword ? 'password' : 'text'; } - togglePasswordType2() { + togglePasswordType2() { this.passwordType2 = this.passwordHideShow2?.showPassword ? 'password' : 'text'; } + passwordMatchValidator(group: AbstractControl): ValidationErrors | null { + const newPassword = group.get('newPassword')?.value; + const confirmPassword = group.get('confirmPassword')?.value; + + return newPassword === confirmPassword ? null : { passwordMismatch: true }; + } + + get newPasswordError() { + const control = this.resetPasswordForm.get('newPassword'); + if (!control || !control.touched) return null; + + if (control.hasError('required')) return 'fieldRequired'; + if (control.hasError('minlength')) return 'passwordTooShort'; + return null; + } + + get confirmPasswordError() { + const control = this.resetPasswordForm.get('confirmPassword'); + if (!control || !control.touched) return null; + + if (control.hasError('required')) return 'fieldRequired'; + if (control.hasError('minlength')) return 'passwordTooShort'; + if (this.resetPasswordForm.hasError('passwordMismatch')) return 'passwordsDoNotMatch'; + + return null; + } + + onSubmit() { + if (this.resetPasswordForm.invalid) return; + + const payload = { + userId: this.resetPasswordForm.value.userId, + newPassword: this.resetPasswordForm.value.newPassword + }; + this.httpURIService.requestPOST(URIKey.RESET_PASSWORD_URI, payload) + .subscribe(); + + } + + } + diff --git a/src/app/user-management/setup-user/setup-user.component.html b/src/app/user-management/setup-user/setup-user.component.html index 1522bbf..f8a8a14 100644 --- a/src/app/user-management/setup-user/setup-user.component.html +++ b/src/app/user-management/setup-user/setup-user.component.html @@ -22,7 +22,7 @@ {{'setupUser' | translate}}
-
+
@@ -34,15 +34,15 @@
- -
- +
+ +
+ {{ 'fieldRequired' | translate }} +
@@ -57,15 +57,18 @@ - +
+ {{ 'fieldRequired' | translate }} +
+ @@ -80,19 +83,15 @@
- +
+ {{ 'fieldRequired' | translate }} +
+
@@ -101,12 +100,11 @@
- - + +
@@ -138,7 +136,7 @@ @@ -157,13 +155,19 @@ - - - + + + - + + @@ -171,21 +175,18 @@ +
{{'userID' | translate}}{{'Name' | translate}}{{'action' | translate}}{{'userID' | translate}}{{'Name' | translate}}{{'action' | translate}}
{{ item.userId }} {{ item.userFullname }}
- - - - - +
@@ -203,7 +204,7 @@
- {{ 'page' | translate }} {{ currentPage }} {{ 'of' | translate }} {{ totalPages() }} ({{ totalCount }} {{ 'totalItems' | translate }}) + {{ 'page' | translate }} {{ currentPage }} {{ 'of' | translate }} {{ getTotalPages() }} ({{ totalCount }} {{ 'totalItems' | translate }})
diff --git a/src/app/user-management/setup-user/setup-user.component.ts b/src/app/user-management/setup-user/setup-user.component.ts index b7e6dcc..01b3097 100644 --- a/src/app/user-management/setup-user/setup-user.component.ts +++ b/src/app/user-management/setup-user/setup-user.component.ts @@ -6,15 +6,24 @@ import { TranslateModule } from '@ngx-translate/core'; import { pageSizeOptions } from '../../utils/app.constants'; import { SetupUser } from '../../models/user'; import { UserSetupService } from '../../services/user-setup.service'; +import { UserFilterPipe } from '../../shared/pipes/userFilterPipe'; +import { FormBuilder, Validators, FormGroup } from '@angular/forms'; + @Component({ selector: 'app-setup-user', standalone: true, - imports: [TranslateModule, ReactiveFormsModule, FormsModule, CommonModule, NgSelectModule], + imports: [TranslateModule, ReactiveFormsModule, FormsModule, CommonModule, NgSelectModule, UserFilterPipe], templateUrl: './setup-user.component.html', styleUrl: './setup-user.component.scss' }) export class SetupUserComponent implements OnInit { + + userForm!: FormGroup; + showForm = false; + selectedUserId!: any; + showDeleteModal = false; + userIdToDelete: any = null; allItems: SetupUser[] = []; currentPage: number = 1; pageSizeOptions = pageSizeOptions @@ -22,13 +31,16 @@ export class SetupUserComponent implements OnInit { searchText: string = ''; renewalDataExpanded: boolean = true; totalCount: number = 0; - userId!: string; - userFullname!: string; - defaultPassword!: string; - constructor(private userService: UserSetupService){} + mode: 'edit' | 'view' = 'view'; + + constructor(private userService: UserSetupService, private fb: FormBuilder){} + + get users$(){ + return this.userService.users$; + } onSearch(value: string): void { - this.userService.setSearchText(value); + this.searchText = value; } onPageSizeChange(pageSize: number): void { @@ -42,52 +54,83 @@ export class SetupUserComponent implements OnInit { previousPage(): void { this.userService.previousPage(); } - - totalPages() { - return 1; - } - toggleCard(arg0: string) { - throw new Error('Method not implemented.'); + + getTotalPages(): number { + return this.userService.getTotalPages(); } - onSubmit() { - if(!this.userId || !this.userFullname|| !this.defaultPassword){ - console.warn('Form incomplete'); - return - } + if (this.userForm.invalid) { + this.userForm.markAllAsTouched(); + return; +} const newUser : SetupUser = { - userId: this.userId, - userFullname: this.userFullname, - email: `${this.userId}@dummy.com` ,// temporary placeholder + userId: this.userForm.value.userId, + userFullname: this.userForm.value.userFullname, + email: `${this.userForm.value.userId}@dummy.com`, role: 'ADMIN', - defaultPassword: this.defaultPassword + defaultPassword: this.userForm.value.defaultPassword } this.userService.addUser(newUser).subscribe({ next: () => { this.userService.loadUsers(); - this.userId = ''; - this.userFullname = ''; - this.defaultPassword = ''; + this.userService.loadUsers(); + this.userForm.reset(); + this.mode = 'edit'; }, error: (err: any) => console.error(err) }); + + + + } + onView(userId: any){ + this.mode = 'view'; + this.showForm = true; + this.selectedUserId = userId; + this.userService.getUserById(userId).subscribe((user: any)=>{ + this.userForm.patchValue({ + userId : user.userId, + userFullname : user.userFullname, + defaultPassword : '', + }) + }) + } + + onDelete(userId: any){ + this.userService.deleteUser(userId).subscribe({ + next: (res: any) => { + this.userService.loadUsers(); + this.userForm.reset() + this.selectedUserId = null; + }, + error: (err:any) =>{ + console.log('user not deleted') + } + + }); + } ngOnInit(): void { + this.userForm = this.fb.group({ + userId: ['', [Validators.required]], + userFullname: ['', [Validators.required, Validators.maxLength(500)]], + defaultPassword: ['', Validators.required] + }); + this.userService.loadUsers(); - this.userService.paginatedUsers$.subscribe((users: SetupUser[]) => this.allItems = users); + this.userService.users$.subscribe((users: SetupUser[]) => { + this.allItems = users; + }); this.userService.currentPage$.subscribe((page: number) => { this.currentPage = page; }); this.userService.totalCount$.subscribe((count: number) => { this.totalCount = count; }); - this.userService.searchText$.subscribe((text: string) => { - this.searchText = text; - }); this.userService.itemsPerPage$.subscribe((size: number) => { this.itemsPerPage = size; }); diff --git a/src/app/user-permissions/user-permissions.component.html b/src/app/user-permissions/user-permissions.component.html index 192cae2..6ae4102 100644 --- a/src/app/user-permissions/user-permissions.component.html +++ b/src/app/user-permissions/user-permissions.component.html @@ -1 +1,95 @@ -

user-permissions works!

+
+
+
+
+
+
+
{{'permissionManagement' | translate}}
+
+
+
+
+ + +
+ +
+ +
+ +
+ + +
+
+
+
+

{{ 'permissions' | translate}}

+
+
    +
  • + + {{node.name | translate}} + + + + + + +
      + +
    +
      + +
    +
  • +
+ + +
    +
  • + + {{node.name | translate}} + + + + + + + + + + +
      + +
    +
      + +
    +
  • +
+
+
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/app/user-permissions/user-permissions.component.scss b/src/app/user-permissions/user-permissions.component.scss index e69de29..6d0f995 100644 --- a/src/app/user-permissions/user-permissions.component.scss +++ b/src/app/user-permissions/user-permissions.component.scss @@ -0,0 +1,19 @@ + + li { + margin: 5px 0; + } + + ul { + list-style-type: none; + margin: 0; + padding-left: 10px; /* Reduce overall left padding */ + } + + ul ul { + padding-left: 5px; /* Reduce space for nested items */ + margin-left: 5px; + } + + li { + margin-bottom: 3px; /* Add slight vertical spacing between items */ + } \ No newline at end of file diff --git a/src/app/user-permissions/user-permissions.component.ts b/src/app/user-permissions/user-permissions.component.ts index 3f37b2f..025ae98 100644 --- a/src/app/user-permissions/user-permissions.component.ts +++ b/src/app/user-permissions/user-permissions.component.ts @@ -1,11 +1,180 @@ import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { PermissionNode } from '../utils/app.constants'; +import { Observable } from 'rxjs'; +import { CredentialService } from '../services/credential.service'; +import { I18NService } from '../services/i18n.service'; +import { HttpURIService } from '../app.http.uri.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { URIKey } from '../utils/uri-enums'; +import { HttpErrorResponse, HttpParams } from '@angular/common/http'; +import { FormConstants, HiddenValues, SuccessMessages } from '../utils/enums'; +import { CommonModule } from '@angular/common'; @Component({ selector: 'app-user-permissions', - imports: [], + imports: [TranslateModule, ReactiveFormsModule, CommonModule], templateUrl: './user-permissions.component.html', styleUrl: './user-permissions.component.scss' }) export class UserPermissionsComponent { + dropdownOptions: { [key: string]: any[] } = {}; + users: any[] = []; + permission: FormGroup; + showPermissions = false; + permissions: PermissionNode[] = []; + constructor(private credentialService: CredentialService, private fb: FormBuilder, private httpService: HttpURIService, private i18nService: I18NService) { + this.permission = this.fb.group({ + allocation: [''], + userCode: [''], + userRole: [''], + }); + + this.defaultPermissions().subscribe((data: PermissionNode[]) => { + this.permissions = data; + }); + } + + ngOnInit(){ + this.getAllUsers(); + } + + defaultPermissions(): Observable { + return this.httpService.requestGET('assets/data/sideMenu.json'); + } + + toggleNode(node: PermissionNode, event: Event): void { + node.checked = (event.target as HTMLInputElement).checked; + if (node.children) { + this.toggleChildren(node.children, node.checked); + } + if (node.buttons) { + this.toggleButtons(node.buttons, node.checked); + } + this.updateParentState(node); + } + + toggleChildren(children: PermissionNode[], isChecked: boolean): void { + children.forEach(child => { + child.checked = isChecked; + if (child.children) { + this.toggleChildren(child.children, isChecked); + } + if (child.buttons) { + this.toggleButtons(child.buttons, child.checked); + } + }); + } + + toggleButtons(buttons: PermissionNode[], isChecked: boolean): void { + buttons.forEach(button => { + button.checked = isChecked; + }); + } + + updateParentState(node: PermissionNode): void { + const parent = this.findParent(node, this.permissions); + if (parent) { + parent.checked = parent.children?.some(child => child.checked) || false; + this.updateParentState(parent); // Recursively update ancestors + } + } + + findParent(target: PermissionNode, nodes: PermissionNode[]): PermissionNode | null { + for (let node of nodes) { + if (node.children?.includes(target)) { + return node; + } + if (node.children) { + const parent = this.findParent(target, node.children); + if (parent) return parent; + } + } + return null; + } + + toggleExpand(node: PermissionNode): void { + node.expanded = !node.expanded; + } + populateDropdowns(data: any) { + data.forEach((control: any) => { + this.dropdownOptions[control.controlId] = control.options; + }); + } + + onAllocationChange(event: Event): void { + this.showPermissions = false; + const selectedValue = (event.target as HTMLInputElement).value; + if (selectedValue === "R") { + this.permission.get('userCode')?.reset(); + } + else if (selectedValue === "U") { + this.permission.get('userRole')?.reset(); + } + } + + getAllUsers() { + this.httpService.requestGET(URIKey.GET_ALL_USER_URI).subscribe((response) => { + if (!(response instanceof HttpErrorResponse)) { + this.users = response.map(item => ({ + userName: item.userFullname, + userId: item.userId, + })); + } + }); + } + + onUserChange() { + this.showPermissions = true; + const params = new HttpParams().set('userId', this.permission.get('userCode')?.value); + this.httpService.requestGET(URIKey.USER_GET_PERMISSIONS, params).subscribe((response: any) => { + if (!(response instanceof HttpErrorResponse)) { + if (response.permissions) { + this.updatePermissions(JSON.parse(response.permissions), this.permissions); + } + else { + this.defaultPermissions().subscribe((data: PermissionNode[]) => { + this.permissions = data; + }); + } + } + }) + } + + savePermissions() { + let payload = { + // porOrgacode: this.credentialService.getPorOrgacode(), + userId: this.permission.get('userCode')?.value, + permissions: JSON.stringify(this.permissions) + } + this.httpService.requestPUT(URIKey.USER_SAVE_PERMISSION, payload).subscribe((response: any) => { + if (!(response instanceof HttpErrorResponse)) { + this.i18nService.success(SuccessMessages.SAVED_SUCESSFULLY, []); + this.permission.reset(); + this.permission.get('userCode')?.setValue(""); + this.showPermissions = false; + } + }) + } + + updatePermissions(savedPermissions: PermissionNode[], existingPermissions: PermissionNode[]): void { + for (const existingNode of existingPermissions) { + const savedNode = savedPermissions.find(node => node.name === existingNode.name); + + if (savedNode) { + // Update state from saved node + existingNode.checked = savedNode.checked; + //existingNode.expanded = savedNode.expanded; + + // Recursively update children if they exist + if (existingNode.children) { + this.updatePermissions(savedNode.children || [], existingNode.children); + } + if (existingNode.buttons) { + this.updatePermissions(savedNode.buttons || [], existingNode.buttons); + } + } + } + } } diff --git a/src/app/utils/uri-enums.ts b/src/app/utils/uri-enums.ts index 650cf52..2d1957c 100644 --- a/src/app/utils/uri-enums.ts +++ b/src/app/utils/uri-enums.ts @@ -3,5 +3,12 @@ export enum URIKey { USER_LOGIN_URI = "USER_LOGIN_URI", USER_REFRESH_TOKEN = "USER_REFRESH_TOKEN", CREATE_USER = 'CREATE_USER', - GET_ALL_USERS = 'GET_ALL_USERS' + GET_ALL_USERS = 'GET_ALL_USERS', + GET_USER_BY_ID = 'GET_USER_BY_ID', + DELETE_USER = 'DELETE_USER', + USER_SAVE_PERMISSION = "USER_SAVE_PERMISSION", + USER_GET_PERMISSIONS = "USER_GET_PERMISSIONS", + GET_ALL_USER_URI = "GET_ALL_USER_URI", + RESET_PASSWORD_URI = "RESET_PASSWORD_URI", + CHANGE_PASSWORD_URI = "CHANGE_PASSWORD_URI" } \ No newline at end of file diff --git a/src/assets/data/app.uri.json b/src/assets/data/app.uri.json index f7fd2dd..6dbded8 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -17,6 +17,11 @@ "URI": "/refreshtoken", "UUID": "USER_REFRESH_TOKEN" }, + { + "Id": "ENTITY_GET_ALL_USER_URI", + "URI": "/user/getAllUsers", + "UUID": "GET_ALL_USER_URI" + }, { "Id": "ENTITY_CREATE_USER", "URI": "/user/createUser", @@ -26,6 +31,31 @@ "Id": "ENTITY_GET_ALL_USERS", "URI": "/user/getAllUsers", "UUID": "GET_ALL_USERS" + }, + { + "Id" : "ENTITY_GET_USER_BY_ID", + "URI": "/user/getUser", + "UUID": "GET_USER_BY_ID" + }, + { + "Id" : "ENTITY_DELETE_USER", + "URI": "/user/deleteUser", + "UUID": "DELETE_USER" + }, + { + "Id" : "ENTITY_USER_GET_PERMISSIONS", + "URI": "/user/getPermissions", + "UUID": "USER_GET_PERMISSIONS" + }, + { + "Id" : "ENTITY_RESET_PASSWORD_URI", + "URI": "/user/reset-password", + "UUID": "RESET_PASSWORD_URI" + }, + { + "Id" : "ENTITY_CHANGE_PASSWORD_URI", + "URI": "/user/change-password", + "UUID": "CHANGE_PASSWORD_URI" } ] } diff --git a/src/assets/data/sideMenu.json b/src/assets/data/sideMenu.json index 5a715da..ecc6ef9 100644 --- a/src/assets/data/sideMenu.json +++ b/src/assets/data/sideMenu.json @@ -210,21 +210,7 @@ "route": "/home/permissions", "checked": false, "expanded": false, - "children": [], - "buttons": [ - { - "name": "edit", - "route": "", - "checked": false, - "expanded": false - }, - { - "name": "delete", - "route": "", - "checked": false, - "expanded": false - } - ] + "children": [] } ] } diff --git a/src/assets/i18n/Arabic.json b/src/assets/i18n/Arabic.json index 1dc6977..6e255f4 100644 --- a/src/assets/i18n/Arabic.json +++ b/src/assets/i18n/Arabic.json @@ -7,6 +7,8 @@ "defaultPassword": "كلمة المرور الافتراضية", "rememberMe":"تذكرنى", "forgotPassword":"هل نسيت كلمة السر؟", + "passwordTooShort": "كلمة المرور قصيرة جدًا.", + "passwordsDoNotMatch": "كلمتا المرور غير متطابقتين.", "login":"تسجيل الدخول", "dashboardTitle":"لوحة القيادة", "passwordChangeRequired": "تغيير كلمة المرور مطلوب", @@ -222,5 +224,11 @@ "CONNECTION_ERROR": "خطأ في الاتصال", "BAD_REQUEST": "اقتراح غير جيد", "FORBIDDEN_REQUEST": "طلب ممنوع", - "UNAUTHORIZED_REQUEST": "طلب غير مصرح به" + "UNAUTHORIZED_REQUEST": "طلب غير مصرح به", + "edit": "يحرر", + "delete": "يمسح", + "deleteUser": "حذف حساب المستخدم", + "permissionManagement": "إدارة الأذونات", + "userCode": "مستخدم", + "choose" : "يختار" } \ No newline at end of file diff --git a/src/assets/i18n/English.json b/src/assets/i18n/English.json index b505ea8..c007008 100644 --- a/src/assets/i18n/English.json +++ b/src/assets/i18n/English.json @@ -136,6 +136,8 @@ "passwordPatternNotMatched":"Password Pattern Not Matched", "successDeleted":"Successfully Deleted", "passwordNotSame":"Password Cannot be same as Old Password", + "passwordTooShort": "Password is too short.", + "passwordsDoNotMatch": "Passwords do not match.", "SuccessSave":"Successfully Saved", "SuccessFind":"Successfully Find", "customerAlreadyUnblocked": "Customer Already UnBlocked", @@ -221,5 +223,11 @@ "CONNECTION_ERROR": "Connection Error", "BAD_REQUEST": "Bad Request", "FORBIDDEN_REQUEST": "Forbidden Request", - "UNAUTHORIZED_REQUEST": "Unauthorized Request" + "UNAUTHORIZED_REQUEST": "Unauthorized Request", + "edit": "Edit", + "delete": "Delete", + "deleteUser": "Delete User", + "permissionManagement": "Permission Managment", + "userCode": "User", + "choose" : "Choose" } \ No newline at end of file