feat(npa): add Recovery Management System reports + Recovery Journey popup
Adds loan-type-aware recovery tracking (EMI/Overdrawn/Bullet) with a Recovery Management Dashboard, Day-wise Overdue/Overdrawn reports, an Agriculture/Gold market-value report, and a security-value exception check — all derived from new repaymentType/emiAmount/drawingPower/maturityDate/collateralMarketValue fields on LoanAccount, wired into Export to Excel and the NPA mega-menu. Also replaces the always-visible Recovery/Collection Journey card on the Account Detail Report with a "Recovery Journey" popup: a date-led, icon-coded timeline of every SMS/call/visit/notice and payment run against an account.
This commit is contained in:
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
<div class="cctr-tabs">
|
||||
@for (g of ['reports', 'analysis', 'classification']; track g) {
|
||||
@for (g of ['reports', 'analysis', 'classification', 'recovery-mgmt']; track g) {
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
@@ -462,9 +462,14 @@
|
||||
|
||||
@if (selectedAccount; as a) {
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">
|
||||
{{ a.accountNo }} — {{ a.customerName }}
|
||||
<span [class]="badgeClass(stage(a))">{{ stageLabel(stage(a)) }}</span>
|
||||
<div class="pos-section-label npa-detail-header">
|
||||
<span
|
||||
>{{ a.accountNo }} — {{ a.customerName }}
|
||||
<span [class]="badgeClass(stage(a))">{{ stageLabel(stage(a)) }}</span></span
|
||||
>
|
||||
<button type="button" class="pg-btn npa-timeline-trigger" (click)="openTimelineModal()">
|
||||
<fa-icon icon="history"></fa-icon> Recovery Journey
|
||||
</button>
|
||||
</div>
|
||||
<dl class="npa-detail-grid">
|
||||
<div class="npa-detail-field">
|
||||
@@ -1037,6 +1042,548 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ===================== 11 RECOVERY MANAGEMENT DASHBOARD ===================== -->
|
||||
@if (activeReport === 'recovery-dashboard') {
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">Recovery Management Dashboard — Loan-Type Overdue Check</div>
|
||||
<p class="pg-sub npa-report-note">
|
||||
Every loan is checked for "is this cycle's dues fully recovered" the way it's actually due — a Term Loan (EMI)
|
||||
is checked against its instalment, an Overdrawn (CC/OD/KCC) account against its drawing power and interest
|
||||
servicing, and a Bullet loan (Gold) is checked once past maturity.
|
||||
</p>
|
||||
<div class="inv-kpis npa-kpis--three">
|
||||
@for (row of recoveryTypeSummary; track row.type) {
|
||||
<div class="inv-kpi">
|
||||
<span class="inv-kpi__label">{{ row.label }}</span>
|
||||
<span class="inv-kpi__value">{{ row.accounts }} accounts</span>
|
||||
<span class="inv-kpi__sub" [class.npa-warn]="row.overdueCount > 0"
|
||||
>{{ row.overdueCount }} overdue this cycle</span
|
||||
>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">Expected vs Actual Recovery — This Cycle, by Loan Type</div>
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Loan Type</th>
|
||||
<th class="num">Accounts</th>
|
||||
<th class="num">Overdue Now</th>
|
||||
<th class="num">Expected Recovery</th>
|
||||
<th class="num col-in">Actual Recovery</th>
|
||||
<th class="num">Variance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (row of recoveryTypeSummary; track row.type) {
|
||||
<tr>
|
||||
<td>{{ row.label }}</td>
|
||||
<td class="num">{{ row.accounts }}</td>
|
||||
<td class="num">{{ row.overdueCount }}</td>
|
||||
<td class="num">₹{{ row.expected | number: '1.0-0' }}</td>
|
||||
<td class="num col-in">₹{{ row.actual | number: '1.0-0' }}</td>
|
||||
<td class="num" [class.col-out]="row.actual - row.expected < 0">
|
||||
₹{{ row.actual - row.expected | number: '1.0-0' }}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="cctr-total-row">
|
||||
<td>Total</td>
|
||||
<td class="num">{{ allAccounts.length }}</td>
|
||||
<td class="num">
|
||||
{{
|
||||
recoveryTypeSummary[0].overdueCount +
|
||||
recoveryTypeSummary[1].overdueCount +
|
||||
recoveryTypeSummary[2].overdueCount
|
||||
}}
|
||||
</td>
|
||||
<td class="num">₹{{ expectedRecoveryTotal | number: '1.0-0' }}</td>
|
||||
<td class="num">₹{{ actualRecoveryTotal | number: '1.0-0' }}</td>
|
||||
<td class="num" [class.col-out]="recoveryVarianceTotal < 0">
|
||||
₹{{ recoveryVarianceTotal | number: '1.0-0' }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<p class="pg-sub npa-report-note">
|
||||
Overall recovery rate: {{ recoveryPctTotal | number: '1.1-1' }}% of this cycle's expected dues.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">Loan-wise Expected vs Actual Recovery</div>
|
||||
<div class="pg-table-scroll">
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account No</th>
|
||||
<th>Customer</th>
|
||||
<th>Branch</th>
|
||||
<th>Loan Type</th>
|
||||
<th class="num">Expected</th>
|
||||
<th class="num col-in">Actual</th>
|
||||
<th class="num">Variance</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (a of paged(loanWiseRecoveryAccounts); track a.accountNo) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">{{ a.accountNo }}</span>
|
||||
</td>
|
||||
<td>{{ a.customerName }}</td>
|
||||
<td>{{ a.branchName }}</td>
|
||||
<td>{{ repaymentTypeLabel(a.repaymentType) }}</td>
|
||||
<td class="num">₹{{ expectedThisMonth(a) | number: '1.0-0' }}</td>
|
||||
<td class="num col-in">₹{{ actualThisMonth(a) | number: '1.0-0' }}</td>
|
||||
<td class="num" [class.col-out]="recoveryVariance(a) < 0">
|
||||
₹{{ recoveryVariance(a) | number: '1.0-0' }}
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
class="npa-badge"
|
||||
[class.npa-badge--standard]="recoveryVariance(a) >= 0"
|
||||
[class.npa-badge--substandard]="recoveryVariance(a) < 0"
|
||||
>
|
||||
{{ recoveryVariance(a) >= 0 ? 'Recovered' : 'Shortfall' }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr>
|
||||
<td colspan="8" class="pg-empty">No accounts in this branch.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@if (loanWiseRecoveryAccounts.length > pageSize) {
|
||||
<div class="pg-pagination">
|
||||
<span class="pg-pagination__info"
|
||||
>Showing {{ rangeStart(loanWiseRecoveryAccounts) }}–{{ rangeEnd(loanWiseRecoveryAccounts) }} of
|
||||
{{ loanWiseRecoveryAccounts.length }}</span
|
||||
>
|
||||
<div class="pg-pagination__controls">
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === 1"
|
||||
(click)="goToPage(currentPage - 1, loanWiseRecoveryAccounts)"
|
||||
>
|
||||
‹ Prev
|
||||
</button>
|
||||
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(loanWiseRecoveryAccounts) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === pageCount(loanWiseRecoveryAccounts)"
|
||||
(click)="goToPage(currentPage + 1, loanWiseRecoveryAccounts)"
|
||||
>
|
||||
Next ›
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ===================== 12 DAY-WISE OVERDUE REPORT ===================== -->
|
||||
@if (activeReport === 'daywise-overdue') {
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">Day-wise Overdue Report — Ageing Buckets</div>
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Overdue Bucket</th>
|
||||
<th class="num">Accounts</th>
|
||||
<th class="num">Outstanding</th>
|
||||
<th class="num col-out">Overdue Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (b of overdueAgeingBuckets; track b.label) {
|
||||
<tr>
|
||||
<td>{{ b.label }}</td>
|
||||
<td class="num">{{ b.count }}</td>
|
||||
<td class="num">₹{{ b.outstanding | number: '1.0-0' }}</td>
|
||||
<td class="num col-out">₹{{ b.overdueAmt | number: '1.0-0' }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">Overdue Accounts — Day-wise, Marked by SMA Stage</div>
|
||||
<div class="pg-table-scroll">
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account No</th>
|
||||
<th>Customer</th>
|
||||
<th>Branch</th>
|
||||
<th>Product</th>
|
||||
<th>Stage</th>
|
||||
<th class="num">Overdue Days</th>
|
||||
<th class="num">Outstanding</th>
|
||||
<th class="num col-out">Overdue Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (a of paged(overdueDaysAccounts); track a.accountNo) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">{{ a.accountNo }}</span>
|
||||
</td>
|
||||
<td>{{ a.customerName }}</td>
|
||||
<td>{{ a.branchName }}</td>
|
||||
<td>{{ a.productName }}</td>
|
||||
<td>
|
||||
<span [class]="badgeClass(stage(a))">{{ stageLabel(stage(a)) }}</span>
|
||||
</td>
|
||||
<td class="num">{{ a.overdueDays }}</td>
|
||||
<td class="num">₹{{ a.outstandingBalance | number: '1.0-0' }}</td>
|
||||
<td class="num col-out">₹{{ a.overdueAmount | number: '1.0-0' }}</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr>
|
||||
<td colspan="8" class="pg-empty">No overdue accounts in this branch.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@if (overdueDaysAccounts.length > pageSize) {
|
||||
<div class="pg-pagination">
|
||||
<span class="pg-pagination__info"
|
||||
>Showing {{ rangeStart(overdueDaysAccounts) }}–{{ rangeEnd(overdueDaysAccounts) }} of
|
||||
{{ overdueDaysAccounts.length }}</span
|
||||
>
|
||||
<div class="pg-pagination__controls">
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === 1"
|
||||
(click)="goToPage(currentPage - 1, overdueDaysAccounts)"
|
||||
>
|
||||
‹ Prev
|
||||
</button>
|
||||
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(overdueDaysAccounts) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === pageCount(overdueDaysAccounts)"
|
||||
(click)="goToPage(currentPage + 1, overdueDaysAccounts)"
|
||||
>
|
||||
Next ›
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ===================== 13 DAY-WISE OVERDRAWN REPORT ===================== -->
|
||||
@if (activeReport === 'daywise-overdrawn') {
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">
|
||||
Day-wise Overdrawn Report — Cash Credit / Overdraft / KCC Accounts ({{ overdrawnBreachCount }} of
|
||||
{{ overdrawnAccounts.length }} breaching Drawing Power)
|
||||
</div>
|
||||
<div class="pg-table-scroll">
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account No</th>
|
||||
<th>Customer</th>
|
||||
<th>Branch</th>
|
||||
<th>Product</th>
|
||||
<th class="num">Drawing Power</th>
|
||||
<th class="num">Outstanding</th>
|
||||
<th class="num col-out">Excess Over DP</th>
|
||||
<th class="num">Days Overdrawn</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (a of paged(overdrawnAccounts); track a.accountNo) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">{{ a.accountNo }}</span>
|
||||
</td>
|
||||
<td>{{ a.customerName }}</td>
|
||||
<td>{{ a.branchName }}</td>
|
||||
<td>{{ a.productName }}</td>
|
||||
<td class="num">₹{{ a.drawingPower | number: '1.0-0' }}</td>
|
||||
<td class="num">₹{{ a.outstandingBalance | number: '1.0-0' }}</td>
|
||||
<td class="num col-out">₹{{ excessOverDp(a) | number: '1.0-0' }}</td>
|
||||
<td class="num">{{ overdrawnBreachOf(a) ? a.overdueDays : 0 }}</td>
|
||||
<td>
|
||||
<span
|
||||
class="npa-badge"
|
||||
[class.npa-badge--standard]="!overdrawnBreachOf(a)"
|
||||
[class.npa-badge--substandard]="overdrawnBreachOf(a)"
|
||||
>
|
||||
{{ overdrawnBreachOf(a) ? 'DP Breached' : 'Within Limit' }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr>
|
||||
<td colspan="9" class="pg-empty">No Overdrawn accounts in this branch.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@if (overdrawnAccounts.length > pageSize) {
|
||||
<div class="pg-pagination">
|
||||
<span class="pg-pagination__info"
|
||||
>Showing {{ rangeStart(overdrawnAccounts) }}–{{ rangeEnd(overdrawnAccounts) }} of
|
||||
{{ overdrawnAccounts.length }}</span
|
||||
>
|
||||
<div class="pg-pagination__controls">
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === 1"
|
||||
(click)="goToPage(currentPage - 1, overdrawnAccounts)"
|
||||
>
|
||||
‹ Prev
|
||||
</button>
|
||||
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(overdrawnAccounts) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === pageCount(overdrawnAccounts)"
|
||||
(click)="goToPage(currentPage + 1, overdrawnAccounts)"
|
||||
>
|
||||
Next ›
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ===================== 14 AGRICULTURE / GOLD MARKET VALUE REPORT ===================== -->
|
||||
@if (activeReport === 'agri-gold-value') {
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">Agriculture / Gold Market Value Report — Current Security Value vs Loan</div>
|
||||
<div class="pg-table-scroll">
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account No</th>
|
||||
<th>Customer</th>
|
||||
<th>Branch</th>
|
||||
<th>Product</th>
|
||||
<th class="num">Outstanding</th>
|
||||
<th class="num">Collateral Value (At Sanction)</th>
|
||||
<th class="num">Market Value (Now)</th>
|
||||
<th class="num">Coverage %</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (a of paged(agriGoldAccounts); track a.accountNo) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">{{ a.accountNo }}</span>
|
||||
</td>
|
||||
<td>{{ a.customerName }}</td>
|
||||
<td>{{ a.branchName }}</td>
|
||||
<td>{{ a.productName }}</td>
|
||||
<td class="num">₹{{ a.outstandingBalance | number: '1.0-0' }}</td>
|
||||
<td class="num">₹{{ a.collateralValue | number: '1.0-0' }}</td>
|
||||
<td
|
||||
class="num"
|
||||
[class.col-in]="a.collateralMarketValue >= a.collateralValue"
|
||||
[class.col-out]="a.collateralMarketValue < a.collateralValue"
|
||||
>
|
||||
₹{{ a.collateralMarketValue | number: '1.0-0' }}
|
||||
</td>
|
||||
<td class="num">{{ coverageRatio(a) | number: '1.0-0' }}%</td>
|
||||
<td>
|
||||
<span
|
||||
class="npa-badge"
|
||||
[class.npa-badge--standard]="!undersecuredOf(a)"
|
||||
[class.npa-badge--substandard]="undersecuredOf(a)"
|
||||
>
|
||||
{{ undersecuredOf(a) ? 'Undersecured' : 'Adequate' }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr>
|
||||
<td colspan="9" class="pg-empty">No Agriculture / Gold accounts in this branch.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@if (agriGoldAccounts.length > pageSize) {
|
||||
<div class="pg-pagination">
|
||||
<span class="pg-pagination__info"
|
||||
>Showing {{ rangeStart(agriGoldAccounts) }}–{{ rangeEnd(agriGoldAccounts) }} of
|
||||
{{ agriGoldAccounts.length }}</span
|
||||
>
|
||||
<div class="pg-pagination__controls">
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === 1"
|
||||
(click)="goToPage(currentPage - 1, agriGoldAccounts)"
|
||||
>
|
||||
‹ Prev
|
||||
</button>
|
||||
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(agriGoldAccounts) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === pageCount(agriGoldAccounts)"
|
||||
(click)="goToPage(currentPage + 1, agriGoldAccounts)"
|
||||
>
|
||||
Next ›
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ===================== 15 EXCEPTION CHECK REPORT ===================== -->
|
||||
@if (activeReport === 'exception-check') {
|
||||
<div class="pg-card">
|
||||
<div class="pos-section-label">
|
||||
Exception Check — Security Value vs Loan ({{ exceptionAccounts.length }} accounts undersecured)
|
||||
</div>
|
||||
<p class="pg-sub npa-report-note">
|
||||
Every secured loan's current security market value is expected to stay above its outstanding balance. This lists
|
||||
the exceptions — where it doesn't — so recovery/credit can review before the next classification review.
|
||||
</p>
|
||||
<div class="pg-table-scroll">
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account No</th>
|
||||
<th>Customer</th>
|
||||
<th>Branch</th>
|
||||
<th>Product</th>
|
||||
<th>Stage</th>
|
||||
<th class="num">Outstanding</th>
|
||||
<th class="num">Market Value</th>
|
||||
<th class="num col-out">Shortfall</th>
|
||||
<th class="num">Coverage %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (a of paged(exceptionAccounts); track a.accountNo) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">{{ a.accountNo }}</span>
|
||||
</td>
|
||||
<td>{{ a.customerName }}</td>
|
||||
<td>{{ a.branchName }}</td>
|
||||
<td>{{ a.productName }}</td>
|
||||
<td>
|
||||
<span [class]="badgeClass(stage(a))">{{ stageLabel(stage(a)) }}</span>
|
||||
</td>
|
||||
<td class="num">₹{{ a.outstandingBalance | number: '1.0-0' }}</td>
|
||||
<td class="num">₹{{ a.collateralMarketValue | number: '1.0-0' }}</td>
|
||||
<td class="num col-out">₹{{ securityShortfall(a) | number: '1.0-0' }}</td>
|
||||
<td class="num">{{ coverageRatio(a) | number: '1.0-0' }}%</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr>
|
||||
<td colspan="9" class="pg-empty">No undersecured accounts in this branch.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@if (exceptionAccounts.length > pageSize) {
|
||||
<div class="pg-pagination">
|
||||
<span class="pg-pagination__info"
|
||||
>Showing {{ rangeStart(exceptionAccounts) }}–{{ rangeEnd(exceptionAccounts) }} of
|
||||
{{ exceptionAccounts.length }}</span
|
||||
>
|
||||
<div class="pg-pagination__controls">
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === 1"
|
||||
(click)="goToPage(currentPage - 1, exceptionAccounts)"
|
||||
>
|
||||
‹ Prev
|
||||
</button>
|
||||
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(exceptionAccounts) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="currentPage === pageCount(exceptionAccounts)"
|
||||
(click)="goToPage(currentPage + 1, exceptionAccounts)"
|
||||
>
|
||||
Next ›
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- ===================== Recovery / Collection Journey popup ===================== -->
|
||||
@if (showTimelineModal && selectedAccount; as a) {
|
||||
<div class="npa-timeline-backdrop" (click)="closeTimelineModal()">
|
||||
<div class="npa-timeline-modal" (click)="$event.stopPropagation()">
|
||||
<header class="npa-timeline-modal__head">
|
||||
<div class="npa-timeline-modal__title">
|
||||
<span class="npa-timeline-modal__eyebrow">Recovery / Collection Journey</span>
|
||||
<h2>{{ a.accountNo }} — {{ a.customerName }}</h2>
|
||||
<div class="npa-timeline-modal__meta">
|
||||
<span [class]="badgeClass(stage(a))">{{ stageLabel(stage(a)) }}</span>
|
||||
<span class="npa-timeline-modal__branch">{{ a.branchName }}</span>
|
||||
<span class="npa-timeline-modal__count">{{ a.collectionTimeline.length }} touchpoints</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="npa-timeline-modal__close" (click)="closeTimelineModal()" aria-label="Close">
|
||||
<fa-icon icon="times"></fa-icon>
|
||||
</button>
|
||||
</header>
|
||||
<div class="npa-timeline-modal__body">
|
||||
@if (a.collectionTimeline.length) {
|
||||
<ol class="npa-timeline">
|
||||
@for (e of a.collectionTimeline; track e.date + e.type) {
|
||||
<li [class]="'npa-timeline-item npa-timeline-item--' + timelineEventTone(e.type)">
|
||||
<span class="npa-timeline-item__icon"><fa-icon [icon]="timelineEventIcon(e.type)"></fa-icon></span>
|
||||
<div class="npa-timeline-item__body">
|
||||
<div class="npa-timeline-item__row">
|
||||
<span class="npa-timeline-item__type">{{ e.type }}</span>
|
||||
<span class="npa-timeline-item__date">{{ e.date }}</span>
|
||||
</div>
|
||||
<p class="npa-timeline-item__remarks">{{ e.remarks }}</p>
|
||||
<span class="npa-timeline-item__channel">{{ e.channel }}</span>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ol>
|
||||
} @else {
|
||||
<div class="npa-timeline-empty">
|
||||
<fa-icon icon="check-circle"></fa-icon>
|
||||
<p>No collection activity — this account has never gone overdue.</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="inv-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
|
||||
|
||||
Reference in New Issue
Block a user