feat: update kyc tab, branch day register, and dormancy reports
Tests / testRigor (push) Canceled after 0s
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s

This commit is contained in:
2026-09-10 18:29:33 +05:30
parent f0c06988c0
commit fd5fe6e3b2
16 changed files with 595 additions and 104 deletions
@@ -34,6 +34,7 @@ import {
sortByIdle,
stageFromSubStatus
} from './dormancy-report.compute';
import { toIsoDate } from 'app/core/utils/api-date';
/**
* The three reports on accounts that have gone quiet.
@@ -109,9 +110,20 @@ export class DormancyReportComponent implements OnInit {
this.clientsService.getDormantAccounts().subscribe({
next: (accounts: any[]) => {
this.rows = sortByIdle(
(accounts || []).map((a) => this.mapAccount(a)).filter((r): r is DormancyRow => r !== null)
);
// Mapping is wrapped because it did once throw on a date the API returned in a shape this
// screen did not expect. The throw escaped the callback, so `loading` was never cleared and
// the report sat on "Loading..." with every control dead and nothing in the network tab to
// explain it. A bad row should cost the row, not the screen.
try {
this.rows = sortByIdle(
(accounts || []).map((a) => this.mapAccount(a)).filter((r): r is DormancyRow => r !== null)
);
} catch (e) {
this.rows = [];
this.errorMessage = 'Could not read the dormancy reports.';
console.error('Dormancy report: could not map the accounts returned by the server', e);
}
this.openFirstStageWithRows();
this.loading = false;
},
error: (err: any) => {
@@ -300,7 +312,7 @@ export class DormancyReportComponent implements OnInit {
return null;
}
const lastTxn = (a?.lastCustomerTransactionDate || '').toString().slice(0, 10);
const lastTxn = toIsoDate(a?.lastCustomerTransactionDate);
const next = lastTxn ? nextStage(lastTxn, stage) : { date: '', label: '' };
return {
@@ -321,10 +333,10 @@ export class DormancyReportComponent implements OnInit {
// against it. Absence of that row is the whole point of the report: the money has left the
// customer's account but is not yet accounted for as having reached RBI.
remittance: stage === 'ESCHEAT' ? (a?.deafRemittedOn ? 'REMITTED' : 'PENDING') : undefined,
escheatedOn: (a?.closedOnDate || '').toString().slice(0, 10) || undefined,
remittedOn: (a?.deafRemittedOn || '').toString().slice(0, 10) || undefined,
escheatedOn: toIsoDate(a?.closedOnDate) || undefined,
remittedOn: toIsoDate(a?.deafRemittedOn) || undefined,
deafReference: a?.deafReference || undefined,
refundedOn: (a?.deafRefundedOn || '').toString().slice(0, 10) || undefined,
refundedOn: toIsoDate(a?.deafRefundedOn) || undefined,
mobile: a?.mobileNo || ''
};
}
@@ -391,6 +403,30 @@ export class DormancyReportComponent implements OnInit {
}
}
/**
* Opens the first stage that actually has accounts on it.
*
* The tab that happens to be selected is not necessarily the one holding the data: the report
* opens on Dormant, and an account that has only reached Inactive — or that fell back to it
* because a customer transaction reset its clock — leaves the reader looking at "No accounts at
* this stage" beside a card counting 1. Only moves off a tab that is empty, so a reader who has
* deliberately opened a stage is not thrown off it when the data reloads.
*/
private openFirstStageWithRows(): void {
if (this.rowsForStage(this.tab).length > 0) {
return;
}
const ladder: DormancyStage[] = [
'INACTIVE',
'DORMANT',
'ESCHEAT'
];
const populated = ladder.find((stage) => this.rowsForStage(stage).length > 0);
if (populated) {
this.showTab(populated);
}
}
// ── Presentation ───────────────────────────────────────────────────────────
/** The server already returns the office by name, so there is nothing to look up. */
@@ -111,6 +111,10 @@ export interface DormancyRow {
function addDays(date: string, days: number): string {
const d = new Date(`${date}T00:00:00Z`);
if (Number.isNaN(d.getTime())) {
// Never let an unparseable date take the whole report down with it.
return '';
}
return new Date(d.getTime() + days * 86400000).toISOString().slice(0, 10);
}