From db1e57a0083a7c5e05bd48cccb84e4ae78d7ad9e Mon Sep 17 00:00:00 2001 From: atif118-mfsys Date: Thu, 25 Dec 2025 17:07:53 +0500 Subject: [PATCH 01/12] completed design for permission management screen. --- .../user-permissions.component.html | 96 +++++++++- .../user-permissions.component.scss | 19 ++ .../user-permissions.component.ts | 171 +++++++++++++++++- src/app/utils/uri-enums.ts | 5 +- src/assets/data/sideMenu.json | 16 +- src/assets/i18n/Arabic.json | 7 +- src/assets/i18n/English.json | 7 +- 7 files changed, 301 insertions(+), 20 deletions(-) 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..7c7c18b 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; + }); + this.getAllUsers(HiddenValues.VAC_USER); + } + + 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(userType: string) { + let porOrgacode = this.credentialService.getPorOrgacode(); + const params = new HttpParams().set('porOrgacode', porOrgacode) + .append('userType', userType); + // this.httpService.requestGET(URIKey.GET_ALL_USER_URI, params).subscribe((response) => { + // if (!(response instanceof HttpErrorResponse)) { + // this.users = response.map(item => ({ + // userName: item.userName, + // userId: item.userId, + // })); + // } + // }); + } + + onUserChange() { + this.showPermissions = true; + const params = new HttpParams().set(FormConstants.POR_ORGACODE, this.credentialService.getPorOrgacode()) + .append(FormConstants.USER_ID, this.permission.get('userCode')?.value); + // this.httpService.requestGET(URIKey.USER_GET_PERMISSIONS, params).subscribe((response: any) => { + // if (!(response instanceof HttpErrorResponse)) { + // if (response.permission) { + // this.updatePermissions(JSON.parse(response.permission), this.permissions); + // } + // else { + // this.defaultPermissions().subscribe((data: PermissionNode[]) => { + // this.permissions = data; + // }); + // } + // } + // }) + } + + savePermissions() { + let payload = { + porOrgacode: this.credentialService.getPorOrgacode(), + userId: this.permission.get('userCode')?.value, + permission: JSON.stringify(this.permissions) + } + // this.httpService.requestPATCH(URIKey.USER_SAVE_PERMISSION, payload).subscribe((response: any) => { + // if (!(response instanceof HttpErrorResponse)) { + // this.i18nService.success(SuccessMessages.SAVED_SUCESSFULLY, []); + // this.permission.reset(); + // 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 87b31be..8061c3d 100644 --- a/src/app/utils/uri-enums.ts +++ b/src/app/utils/uri-enums.ts @@ -1,5 +1,8 @@ export enum URIKey { USER_LOGIN_URI = "USER_LOGIN_URI", - USER_REFRESH_TOKEN = "USER_REFRESH_TOKEN" + USER_REFRESH_TOKEN = "USER_REFRESH_TOKEN", + USER_SAVE_PERMISSION = "USER_SAVE_PERMISSION", + USER_GET_PERMISSIONS = "USER_GET_PERMISSIONS", + GET_ALL_USER_URI = "GET_ALL_USER_URI" } \ No newline at end of file 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 10d017a..8278493 100644 --- a/src/assets/i18n/Arabic.json +++ b/src/assets/i18n/Arabic.json @@ -220,5 +220,10 @@ "CONNECTION_ERROR": "خطأ في الاتصال", "BAD_REQUEST": "اقتراح غير جيد", "FORBIDDEN_REQUEST": "طلب ممنوع", - "UNAUTHORIZED_REQUEST": "طلب غير مصرح به" + "UNAUTHORIZED_REQUEST": "طلب غير مصرح به", + "edit": "يحرر", + "delete": "يمسح", + "permissionManagement": "إدارة الأذونات", + "userCode": "مستخدم", + "choose" : "يختار" } \ No newline at end of file diff --git a/src/assets/i18n/English.json b/src/assets/i18n/English.json index 2fdac12..c6487ee 100644 --- a/src/assets/i18n/English.json +++ b/src/assets/i18n/English.json @@ -219,5 +219,10 @@ "CONNECTION_ERROR": "Connection Error", "BAD_REQUEST": "Bad Request", "FORBIDDEN_REQUEST": "Forbidden Request", - "UNAUTHORIZED_REQUEST": "Unauthorized Request" + "UNAUTHORIZED_REQUEST": "Unauthorized Request", + "edit": "Edit", + "delete": "Delete", + "permissionManagement": "Permission Managment", + "userCode": "User", + "choose" : "Choose" } \ No newline at end of file -- 2.32.0 From 9ccda5bc86a8f4f9a5f53e256cd2d413f18c8ac2 Mon Sep 17 00:00:00 2001 From: atif118-mfsys Date: Thu, 25 Dec 2025 17:10:02 +0500 Subject: [PATCH 02/12] applied optional chaining to avoid errors. --- .../change-password/change-password.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4eae8cc..dc6d5bd 100644 --- a/src/app/user-management/change-password/change-password.component.ts +++ b/src/app/user-management/change-password/change-password.component.ts @@ -46,7 +46,7 @@ passwordType2: string = 'password'; checkIfFirstTimeChangePasswordOrNot(){ let currentUser: any = JSON.parse(this.storageService.getItem('user')!) - if(currentUser.user.isFirstLogin){ + if(currentUser?.user?.isFirstLogin){ this.isFirstLogin = true; } else{ -- 2.32.0 From d703494c3ad4dfeac816329f061e3308394865b1 Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Tue, 30 Dec 2025 12:08:02 +0500 Subject: [PATCH 03/12] Implemented getUser Api implemented getUser Api to show the view and edit of the selected Id in the form. later removed the edit function --- src/app/services/user-setup.service.ts | 7 +++++ .../setup-user/setup-user.component.html | 26 +++++++------------ .../setup-user/setup-user.component.ts | 22 +++++++++++++++- src/app/utils/uri-enums.ts | 3 ++- src/assets/data/app.uri.json | 5 ++++ 5 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/app/services/user-setup.service.ts b/src/app/services/user-setup.service.ts index 99c0faa..f80a896 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' @@ -109,4 +110,10 @@ 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); +} } \ No newline at end of file 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..176c8b9 100644 --- a/src/app/user-management/setup-user/setup-user.component.html +++ b/src/app/user-management/setup-user/setup-user.component.html @@ -101,12 +101,11 @@
- - + +
@@ -157,9 +156,9 @@ - - - + + + @@ -171,15 +170,10 @@ - + + @@ -177,9 +182,11 @@ + +
{{'userID' | translate}}{{'Name' | translate}}{{'action' | translate}}{{'userID' | translate}}{{'Name' | translate}}{{'action' | translate}}
- - - - @@ -203,7 +197,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..9aa1dcd 100644 --- a/src/app/user-management/setup-user/setup-user.component.ts +++ b/src/app/user-management/setup-user/setup-user.component.ts @@ -25,6 +25,11 @@ export class SetupUserComponent implements OnInit { userId!: string; userFullname!: string; defaultPassword!: string; + mode: 'edit' | 'view' = 'view'; + showForm = false; + selectedUserId!: any; + user: any; + constructor(private userService: UserSetupService){} onSearch(value: string): void { @@ -50,7 +55,9 @@ export class SetupUserComponent implements OnInit { 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'); @@ -73,6 +80,19 @@ export class SetupUserComponent implements OnInit { }, 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.userId = user.userId; + this.userFullname = user.userFullname; + this.defaultPassword = ''; + }) } ngOnInit(): void { diff --git a/src/app/utils/uri-enums.ts b/src/app/utils/uri-enums.ts index 650cf52..77d7e5c 100644 --- a/src/app/utils/uri-enums.ts +++ b/src/app/utils/uri-enums.ts @@ -3,5 +3,6 @@ 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' } \ No newline at end of file diff --git a/src/assets/data/app.uri.json b/src/assets/data/app.uri.json index f7fd2dd..e6083d0 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -26,6 +26,11 @@ "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" } ] } -- 2.32.0 From 1976648c08d345c823dc1d6332e0300c54448143 Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Tue, 30 Dec 2025 15:47:09 +0500 Subject: [PATCH 04/12] Integrate deleteUser Api Integrate deleteUser Api --- src/app/services/user-setup.service.ts | 7 +++++++ .../setup-user/setup-user.component.html | 2 +- .../setup-user/setup-user.component.ts | 13 +++++++++++++ src/app/utils/uri-enums.ts | 3 ++- src/assets/data/app.uri.json | 5 +++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/app/services/user-setup.service.ts b/src/app/services/user-setup.service.ts index f80a896..b26f4c2 100644 --- a/src/app/services/user-setup.service.ts +++ b/src/app/services/user-setup.service.ts @@ -116,4 +116,11 @@ getUserById(userId: any){ 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/user-management/setup-user/setup-user.component.html b/src/app/user-management/setup-user/setup-user.component.html index 176c8b9..b8a681c 100644 --- a/src/app/user-management/setup-user/setup-user.component.html +++ b/src/app/user-management/setup-user/setup-user.component.html @@ -174,7 +174,7 @@ -
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 9aa1dcd..41105b8 100644 --- a/src/app/user-management/setup-user/setup-user.component.ts +++ b/src/app/user-management/setup-user/setup-user.component.ts @@ -6,6 +6,7 @@ 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 { error } from 'node:console'; @Component({ selector: 'app-setup-user', @@ -94,6 +95,18 @@ export class SetupUserComponent implements OnInit { this.defaultPassword = ''; }) } + + onDelete(userId: any){ + this.userService.deleteUser(userId).subscribe({ + next: (res: any) => { + this.userService.loadUsers(); + console.log('user deleted successfully') + }, + error: (err:any) =>{ + console.log('user not deleted') + } + }); + } ngOnInit(): void { this.userService.loadUsers(); diff --git a/src/app/utils/uri-enums.ts b/src/app/utils/uri-enums.ts index 77d7e5c..1d9bf19 100644 --- a/src/app/utils/uri-enums.ts +++ b/src/app/utils/uri-enums.ts @@ -4,5 +4,6 @@ export enum URIKey { USER_REFRESH_TOKEN = "USER_REFRESH_TOKEN", CREATE_USER = 'CREATE_USER', GET_ALL_USERS = 'GET_ALL_USERS', - GET_USER_BY_ID = 'GET_USER_BY_ID' + GET_USER_BY_ID = 'GET_USER_BY_ID', + DELETE_USER = 'DELETE_USER' } \ No newline at end of file diff --git a/src/assets/data/app.uri.json b/src/assets/data/app.uri.json index e6083d0..59fa5c7 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -31,6 +31,11 @@ "Id" : "ENTITY_GET_USER_BY_ID", "URI": "/user/getUser", "UUID": "GET_USER_BY_ID" + }, + { + "Id" : "ENTITY_DELETE_USER", + "URI": "/user/deleteUser", + "UUID": "DELETE_USER" } ] } -- 2.32.0 From 80a1e62411fc74674b8fe0af3ae41f2ec24589e7 Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Wed, 31 Dec 2025 10:57:03 +0500 Subject: [PATCH 05/12] onDelete form reset onDelete form reset --- .../user-management/setup-user/setup-user.component.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 41105b8..5ffa79f 100644 --- a/src/app/user-management/setup-user/setup-user.component.ts +++ b/src/app/user-management/setup-user/setup-user.component.ts @@ -100,12 +100,18 @@ export class SetupUserComponent implements OnInit { this.userService.deleteUser(userId).subscribe({ next: (res: any) => { this.userService.loadUsers(); - console.log('user deleted successfully') + this.showForm = false; + this.userId = ''; + this.userFullname = ''; + this.defaultPassword = ''; + this.selectedUserId = null; }, error: (err:any) =>{ console.log('user not deleted') } + }); + } ngOnInit(): void { -- 2.32.0 From dee23848ea8e8b2e4d9ec39dd5fff02395d97213 Mon Sep 17 00:00:00 2001 From: atif118-mfsys Date: Wed, 31 Dec 2025 15:15:26 +0500 Subject: [PATCH 06/12] integrated get all users API to provide options for user dropdown in permission management --- .../user-permissions.component.ts | 26 +++++++++---------- src/assets/data/app.uri.json | 5 ++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/app/user-permissions/user-permissions.component.ts b/src/app/user-permissions/user-permissions.component.ts index 7c7c18b..0041386 100644 --- a/src/app/user-permissions/user-permissions.component.ts +++ b/src/app/user-permissions/user-permissions.component.ts @@ -34,7 +34,10 @@ export class UserPermissionsComponent { this.defaultPermissions().subscribe((data: PermissionNode[]) => { this.permissions = data; }); - this.getAllUsers(HiddenValues.VAC_USER); + } + + ngOnInit(){ + this.getAllUsers(); } defaultPermissions(): Observable { @@ -111,18 +114,15 @@ export class UserPermissionsComponent { } } - getAllUsers(userType: string) { - let porOrgacode = this.credentialService.getPorOrgacode(); - const params = new HttpParams().set('porOrgacode', porOrgacode) - .append('userType', userType); - // this.httpService.requestGET(URIKey.GET_ALL_USER_URI, params).subscribe((response) => { - // if (!(response instanceof HttpErrorResponse)) { - // this.users = response.map(item => ({ - // userName: item.userName, - // userId: item.userId, - // })); - // } - // }); + 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() { diff --git a/src/assets/data/app.uri.json b/src/assets/data/app.uri.json index 6442eac..fdb81a4 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -16,6 +16,11 @@ "Id": "ENTITY_USER_REFRESH_TOKEN", "URI": "/refreshtoken", "UUID": "USER_REFRESH_TOKEN" + }, + { + "Id": "ENTITY_GET_ALL_USER_URI", + "URI": "/user/getAllUsers", + "UUID": "GET_ALL_USER_URI" } ] } -- 2.32.0 From 23d65b82d25a350aa89b4c648c06a42e629bac7d Mon Sep 17 00:00:00 2001 From: atif118-mfsys Date: Thu, 1 Jan 2026 14:32:37 +0500 Subject: [PATCH 07/12] integrated get permission for a specific user API --- .../user-permissions.component.ts | 27 +++++++++---------- src/assets/data/app.uri.json | 5 ++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/app/user-permissions/user-permissions.component.ts b/src/app/user-permissions/user-permissions.component.ts index 0041386..1bd2ed8 100644 --- a/src/app/user-permissions/user-permissions.component.ts +++ b/src/app/user-permissions/user-permissions.component.ts @@ -127,20 +127,19 @@ export class UserPermissionsComponent { onUserChange() { this.showPermissions = true; - const params = new HttpParams().set(FormConstants.POR_ORGACODE, this.credentialService.getPorOrgacode()) - .append(FormConstants.USER_ID, this.permission.get('userCode')?.value); - // this.httpService.requestGET(URIKey.USER_GET_PERMISSIONS, params).subscribe((response: any) => { - // if (!(response instanceof HttpErrorResponse)) { - // if (response.permission) { - // this.updatePermissions(JSON.parse(response.permission), this.permissions); - // } - // else { - // this.defaultPermissions().subscribe((data: PermissionNode[]) => { - // this.permissions = data; - // }); - // } - // } - // }) + 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.permission) { + this.updatePermissions(JSON.parse(response.permission), this.permissions); + } + else { + this.defaultPermissions().subscribe((data: PermissionNode[]) => { + this.permissions = data; + }); + } + } + }) } savePermissions() { diff --git a/src/assets/data/app.uri.json b/src/assets/data/app.uri.json index 9be8317..65e93ab 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -41,6 +41,11 @@ "Id" : "ENTITY_DELETE_USER", "URI": "/user/deleteUser", "UUID": "DELETE_USER" + }, + { + "Id" : "ENTITY_USER_GET_PERMISSIONS", + "URI": "/user/getPermissions", + "UUID": "USER_GET_PERMISSIONS" } ] } -- 2.32.0 From 35c23badcccc451120c912e97d5480cd3c338c36 Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Thu, 1 Jan 2026 15:40:42 +0500 Subject: [PATCH 08/12] updated the form with Reactive Forms updated the form with Reactive Forms --- src/app/services/user-setup.service.ts | 39 +-------- src/app/shared/pipes/userFilterPipe.ts | 22 +++++ .../setup-user/setup-user.component.html | 49 ++++++----- .../setup-user/setup-user.component.ts | 86 ++++++++++--------- src/assets/i18n/Arabic.json | 1 + src/assets/i18n/English.json | 1 + 6 files changed, 101 insertions(+), 97 deletions(-) create mode 100644 src/app/shared/pipes/userFilterPipe.ts diff --git a/src/app/services/user-setup.service.ts b/src/app/services/user-setup.service.ts index b26f4c2..3ee7018 100644 --- a/src/app/services/user-setup.service.ts +++ b/src/app/services/user-setup.service.ts @@ -13,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) { } @@ -35,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) }); @@ -43,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 { @@ -80,7 +50,6 @@ loadUsers(): void { const currentPage = this.currentPageSubject.value; if (currentPage < totalPages) { this.currentPageSubject.next(currentPage + 1); - this.applyPagination(); } } @@ -88,7 +57,7 @@ loadUsers(): void { const currentPage = this.currentPageSubject.value; if (currentPage > 1) { this.currentPageSubject.next(currentPage - 1); - this.applyPagination(); + } } @@ -96,7 +65,7 @@ loadUsers(): void { const totalPages = this.getTotalPages(); if (page > 0 && page <= totalPages) { this.currentPageSubject.next(page); - this.applyPagination(); + } } 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/setup-user/setup-user.component.html b/src/app/user-management/setup-user/setup-user.component.html index b8a681c..2f60c9d 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 @@
- -
- +
+ +
+ {{ 'requiredField' | translate }} +
@@ -57,7 +57,7 @@ +
+ {{ 'requiredField' | translate }}
@@ -80,18 +83,14 @@
- + +
+
+ {{ 'requiredField' | translate }}
@@ -101,8 +100,8 @@
- @@ -137,7 +136,7 @@ @@ -162,7 +161,13 @@
{{ item.userId }} {{ item.userFullname }}
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 5ffa79f..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,16 +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 { error } from 'node:console'; +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 @@ -23,18 +31,16 @@ export class SetupUserComponent implements OnInit { searchText: string = ''; renewalDataExpanded: boolean = true; totalCount: number = 0; - userId!: string; - userFullname!: string; - defaultPassword!: string; mode: 'edit' | 'view' = 'view'; - showForm = false; - selectedUserId!: any; - user: any; - constructor(private userService: UserSetupService){} + 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 { @@ -48,36 +54,30 @@ 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) }); @@ -90,21 +90,20 @@ export class SetupUserComponent implements OnInit { this.showForm = true; this.selectedUserId = userId; this.userService.getUserById(userId).subscribe((user: any)=>{ - this.userId = user.userId; - this.userFullname = user.userFullname; - this.defaultPassword = ''; + 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.showForm = false; - this.userId = ''; - this.userFullname = ''; - this.defaultPassword = ''; - this.selectedUserId = null; + this.userService.loadUsers(); + this.userForm.reset() + this.selectedUserId = null; }, error: (err:any) =>{ console.log('user not deleted') @@ -115,18 +114,23 @@ export class SetupUserComponent implements OnInit { } 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/assets/i18n/Arabic.json b/src/assets/i18n/Arabic.json index 397f143..2cc2571 100644 --- a/src/assets/i18n/Arabic.json +++ b/src/assets/i18n/Arabic.json @@ -225,6 +225,7 @@ "UNAUTHORIZED_REQUEST": "طلب غير مصرح به", "edit": "يحرر", "delete": "يمسح", + "deleteUser": "حذف حساب المستخدم", "permissionManagement": "إدارة الأذونات", "userCode": "مستخدم", "choose" : "يختار" diff --git a/src/assets/i18n/English.json b/src/assets/i18n/English.json index 6434080..a8574d8 100644 --- a/src/assets/i18n/English.json +++ b/src/assets/i18n/English.json @@ -224,6 +224,7 @@ "UNAUTHORIZED_REQUEST": "Unauthorized Request", "edit": "Edit", "delete": "Delete", + "deleteUser": "Delete User", "permissionManagement": "Permission Managment", "userCode": "User", "choose" : "Choose" -- 2.32.0 From 25d1e49475c80a816f6cd71d10cbd16217e4a9cc Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Thu, 1 Jan 2026 15:46:34 +0500 Subject: [PATCH 09/12] add missing translation add missing translation --- .../setup-user/setup-user.component.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 2f60c9d..f8a8a14 100644 --- a/src/app/user-management/setup-user/setup-user.component.html +++ b/src/app/user-management/setup-user/setup-user.component.html @@ -41,7 +41,7 @@
- {{ 'requiredField' | translate }} + {{ 'fieldRequired' | translate }}
@@ -64,11 +64,11 @@ rows="3" /> - - -
- {{ 'requiredField' | translate }} +
+ {{ 'fieldRequired' | translate }} +
+ @@ -87,11 +87,11 @@ name="defaultPassword" placeholder="{{ 'passwordPlaceHolder' | translate }}" appNoWhitespaces/> - -
- {{ 'requiredField' | translate }} + {{ 'fieldRequired' | translate }}
+ +
-- 2.32.0 From 7ba6a8b65f30065058ea42fec7682343a3ee2b6c Mon Sep 17 00:00:00 2001 From: atif118-mfsys Date: Fri, 2 Jan 2026 10:29:56 +0500 Subject: [PATCH 10/12] integrated the API to save permissions for a specific user --- .../user-permissions.component.ts | 23 ++++++++++--------- src/assets/data/app.uri.json | 5 ++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/app/user-permissions/user-permissions.component.ts b/src/app/user-permissions/user-permissions.component.ts index 1bd2ed8..025ae98 100644 --- a/src/app/user-permissions/user-permissions.component.ts +++ b/src/app/user-permissions/user-permissions.component.ts @@ -130,8 +130,8 @@ export class UserPermissionsComponent { 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.permission) { - this.updatePermissions(JSON.parse(response.permission), this.permissions); + if (response.permissions) { + this.updatePermissions(JSON.parse(response.permissions), this.permissions); } else { this.defaultPermissions().subscribe((data: PermissionNode[]) => { @@ -144,17 +144,18 @@ export class UserPermissionsComponent { savePermissions() { let payload = { - porOrgacode: this.credentialService.getPorOrgacode(), + // porOrgacode: this.credentialService.getPorOrgacode(), userId: this.permission.get('userCode')?.value, - permission: JSON.stringify(this.permissions) + permissions: JSON.stringify(this.permissions) } - // this.httpService.requestPATCH(URIKey.USER_SAVE_PERMISSION, payload).subscribe((response: any) => { - // if (!(response instanceof HttpErrorResponse)) { - // this.i18nService.success(SuccessMessages.SAVED_SUCESSFULLY, []); - // this.permission.reset(); - // this.showPermissions = false; - // } - // }) + 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 { diff --git a/src/assets/data/app.uri.json b/src/assets/data/app.uri.json index 65e93ab..be0b396 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -46,6 +46,11 @@ "Id" : "ENTITY_USER_GET_PERMISSIONS", "URI": "/user/getPermissions", "UUID": "USER_GET_PERMISSIONS" + }, + { + "Id" : "ENTITY_USER_SAVE_PERMISSION", + "URI": "/user/updatePermissions", + "UUID": "USER_SAVE_PERMISSION" } ] } -- 2.32.0 From 61df1a4ac2f1e9e3729efbd48cd1c7f256b6596e Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Mon, 5 Jan 2026 11:24:24 +0500 Subject: [PATCH 11/12] creating payload for reset and change password creating payload for reset and change password before the apis are ready --- .../change-password.component.html | 21 +++-- .../change-password.component.ts | 81 ++++++++++++------- .../reset-password.component.html | 59 +++++++------- .../reset-password.component.ts | 81 ++++++++++++++++--- src/app/utils/uri-enums.ts | 4 +- src/assets/data/app.uri.json | 10 +++ src/assets/i18n/Arabic.json | 2 + src/assets/i18n/English.json | 2 + 8 files changed, 188 insertions(+), 72 deletions(-) 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..595a91a 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,13 @@ 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 { URIService } from '../../app.uri'; +import { HttpURIService } from '../../app.http.uri.service'; +import { URIKey } from '../../utils/uri-enums'; @Component({ selector: 'app-change-password', @@ -13,15 +16,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 +29,7 @@ passwordType2: string = 'password'; @ViewChild('psh') passwordHideShow?: PasswordHideShowComponent; @ViewChild('psh1') passwordHideShow1 ?: PasswordHideShowComponent; @ViewChild('psh2') passwordHideShow2 ?: PasswordHideShowComponent; +constructor(private fb: FormBuilder, private uriService: URIService, private httpURIService: HttpURIService){} togglePasswordType() { this.passwordType = this.passwordHideShow?.showPassword ? 'password' : 'text'; @@ -40,31 +41,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..fb412d5 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,89 @@ -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 { URIService } from '../../app.uri'; +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 uriService: URIService, 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/utils/uri-enums.ts b/src/app/utils/uri-enums.ts index c0feff2..2d1957c 100644 --- a/src/app/utils/uri-enums.ts +++ b/src/app/utils/uri-enums.ts @@ -8,5 +8,7 @@ export enum URIKey { DELETE_USER = 'DELETE_USER', USER_SAVE_PERMISSION = "USER_SAVE_PERMISSION", USER_GET_PERMISSIONS = "USER_GET_PERMISSIONS", - GET_ALL_USER_URI = "GET_ALL_USER_URI" + 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 65e93ab..6dbded8 100644 --- a/src/assets/data/app.uri.json +++ b/src/assets/data/app.uri.json @@ -46,6 +46,16 @@ "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/i18n/Arabic.json b/src/assets/i18n/Arabic.json index 397f143..921b18e 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": "تغيير كلمة المرور مطلوب", diff --git a/src/assets/i18n/English.json b/src/assets/i18n/English.json index 6434080..0ee620c 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", -- 2.32.0 From ba5ca98da9722ff8568676d33e0ee40304b4cd01 Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Mon, 5 Jan 2026 12:22:04 +0500 Subject: [PATCH 12/12] removed unused imports --- .../change-password/change-password.component.ts | 5 +---- .../reset-password/reset-password.component.ts | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) 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 595a91a..423cdd4 100644 --- a/src/app/user-management/change-password/change-password.component.ts +++ b/src/app/user-management/change-password/change-password.component.ts @@ -3,9 +3,6 @@ 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 { URIService } from '../../app.uri'; import { HttpURIService } from '../../app.http.uri.service'; import { URIKey } from '../../utils/uri-enums'; @@ -29,7 +26,7 @@ passwordType2: string = 'password'; @ViewChild('psh') passwordHideShow?: PasswordHideShowComponent; @ViewChild('psh1') passwordHideShow1 ?: PasswordHideShowComponent; @ViewChild('psh2') passwordHideShow2 ?: PasswordHideShowComponent; -constructor(private fb: FormBuilder, private uriService: URIService, private httpURIService: HttpURIService){} +constructor(private fb: FormBuilder, private httpURIService: HttpURIService){} togglePasswordType() { this.passwordType = this.passwordHideShow?.showPassword ? 'password' : 'text'; 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 fb412d5..c810314 100644 --- a/src/app/user-management/reset-password/reset-password.component.ts +++ b/src/app/user-management/reset-password/reset-password.component.ts @@ -4,7 +4,6 @@ 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 { URIService } from '../../app.uri'; import { HttpURIService } from '../../app.http.uri.service'; @Component({ @@ -21,7 +20,7 @@ export class ResetPasswordComponent implements OnInit{ @ViewChild('psh1') passwordHideShow1?: PasswordHideShowComponent; @ViewChild('psh2') passwordHideShow2?: PasswordHideShowComponent; - constructor(private fb: FormBuilder, private uriService: URIService, private httpURIService: HttpURIService){} + constructor(private fb: FormBuilder, private httpURIService: HttpURIService){} ngOnInit(): void { this.resetPasswordForm = this.fb.group({ -- 2.32.0