Files
cbsnexora/src/app/cfcfrms/i4c/i4c-dashboard/i4c-dashboard.component.ts
T
niteshandClaude Opus 5.5 fca550f4c4 feat(cfcfrms): I4C Live screens for the I4C-MHA integration
New CFCFRMS > I4C Live section backed by /v1/i4c/admin and /v1/i4c/cases
(the demo mock interceptor does not match these paths):

- Dashboard, complaints from I4C, holds register, approvals, responses and
  API log, bank code master, intimation settings.
- Hold popup: overview, hold transactions, customer intimation (automatic and
  manual), maker request (full / partial release, freeze, unfreeze), GRM / MRM
  and documents, request history.
- GRM grievances, MRM restorations and MRM balance report pages; shared date
  range filter (today, yesterday, week, month, custom), server-side paging and
  filters on every list; document upload / download.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:43:30 +05:30

127 lines
3.7 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, OnInit, inject } from '@angular/core';
import { DecimalPipe } from '@angular/common';
import { RouterLink } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { I4cService, i4cErrorMessage } from '../i4c.service';
/**
* Integration health at a glance, and the API performance figures the RBI letter (05 Dec 2025, para 4) asks to be
* reviewed periodically: calls, failures and response times in each direction.
*/
@Component({
selector: 'mifosx-i4c-dashboard',
templateUrl: './i4c-dashboard.component.html',
styleUrls: ['./i4c-dashboard.component.scss'],
imports: [
DecimalPipe,
RouterLink,
MatButtonModule,
MatProgressBarModule,
FaIconComponent
]
})
export class I4cDashboardComponent implements OnInit {
private i4c = inject(I4cService);
data: any = null;
loading = false;
error = '';
showConfigModal = false;
copiedKey = '';
ngOnInit(): void {
this.load();
}
load(): void {
this.loading = true;
this.error = '';
this.i4c.dashboard().subscribe({
next: (d) => {
this.data = d;
this.loading = false;
},
error: (e) => {
this.error = i4cErrorMessage(e);
this.loading = false;
}
});
}
copyText(text: string, key: string): void {
if (!text) {
return;
}
navigator.clipboard.writeText(text);
this.copiedKey = key;
setTimeout(() => {
if (this.copiedKey === key) {
this.copiedKey = '';
}
}, 2000);
}
statusClass(status: string): string {
switch (status) {
case 'PROCESSED':
return 'i4c-badge--green';
case 'RETRY':
return 'i4c-badge--red';
case 'RECEIVED':
case 'PROCESSING':
return 'i4c-badge--amber';
default:
return '';
}
}
/** Success rate of calls in one direction, as a percentage; null when there were none. */
successRate(row: any): number | null {
const calls = Number(row?.calls || 0);
return calls === 0 ? null : (Number(row?.succeeded || 0) * 100) / calls;
}
/** What still stands between this bank and live traffic, worked out from the configuration. */
get setupGaps(): string[] {
const c = this.data?.configuration;
if (!c) {
return [];
}
const gaps: string[] = [];
if (!c.enabled) {
gaps.push('Integration is switched off (fineract.i4c.enabled=false): I4C calls are refused with 503.');
}
if (!c.inboundCredentialsConfigured) {
gaps.push('No inbound username/password set for I4C to obtain a token.');
} else if (!c.inboundPasswordHashed) {
gaps.push('Inbound password is configured in plain text; set the bcrypt hash for production.');
}
if (!c.allowedIpCount) {
gaps.push('No I4C source IP allowlist: any address may call (UAT only).');
}
if (c.cryptoMode !== 'NONE' && !c.cryptoPassphraseConfigured) {
gaps.push('Encryption mode is ' + c.cryptoMode + ' but no passphrase is configured.');
}
if (!c.outboundConfigured) {
gaps.push('I4C response URL is not configured: replies wait in the outbox.');
}
if (!c.bankCode) {
gaps.push("This bank's I4C bank code is not set (fineract.i4c.bank-code); root_bankid is sent as 0.");
}
if (c.simulatorEnabled) {
gaps.push('The local I4C simulator is enabled; switch it off in production.');
}
return gaps;
}
}