feat: letter-mgmt module + digital UPI/IMPS/ATM-POS reports + header redesign

letter-mgmt (new module):
- Notice page: overdue loan list with filters, KPI strip, bulk actions,
  call disposition logging (Promise-to-Pay, Not Reachable, etc.), Speed
  Post dispatch dialog with consignment + post-office tracking,
  PDF preview + download, call-contact dialog with primary / alt /
  family / nominee numbers and per-contact disposition history.
- Certificates: Loan Interest, Share, Balance, Form 60 (no-PAN flow),
  Form 15G/H (auto age-based), Hypothecation, NOC - each with shared
  preview dialog (six tone variants) and jsPDF generator using a
  common letterhead / summary-grid / signature-seal helper.

digital:
- IMPS module: report (P2A/P2P/Aadhaar tabs) + entry form with
  MMID/mobile lookup, NPCI switch resolve-to-A/C+IFSC BANL flow,
  sender autocomplete, hide sender field for P2P/Aadhaar, charges +
  18% GST + waive checkbox, per-sender today-only history dialog.
- UPI report with app-mix tab and full transaction filtering.
- ATM/POS/ECOM hub with three ticket cards routing to today/status/cycle.
- NEFT/RTGS entry: sender-account autocomplete, charges + GST + waive,
  field reorder (sender before amount), NEFT cap / RTGS floor
  validation, History button opening per-sender today's transactions.
- NEFT/RTGS report: horizontal-bar trend leaderboard replacing tall bars.

shell + theme:
- Header redesigned with IBM Plex Sans 12/500 typography, 11-column grid
  per row, top-accent hover indicator, bordered cells via grid-gap.
- Live KPI ticker below menu (CASH, TXN TODAY, CLEARING IN/OUT, NPA,
  CASA, CD RATIO, RBI CIRC, REPO) with marquee scroll, pause-on-hover,
  brand-blue gradient, amber bottom strip, pulsing red LIVE chip.
- Sidebar 'KYC Management' -> 'KYC & ReKYC Management'.
- Letter Mgmt / certificate menu items wired with green icon hints for
  items that have a working page.

access-control:
- MFA card layout compacted; method header inlines back button + title.

