import { Component } from '@angular/core'; import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { PermissionNode } from '../utils/app.interfaces'; 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 { CommonModule } from '@angular/common'; import { NgSelectModule } from '@ng-select/ng-select'; import { filter, Observable, take } from 'rxjs'; import { SuccessMessages } from '../utils/enums'; import { URIService } from '../app.uri'; @Component({ selector: 'app-menu', imports: [TranslateModule, ReactiveFormsModule, CommonModule, TranslateModule, NgSelectModule, FormsModule], templateUrl: './menu.component.html', styleUrl: './menu.component.scss' }) export class MenuComponent { users: any[] = []; permission: FormGroup; showPermissions = false; permissions: PermissionNode[] = []; saving = false; menuItems: { endpoint: string; checked: boolean }[] = []; constructor( private credentialService: CredentialService, private fb: FormBuilder, private httpService: HttpURIService, private i18nService: I18NService, private uriService: URIService ) { this.permission = this.fb.group({ userCode: [null] }); this.defaultPermissions().subscribe((data: PermissionNode[]) => { this.permissions = data; // needed for savePermissions }); } ngOnInit() { this.getAllUsers(); this.loadTransactionEndpoints(); } loadTransactionEndpoints() { this.httpService.requestGET(URIKey.TRANSACTION_ENDPOINTS).subscribe((response) => { if (!(response instanceof HttpErrorResponse)) { this.menuItems = response.map(endpoint => ({ endpoint, checked: false })); } }); } defaultPermissions(): Observable { return this.httpService.requestGET('assets/data/sideMenu.json'); } 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, })); } }); } // mapEndpointsToPermissions(endpoints: string[]): PermissionNode[] { // return [{ // name: 'menu', // checked: false, // expanded: false, // children: [ // { name: 'accountToAccount', checked: endpoints.includes(this.uriService.getURIForRequest(URIKey.ACCOUNT_TO_ACCOUNT)), expanded: false }, // { name: 'glToGl', checked: endpoints.includes(this.uriService.getURIForRequest(URIKey.GL_TO_GL)), expanded: false }, // { name: 'accountToGl', checked: endpoints.includes(this.uriService.getURIForRequest(URIKey.ACCOUNT_TO_GL)), expanded: false }, // { name: 'glToAccount', checked: endpoints.includes(this.uriService.getURIForRequest(URIKey.GL_TO_ACCOUNT)), expanded: false } // ] // }]; // } onUserChange() { this.showPermissions = true; const userId = this.permission.get('userCode')?.value; const params = new HttpParams().set('userId', userId); this.httpService.requestGET(URIKey.TRANSACTION_PERMISSIONS, params) .subscribe((response: any) => { if (!(response instanceof HttpErrorResponse)) { const allowedEndpoints: string[] = (response as any[]) .filter(p => p.allowed) .map(p => this.normalizeUrl(p.transactionEndpoint)); // ← normalize this.menuItems.forEach(item => { item.checked = allowedEndpoints.some(allowed => allowed.endsWith(this.normalizeUrl(item.endpoint)) ); }); } else { this.menuItems.forEach(item => item.checked = false); } }); } // Add this helper method to the class private normalizeUrl(url: string): string { return url?.trim().toLowerCase().replace(/\/+$/, ''); // trim, lowercase, remove trailing slash } // savePermissions() { // const selectedUser = this.permission.get('userCode')?.value; // const menuNode = this.permissions.find(x => x.name === 'menu'); // if (!menuNode) return; // const nameToURIKey: { [key: string]: URIKey } = { // accountToAccount: URIKey.ACCOUNT_TO_ACCOUNT, // glToGl: URIKey.GL_TO_GL, // accountToGl: URIKey.ACCOUNT_TO_GL, // glToAccount: URIKey.GL_TO_ACCOUNT // }; // const transactionEndpoints: string[] = (menuNode.children || []) // .filter(c => c.checked) // .map(c => this.uriService.getURIForRequest(nameToURIKey[c.name])); // const payload = { userId: selectedUser, transactionEndpoints, permissions: JSON.stringify(this.permissions) }; // this.httpService.requestPOST(URIKey.TRANSACTION_PERMISSIONS_ASSIGN, payload).subscribe((response: any) => { // if (!(response instanceof HttpErrorResponse)) { // this.i18nService.success(SuccessMessages.SAVED_SUCCESSFULLY, []); // this.permission.get('userCode')?.setValue(selectedUser); // this.onUserChange(); // } // }); // } savePermissions() { if (this.saving) return; // ← guard against double clicks this.saving = true; const selectedUser = this.permission.get('userCode')?.value; this.uriService.canSubscribe.pipe( filter(ready => ready === true), take(1) ).subscribe(() => { const transactionEndpoints: string[] = this.menuItems .filter(item => item.checked) .map(item => item.endpoint); const payload = { userId: selectedUser, transactionEndpoints }; this.httpService.requestPOST(URIKey.TRANSACTION_PERMISSIONS_ASSIGN, payload) .subscribe({ next: (response: any) => { if (!(response instanceof HttpErrorResponse)) { this.i18nService.success(SuccessMessages.SAVED_SUCCESSFULLY, []); this.onUserChange(); // this triggers one GET — expected } }, complete: () => { this.saving = false; // ← reset after done }, error: () => { this.saving = 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); } } } } }