199 lines
6.2 KiB
TypeScript
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]));
|
|
}
|
|
}
|