icons:
- Register faTruck/TruckFast, faEllipsisV/H, faCommentDots.
- Add IBM Plex Sans Google Fonts import to index.html.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-05-19 10:09:06 +05:30
co-authored by Claude Opus 4.7
parent 4322f37c6d
commit 325228c514
138 changed files with 27473 additions and 3997 deletions
+81 -42
View File
@@ -55,6 +55,40 @@
<!-- Toolbar -->
<mifosx-toolbar [sidenav]="sidenav" (collapse)="toggleCollapse($event)"></mifosx-toolbar>
<!-- Live KPI ticker items — referenced twice below for seamless marquee loop -->
<ng-template #kpiTickerItems>
<span class="ti"><span class="ti-k">CASH</span><span class="ti-v amber">₹14,82,500</span></span>
<span class="ti-d">│</span>
<span class="ti">
<span class="ti-k">TXN TODAY</span>
<span class="ti-v">1,247</span>
<span class="ti-v up">↑ 8.2%</span>
</span>
<span class="ti-d">│</span>
<span class="ti"><span class="ti-k">CLEARING IN</span><span class="ti-v">42</span></span>
<span class="ti-d">│</span>
<span class="ti"><span class="ti-k">CLEARING OUT</span><span class="ti-v">38</span></span>
<span class="ti-d">│</span>
<span class="ti">
<span class="ti-k">NPA·GROSS</span>
<span class="ti-v amber">3.47%</span>
<span class="ti-v down">↑ 0.12</span>
</span>
<span class="ti-d">│</span>
<span class="ti"><span class="ti-k">CASA</span><span class="ti-v">58.2%</span></span>
<span class="ti-d">│</span>
<span class="ti"><span class="ti-k">CD RATIO</span><span class="ti-v">71.8%</span></span>
<span class="ti-d">│</span>
<span class="ti">
<span class="ti-k">RBI CIRC</span>
<span class="ti-v">DBR.AML.NO.4/14.01.001</span>
<span class="ti-v amber">NEW</span>
</span>
<span class="ti-d">│</span>
<span class="ti"><span class="ti-k">REPO</span><span class="ti-v">6.50%</span></span>
<span class="ti-d">│</span>
</ng-template>
<!-- Main Header — 2-Row Navigation -->
<div class="main-header">
<!-- Row 1 — 11 items (permission-gated) -->
@@ -170,6 +204,19 @@
</div>
</div>
<!-- LIVE KPI TICKER (below the menu — pauses on hover) -->
<div class="kpi-ticker" role="marquee" aria-label="Live key-performance ticker">
<span class="kpi-live">
<span class="kpi-live-dot"></span>
LIVE
</span>
<div class="kpi-track">
<!-- Render the item block twice so the marquee loops seamlessly. -->
<ng-container *ngTemplateOutlet="kpiTickerItems"></ng-container>
<ng-container *ngTemplateOutlet="kpiTickerItems"></ng-container>
</div>
</div>
<!-- Row 1 Menus -->
<mat-menu #institutionMenu="matMenu" [overlapTrigger]="false" class="nav-dropdown">
<button mat-menu-item routerLink="/clients" tabindex="0">
@@ -794,19 +841,8 @@
</mat-menu>
<mat-menu #ckycMenu="matMenu" [overlapTrigger]="false" class="nav-dropdown">
<button mat-menu-item tabindex="0"><fa-icon icon="camera" class="menu-item-icon"></fa-icon> Photo</button>
<button mat-menu-item tabindex="0"><fa-icon icon="pen" class="menu-item-icon"></fa-icon> Sign Upload</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="users" class="menu-item-icon"></fa-icon> Client Management
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="file-signature" class="menu-item-icon"></fa-icon> Signature Report
</button>
<button mat-menu-item tabindex="0" (click)="openCkycReportsDialog('RISK-REVIEW')">
<fa-icon icon="exclamation-triangle" class="menu-item-icon" style="color: #be185d"></fa-icon> Risk Category
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="chart-bar" class="menu-item-icon"></fa-icon> Risk Category and Turnover Profile
<button mat-menu-item routerLink="/ckyc" tabindex="0">
<fa-icon icon="id-card" class="menu-item-icon"></fa-icon> CKYC Management
</button>
<button mat-menu-item tabindex="0" (click)="openCkycReportsDialog('REKYC')">
<fa-icon icon="sync-alt" class="menu-item-icon" style="color: #be185d"></fa-icon> Re-KYC Report
@@ -868,15 +904,18 @@
<!-- Notices & Renewals -->
<div class="deposit-menu-group">
<div class="deposit-group-title">Notices &amp; Renewals</div>
<button mat-menu-item tabindex="0"><fa-icon icon="file-alt" class="menu-item-icon"></fa-icon> Notice</button>
<button mat-menu-item routerLink="/letter-mgmt/notice" tabindex="0">
<fa-icon icon="file-alt" class="menu-item-icon" style="color: #15803d"></fa-icon> Notice
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="sync" class="menu-item-icon"></fa-icon> Limit Renewal
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="file-invoice" class="menu-item-icon"></fa-icon> Loan Interest Certificate
<button mat-menu-item routerLink="/letter-mgmt/loan-interest-certificate" tabindex="0">
<fa-icon icon="file-invoice" class="menu-item-icon" style="color: #15803d"></fa-icon>
Loan Interest Certificate
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="certificate" class="menu-item-icon"></fa-icon> Share Certificate
<button mat-menu-item routerLink="/letter-mgmt/share-certificate" tabindex="0">
<fa-icon icon="certificate" class="menu-item-icon" style="color: #15803d"></fa-icon> Share Certificate
</button>
</div>
<!-- Printing -->
@@ -896,25 +935,30 @@
<!-- Certificates -->
<div class="deposit-menu-group">
<div class="deposit-group-title">Certificates</div>
<button mat-menu-item tabindex="0">
<fa-icon icon="balance-scale" class="menu-item-icon"></fa-icon> Balance Certificate
<button mat-menu-item routerLink="/letter-mgmt/balance-certificate" tabindex="0">
<fa-icon icon="balance-scale" class="menu-item-icon" style="color: #15803d"></fa-icon>
Balance Certificate
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="file-signature" class="menu-item-icon"></fa-icon> Form 60
<button mat-menu-item routerLink="/letter-mgmt/form-60" tabindex="0">
<fa-icon icon="file-signature" class="menu-item-icon" style="color: #15803d"></fa-icon> Form 60
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="file-signature" class="menu-item-icon"></fa-icon> Form 15G and H
<button mat-menu-item routerLink="/letter-mgmt/form-15gh" tabindex="0">
<fa-icon icon="file-signature" class="menu-item-icon" style="color: #15803d"></fa-icon> Form 15G and H
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="file-alt" class="menu-item-icon"></fa-icon> Hypothication Certificate
<button mat-menu-item routerLink="/letter-mgmt/hypothecation-certificate" tabindex="0">
<fa-icon icon="file-alt" class="menu-item-icon" style="color: #15803d"></fa-icon>
Hypothecation Certificate
</button>
</div>
<!-- Others -->
<div class="deposit-menu-group">
<div class="deposit-group-title">Others</div>
<button mat-menu-item tabindex="0"><fa-icon icon="id-card" class="menu-item-icon"></fa-icon> NOC</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="fingerprint" class="menu-item-icon"></fa-icon> Rekyc Letter Pre-Post
<button mat-menu-item routerLink="/letter-mgmt/noc" tabindex="0">
<fa-icon icon="id-card" class="menu-item-icon" style="color: #15803d"></fa-icon> NOC
</button>
<button mat-menu-item routerLink="/kyc-management" tabindex="0">
<fa-icon icon="fingerprint" class="menu-item-icon" style="color: #15803d"></fa-icon>
KYC &amp; ReKYC Management
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="money-bill-wave" class="menu-item-icon"></fa-icon> Digital Transaction UTR
@@ -947,27 +991,22 @@
</mat-menu>
<mat-menu #digitalMenu="matMenu" [overlapTrigger]="false" class="nav-dropdown">
<button mat-menu-item routerLink="/digital/neft-rtgs" tabindex="0">
<button mat-menu-item routerLink="/digital/neft-rtgs-report" tabindex="0">
<fa-icon icon="exchange" class="menu-item-icon"></fa-icon> NEFT / RTGS
</button>
<button mat-menu-item routerLink="/digital/neft-rtgs-report" tabindex="0">
<fa-icon icon="chart-line" class="menu-item-icon"></fa-icon> NEFT / RTGS Report
<button mat-menu-item routerLink="/digital/imps-report" tabindex="0">
<fa-icon icon="bolt" class="menu-item-icon"></fa-icon> IMPS
</button>
<button mat-menu-item tabindex="0"><fa-icon icon="bolt" class="menu-item-icon"></fa-icon> IMPS / BANL</button>
<button mat-menu-item tabindex="0"><fa-icon icon="mobile-alt" class="menu-item-icon"></fa-icon> UPI</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="credit-card" class="menu-item-icon"></fa-icon> ATM / POS / ECOM
<button mat-menu-item routerLink="/digital/upi-report" tabindex="0">
<fa-icon icon="mobile-alt" class="menu-item-icon"></fa-icon> UPI Reports
</button>
<button mat-menu-item routerLink="/digital/atm-pos-ecom" tabindex="0">
<fa-icon icon="credit-card" class="menu-item-icon"></fa-icon> ATM / POS / ECOM Reports
</button>
<button mat-menu-item tabindex="0"><fa-icon icon="sync" class="menu-item-icon"></fa-icon> NACH</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="file-signature" class="menu-item-icon"></fa-icon> Mandate
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="list-alt" class="menu-item-icon"></fa-icon> Transaction Register Cycle Wise
</button>
<button mat-menu-item tabindex="0">
<fa-icon icon="info-circle" class="menu-item-icon"></fa-icon> ATM TXN Status
</button>
</mat-menu>
<!-- RBI Mega Menu -->
+305 -39
View File
@@ -106,8 +106,24 @@ $brand: #1353a0;
$brand-light: #eaf1fc;
$brand-hover: #ddeafb;
$gray-200: #e2e8f0;
$gray-400: #94a3b8;
$gray-500: #64748b;
$gray-700: #334155;
/* ============================================================
Main header (top 2-row navigation)
--------------------------------------------------------------
Redesigned 2026 — clean, modern enterprise SaaS feel:
• Both rows live on the same white surface separated only by a
hairline; r2 has a barely-there blue-50 wash so frequent vs
secondary menus read at a glance without dark/light contrast.
• Items are now equal-width "tabs" with NO vertical dividers
between them (the old cell borders made it look spreadsheet-y).
• Hover / active = a 3 px brand-coloured TOP bar + brand text +
coloured icon. Reads instantly without colour-flooding the row.
• Icons larger (12.5 px) and full-opacity always — easier to scan
during demos. Caret is subtle and rotates on open.
============================================================ */
.main-header {
background: #fff;
border-bottom: 2.5px solid $brand;
@@ -119,48 +135,70 @@ $gray-700: #334155;
}
.nav-row {
height: 38px;
display: flex;
height: 44px;
display: grid;
grid-template-columns: repeat(11, minmax(0, 1fr));
align-items: stretch;
justify-content: space-between;
overflow: visible;
position: relative;
/* Grid container background shows through the 1 px gap as crisp 1 px borders
on every side of every cell — no doubled-up 2 px lines between adjacent
items, perfect 1 px outer frame too. */
gap: 1px;
background: $gray-200;
border: 1px solid $gray-200;
}
.r1 {
.r1 .ni {
background: #fff;
border-bottom: 1px solid $gray-200;
}
.r2 {
.r2 .ni {
background: #f8fafc;
}
// ===== Nav Item =====
// ===== Nav Item — modern tab style =====
// Typography spec — same family / size / weight / color for BOTH rows.
.ni {
position: relative;
display: flex;
display: inline-flex;
align-items: center;
gap: 4px;
flex: 1;
justify-content: center;
gap: 7px;
height: 100%;
padding: 0 10px;
cursor: pointer;
white-space: nowrap;
color: $gray-700;
font-size: 11px;
font-family:
'IBM Plex Sans',
-apple-system,
sans-serif;
font-size: 12px;
font-weight: 500;
color: #0a1a2e;
line-height: 1.3;
letter-spacing: 0.01em;
transition:
background 0.12s,
color 0.12s;
user-select: none;
border-right: 1px solid $gray-200;
text-decoration: none;
font-family: 'DM Sans', Roboto, sans-serif;
user-select: none;
transition:
background 0.15s ease,
color 0.15s ease,
box-shadow 0.15s ease;
border-radius: 0;
&:last-child {
border-right: none;
/* 3px accent strip that fills on hover / active (uses ::before so we
don't reflow the row when toggling). */
&::before {
content: '';
position: absolute;
left: 8px;
right: 8px;
top: 0;
height: 3px;
background: transparent;
border-radius: 0 0 3px 3px;
transition: background 0.15s ease;
}
&:hover {
@@ -168,48 +206,276 @@ $gray-700: #334155;
color: $brand;
}
&:hover::before {
background: $brand;
}
&.active {
background: $brand-light;
color: $brand;
font-weight: 600;
background: $brand-light;
}
&.active::before {
content: '';
position: absolute;
left: 0;
top: 18%;
bottom: 18%;
width: 2.5px;
background: $brand;
border-radius: 0 2px 2px 0;
}
&:focus-visible {
outline: 2px solid $brand;
outline-offset: -2px;
}
}
.ni-ico {
font-size: 11px;
opacity: 0.55;
width: 12px;
height: 12px;
font-size: 12px;
color: $gray-500;
flex-shrink: 0;
transition: color 0.15s ease;
.ni:hover &,
.ni.active & {
opacity: 1;
color: $brand;
}
}
.ni-caret {
font-size: 8px;
opacity: 0.3;
transition:
transform 0.18s,
opacity 0.18s;
width: 7px;
height: 7px;
font-size: 7px;
color: $gray-400;
flex-shrink: 0;
transition:
transform 0.18s ease,
color 0.18s ease;
.ni:hover & {
opacity: 0.7;
.ni:hover &,
.ni.active & {
color: $brand;
}
}
@media (width <= 1200px) {
.ni {
padding: 0 8px;
gap: 5px;
}
}
@media (width <= 980px) {
.ni {
padding: 0 6px;
gap: 4px;
}
}
/* ============================================================
Live KPI ticker — sits directly under the 2-row menu
============================================================ */
.kpi-ticker {
position: relative;
display: flex;
align-items: center;
height: 30px;
/* Premium rich brand-blue gradient — matches the CKYC banner you saw in the
screenshot, anchoring the ticker into the same brand surface family.
Same hues, same direction, same depth = visual cohesion across the app. */
background: linear-gradient(135deg, #0b1e3d 0%, #1e3a8a 35%, #1d4ed8 65%, #1e40af 100%);
color: #fff;
overflow: hidden;
font-family:
'IBM Plex Sans',
-apple-system,
sans-serif;
font-size: 11.5px;
line-height: 1;
user-select: none;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 10%);
/* Thin amber accent strip at the bottom — classic financial-ticker premium
touch, picks up the same amber used inside the value chips. */
border-bottom: 1.5px solid #fbbf24;
}
/* Slow-moving sheen overlay that gives the band a subtle "live" pulse without
stealing focus from the data. Pointer-events: none so it never blocks hover
pausing on the track. */
.kpi-ticker::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
115deg,
transparent 0%,
transparent 38%,
rgb(255 255 255 / 8%) 50%,
transparent 62%,
transparent 100%
);
background-size: 300% 100%;
animation: kpi-sheen 8s linear infinite;
pointer-events: none;
z-index: 1;
}
.kpi-ticker:hover::before {
animation-play-state: paused;
}
@keyframes kpi-sheen {
from {
background-position: 200% 0;
}
to {
background-position: -100% 0;
}
}
/* Sticky "LIVE" badge — a punchy red chip so the eye finds it instantly on
the dark blue band. Classic financial-ticker vibe. */
.kpi-live {
position: sticky;
left: 0;
z-index: 3;
display: inline-flex;
align-items: center;
gap: 7px;
height: 100%;
padding: 0 14px;
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
font-weight: 800;
letter-spacing: 0.18em;
font-size: 10px;
color: #fff;
text-transform: uppercase;
border-right: 1px solid rgb(255 255 255 / 18%);
box-shadow:
8px 0 14px -8px rgb(11 30 61 / 60%),
inset 0 1px 0 rgb(255 255 255 / 16%);
flex-shrink: 0;
text-shadow: 0 1px 0 rgb(0 0 0 / 25%);
}
.kpi-live-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #fef08a; /* bright yellow dot on red — high-contrast attention */
box-shadow:
0 0 0 0 rgb(254 240 138 / 80%),
0 0 6px 1px rgb(254 240 138 / 60%);
animation: kpi-pulse 1.3s ease-in-out infinite;
}
@keyframes kpi-pulse {
0% {
box-shadow:
0 0 0 0 rgb(254 240 138 / 70%),
0 0 6px 1px rgb(254 240 138 / 60%);
transform: scale(1);
}
70% {
box-shadow:
0 0 0 8px rgb(254 240 138 / 0%),
0 0 6px 1px rgb(254 240 138 / 0%);
transform: scale(1.18);
}
100% {
box-shadow:
0 0 0 0 rgb(254 240 138 / 0%),
0 0 6px 1px rgb(254 240 138 / 30%);
transform: scale(1);
}
}
/* Scrolling track — rendered with the item list twice so the loop is seamless.
z-index keeps the data above the sheen overlay. */
.kpi-track {
position: relative;
z-index: 2;
display: inline-flex;
align-items: center;
gap: 0;
white-space: nowrap;
width: max-content;
padding-left: 18px;
animation: kpi-scroll 75s linear infinite;
}
.kpi-ticker:hover .kpi-track,
.kpi-ticker:focus-within .kpi-track {
animation-play-state: paused;
}
@keyframes kpi-scroll {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
/* Individual ticker item — key + one or more values */
.ti {
display: inline-flex;
align-items: baseline;
gap: 8px;
padding: 0 14px;
position: relative;
z-index: 2; /* above the sheen overlay */
}
.ti-k {
font-size: 10px;
font-weight: 700;
letter-spacing: 0.14em;
text-transform: uppercase;
color: rgb(255 255 255 / 62%);
}
.ti-v {
font-size: 12px;
font-weight: 700;
color: #fff;
font-variant-numeric: tabular-nums;
letter-spacing: 0.02em;
text-shadow: 0 1px 0 rgb(0 0 0 / 20%);
&.amber {
/* Bright gold value — financial-ticker classic, pops on deep blue */
color: #fcd34d;
text-shadow:
0 1px 0 rgb(0 0 0 / 25%),
0 0 8px rgb(252 211 77 / 30%);
}
&.up {
color: #4ade80; /* green-400 — bright on dark blue */
text-shadow: 0 1px 0 rgb(0 0 0 / 25%);
}
&.down {
color: #fca5a5; /* red-300 — bright on dark blue */
text-shadow: 0 1px 0 rgb(0 0 0 / 25%);
}
}
/* Vertical pipe separator between items */
.ti-d {
position: relative;
z-index: 2;
color: rgb(255 255 255 / 26%);
font-weight: 300;
font-size: 14px;
padding: 0 2px;
}
.menu-item-icon {
margin-right: 8px;
width: 16px;
+3
View File
@@ -82,6 +82,9 @@ export class ShellComponent implements OnInit, OnDestroy {
rbiMenuOpen = false;
rbiSearch = '';
/* Live KPI ticker — markup is static inside the template; the marquee
animation, LIVE badge, and pause-on-hover handle the live feel. */
matchesSubLedgerSearch(label: string): boolean {
if (!this.subLedgerSearch) return true;
return label.toLowerCase().includes(this.subLedgerSearch.toLowerCase());
@@ -68,14 +68,14 @@
<mat-list-item
[routerLink]="['/kyc-management']"
[matTooltipPosition]="tooltipPosition"
matTooltip="KYC Management"
matTooltip="KYC & ReKYC Management"
routerLinkActive="active-menu"
[routerLinkActiveOptions]="{ exact: false }"
>
<mat-icon matListIcon>
<fa-icon icon="user-shield" size="sm"></fa-icon>
</mat-icon>
<a matLine>KYC Management</a>
<a matLine>KYC &amp; ReKYC Management</a>
</mat-list-item>
<mat-list-item
[routerLink]="['/bank-calendar']"