implement user, role, product, and task management components along with associated services and UI updates

This commit is contained in:
2026-08-27 18:30:45 +05:30
parent fa2522e678
commit abc966d507
20 changed files with 1471 additions and 202 deletions
@@ -21,6 +21,7 @@ import { MatDialog } from '@angular/material/dialog';
/** Custom Services */
import { UsersService } from '../users.service';
import { PopoverService } from '../../configuration-wizard/popover/popover.service';
import { AlertService } from 'app/core/alert/alert.service';
/** Custom Dialog Component */
import { PasswordsUtility } from 'app/core/utils/passwords-utility';
@@ -56,6 +57,7 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
private configurationWizardService = inject(ConfigurationWizardService);
private dialog = inject(MatDialog);
private passwordsUtility = inject(PasswordsUtility);
private alertService = inject(AlertService);
/** User form. */
userForm: UntypedFormGroup;
@@ -211,6 +213,12 @@ export class CreateUserComponent implements OnInit, AfterViewInit {
if (this.configurationWizardService.showUsersForm) {
this.configurationWizardService.showUsersForm = false;
this.openDialog();
} else if (response?.rollbackTransaction) {
this.alertService.alert({
type: 'Success',
message: 'User creation request submitted successfully for approval.'
});
this.router.navigate(['../'], { relativeTo: this.route });
} else {
this.router.navigate(
[
+31 -21
View File
@@ -19,6 +19,7 @@ import { MatIcon } from '@angular/material/icon';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { SuccessDialogComponent } from 'app/shared/success-dialog/success-dialog.component';
import { ErrorDialogComponent } from 'app/shared/error-dialog/error-dialog.component';
import { AlertService } from 'app/core/alert/alert.service';
/**
* Edit User Component.
@@ -39,6 +40,7 @@ export class EditUserComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
private dialog = inject(MatDialog);
private alertService = inject(AlertService);
/** User Data */
userData: any;
@@ -142,27 +144,35 @@ export class EditUserComponent implements OnInit {
const editedUser = this.editUserForm.value;
this.usersService.editUser(this.userData.id, editedUser).subscribe({
next: (response: any) => {
// Fineract sometimes omits resourceId in PUT responses — fall back to
// the user id we're editing so navigation never silently no-ops.
const targetId = response?.resourceId ?? this.userData.id;
const dialogRef = this.dialog.open(SuccessDialogComponent, {
data: {
title: 'User updated',
message: `Changes to ${this.userData.username} have been saved successfully.`,
buttonLabel: 'View user'
},
panelClass: 'sd-panel',
disableClose: true
});
dialogRef.afterClosed().subscribe(() => {
this.router.navigate(
[
'../../',
targetId
],
{ relativeTo: this.route }
);
});
if (response?.rollbackTransaction) {
this.alertService.alert({
type: 'Success',
message: 'User update request submitted successfully for approval.'
});
this.router.navigate(['../../'], { relativeTo: this.route });
} else {
// Fineract sometimes omits resourceId in PUT responses — fall back to
// the user id we're editing so navigation never silently no-ops.
const targetId = response?.resourceId ?? this.userData.id;
const dialogRef = this.dialog.open(SuccessDialogComponent, {
data: {
title: 'User updated',
message: `Changes to ${this.userData.username} have been saved successfully.`,
buttonLabel: 'View user'
},
panelClass: 'sd-panel',
disableClose: true
});
dialogRef.afterClosed().subscribe(() => {
this.router.navigate(
[
'../../',
targetId
],
{ relativeTo: this.route }
);
});
}
},
error: (err) => {
console.error('[EditUser] update failed', err);
+58
View File
@@ -87,4 +87,62 @@ export class UsersService {
const httpParams = new HttpParams().set('officeId', officeId.toString()).set('status', 'all');
return this.http.get('/staff', { params: httpParams });
}
/**
* @param {string} status Status filter (e.g. 'PENDING')
* @param {string} username Username filter
* @param {string} fromDate From date filter
* @param {string} toDate To date filter
* @param {number} offset Offset
* @param {number} limit Limit
* @returns {Observable<any>} Pending users
*/
getPendingUsers(
status?: string,
username?: string,
fromDate?: string,
toDate?: string,
offset: number = 0,
limit: number = 20
): Observable<any> {
let httpParams = new HttpParams().set('offset', offset.toString()).set('limit', limit.toString());
if (status) {
httpParams = httpParams.set('status', status);
}
if (username) {
httpParams = httpParams.set('username', username);
}
if (fromDate) {
httpParams = httpParams.set('fromDate', fromDate);
}
if (toDate) {
httpParams = httpParams.set('toDate', toDate);
}
return this.http.get('/users/pending', { params: httpParams });
}
/**
* @param {string | number} id Pending request ID
* @returns {Observable<any>}
*/
getPendingUser(id: string | number): Observable<any> {
return this.http.get(`/users/pending/${id}`);
}
/**
* @param {string | number} id Pending request ID
* @returns {Observable<any>}
*/
approvePendingUser(id: string | number): Observable<any> {
return this.http.post(`/users/pending/${id}/approve`, {});
}
/**
* @param {string | number} id Pending request ID
* @param {string} reason Rejection reason
* @returns {Observable<any>}
*/
rejectPendingUser(id: string | number, reason: string): Observable<any> {
return this.http.post(`/users/pending/${id}/reject`, { reason });
}
}
@@ -15,6 +15,7 @@ import { MatIconButton } from '@angular/material/button';
/** Custom Services */
import { UsersService } from '../users.service';
import { AlertService } from 'app/core/alert/alert.service';
/** Custom Components */
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
@@ -42,6 +43,7 @@ export class ViewUserComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private dialog = inject(MatDialog);
private alertService = inject(AlertService);
/** User Data. */
userData: any;
@@ -68,7 +70,13 @@ export class ViewUserComponent {
});
deleteUserDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.usersService.deleteUser(this.userData.id).subscribe(() => {
this.usersService.deleteUser(this.userData.id).subscribe((res: any) => {
if (res?.rollbackTransaction) {
this.alertService.alert({
type: 'Success',
message: 'User deletion request submitted successfully for approval.'
});
}
this.router.navigate(['/appusers']);
});
}