Files
cbsnexora/src/app/tasks/checker-inbox-and-tasks-tabs/pending-savings-account-edits/pending-savings-account-edits.component.ts
T

199 lines
6.2 KiB
TypeScript

/**
* Copyright since 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Component, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import {
MatTableDataSource,
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow
} from '@angular/material/table';
import { MatDialog } from '@angular/material/dialog';
import { MatIcon } from '@angular/material/icon';
import { MatIconButton } from '@angular/material/button';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { SavingsService } from 'app/savings/savings.service';
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component';
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Checker-facing list of savings account Nominee / Digital-Feature edits awaiting approval.
* Mirrors PendingSavingsProductsComponent's list + compare + approve/reject pattern.
*/
@Component({
selector: 'mifosx-pending-savings-account-edits',
templateUrl: './pending-savings-account-edits.component.html',
styleUrls: ['./pending-savings-account-edits.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
FaIconComponent,
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow,
MatIcon,
MatIconButton
]
})
export class PendingSavingsAccountEditsComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private dialog = inject(MatDialog);
private savingsService = inject(SavingsService);
private currentAccountsService = inject(CurrentAccountsService);
dataSource: MatTableDataSource<any>;
showData = false;
displayedColumns: string[] = [
'accountNo',
'accountType',
'makerUsername',
'createdOn',
'holdAmount',
'status',
'actions'
];
selectedEdit: any = null;
constructor() {
this.route.data.subscribe((data: { pendingSavingsAccountEditsData: any; pendingCurrentAccountEditsData: any }) => {
const savingsItems = (data.pendingSavingsAccountEditsData || []).map((item: any) => {
let type = 'Savings';
if (item.depositAccountType === 'FIXED_DEPOSIT') {
type = 'Fixed Deposit';
} else if (item.depositAccountType === 'RECURRING_DEPOSIT') {
type = 'Recurring Deposit';
}
return {
...item,
accountType: type
};
});
const currentItems = (data.pendingCurrentAccountEditsData || []).map((item: any) => ({
...item,
accountType: 'Current'
}));
const items = [
...savingsItems,
...currentItems
];
this.showData = items.length > 0;
this.dataSource = new MatTableDataSource(items);
});
}
applyFilter(filterValue: string = '') {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
formatDate(date: any): string {
if (!date) return '';
const d = Array.isArray(date)
? new Date(date[0], date[1] - 1, date[2], date[3] || 0, date[4] || 0)
: new Date(date);
return isNaN(d.getTime()) ? String(date) : d.toLocaleString('en-IN');
}
/** Readable list of "key: value" pairs for the proposed facility/nominee changes. */
entries(obj: any): { key: string; value: any }[] {
if (!obj) return [];
return Object.keys(obj).map((key) => ({ key, value: obj[key] }));
}
viewCompare(edit: any): void {
this.selectedEdit = this.selectedEdit === edit ? null : edit;
}
closeCompare(): void {
this.selectedEdit = null;
}
approve(edit: any): void {
const isCurrent = edit.accountType === 'Current';
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: {
heading: isCurrent ? 'Approve Current Account Edit' : 'Approve Savings Account Edit',
dialogContext: `Apply the pending Nominee/Digital-Feature edit for account "${edit.accountNo}"? This cannot be undone.`,
type: 'basic'
}
});
dialogRef.afterClosed().subscribe((response: any) => {
if (response?.confirm) {
if (isCurrent) {
this.currentAccountsService.approveCurrentAccountEdit(edit.currentAccountId).subscribe(() => this.reload());
} else {
this.savingsService.approveSavingsAccountEdit(edit.savingsAccountId).subscribe(() => this.reload());
}
}
});
}
reject(edit: any): void {
const isCurrent = edit.accountType === 'Current';
const formfields: FormfieldBase[] = [
new InputBase({
controlName: 'rejectReason',
label: 'Reason for rejection',
value: '',
type: 'text',
required: false
})
];
const dialogRef = this.dialog.open(FormDialogComponent, {
data: {
title: `Reject edit for account "${edit.accountNo}"`,
layout: { addButtonText: 'Reject' },
formfields
}
});
dialogRef.afterClosed().subscribe((response: any) => {
if (response?.data) {
const rejectReason = response.data.value.rejectReason || '';
if (isCurrent) {
this.currentAccountsService
.rejectCurrentAccountEdit(edit.currentAccountId, rejectReason)
.subscribe(() => this.reload());
} else {
this.savingsService
.rejectSavingsAccountEdit(edit.savingsAccountId, rejectReason)
.subscribe(() => this.reload());
}
}
});
}
reload(): void {
this.closeCompare();
const url = this.router.url;
this.router
.navigateByUrl('/checker-inbox-and-tasks', { skipLocationChange: true })
.then(() => this.router.navigate([url]));
}
}