feat: client extra fields + KYC home-visit & video-KYC dialogs
- Add Education Level, Degree/Qualification, Religion, Social Category dropdowns (individual clients) with dependent filtering on the create/edit/preview/view flows - Add Agriculture Income & Non-Agriculture Income fields under Financial & Classification - Gate Save with a Verify Client alert dialog when sanctions screening is not yet performed - Trim Office Name and CKYC Number columns from clients list; widen table to fill container - Remove DIP/Screening log IDs from preview and personal-data tabs - Rename "Branch Visit" to "Home Visit" across KYC management - Wire Take Action: open dedicated dialogs for Schedule Home Visit (officer + datetime) and Send Video KYC link (channels + officer + 48h expiry + session preview) - Migrate Signatory and Guardian image dialogs to inject() for prefer-inject lint rule Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
d72e969dc3
commit
52e3395345
@@ -77,15 +77,24 @@
|
||||
|
||||
<div class="km-filters">
|
||||
<select class="km-fsel">
|
||||
<option>All Risk</option><option>Low</option><option>Mid</option><option>High</option>
|
||||
<option>All Risk</option>
|
||||
<option>Low</option>
|
||||
<option>Mid</option>
|
||||
<option>High</option>
|
||||
</select>
|
||||
<select class="km-fsel">
|
||||
<option>All States</option><option>Alert Window</option><option>Debit Freeze</option>
|
||||
<option>Inoperative</option><option>Dormant</option>
|
||||
<option>All States</option>
|
||||
<option>Alert Window</option>
|
||||
<option>Debit Freeze</option>
|
||||
<option>Inoperative</option>
|
||||
<option>Dormant</option>
|
||||
</select>
|
||||
<select class="km-fsel">
|
||||
<option>All Notices</option><option>Notice 1 Pending</option><option>Notice 2 Pending</option>
|
||||
<option>Notice 3 Pending</option><option>All 3 Sent</option>
|
||||
<option>All Notices</option>
|
||||
<option>Notice 1 Pending</option>
|
||||
<option>Notice 2 Pending</option>
|
||||
<option>Notice 3 Pending</option>
|
||||
<option>All 3 Sent</option>
|
||||
</select>
|
||||
<input class="km-finp" type="text" placeholder="Search name or account..." />
|
||||
<button class="km-btn km-btn-t" (click)="toast('Filters applied')">Apply</button>
|
||||
@@ -100,8 +109,15 @@
|
||||
<table class="km-tbl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Customer</th><th>Risk</th><th>Expiry Date</th><th>Days Left</th>
|
||||
<th>Notices</th><th>State</th><th>Pending Action</th><th>Next Stage</th><th></th>
|
||||
<th>Customer</th>
|
||||
<th>Risk</th>
|
||||
<th>Expiry Date</th>
|
||||
<th>Days Left</th>
|
||||
<th>Notices</th>
|
||||
<th>State</th>
|
||||
<th>Pending Action</th>
|
||||
<th>Next Stage</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -111,7 +127,9 @@
|
||||
<div class="km-an">{{ row.name }}</div>
|
||||
<div class="km-ai">{{ row.account }}</div>
|
||||
</td>
|
||||
<td><span class="km-b" [ngClass]="riskClass(row.risk)">{{ row.riskLabel.split(' ')[0] }}</span></td>
|
||||
<td>
|
||||
<span class="km-b" [ngClass]="riskClass(row.risk)">{{ row.riskLabel.split(' ')[0] }}</span>
|
||||
</td>
|
||||
<td>{{ row.expiry }}</td>
|
||||
<td>
|
||||
<div class="km-pbar">
|
||||
@@ -125,10 +143,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-bl">{{ row.noticesSent }}/3</span></td>
|
||||
<td><span class="km-sp" [ngClass]="stateClass(row.state)">{{ stateLabel(row.state) }}</span></td>
|
||||
<td><span class="km-b km-b-am">{{ row.noticePending }}</span></td>
|
||||
<td><span class="km-b km-b-or">{{ row.nextStage }}</span></td>
|
||||
<td>
|
||||
<span class="km-b km-b-bl">{{ row.noticesSent }}/3</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="km-sp" [ngClass]="stateClass(row.state)">{{ stateLabel(row.state) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="km-b km-b-am">{{ row.noticePending }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="km-b km-b-or">{{ row.nextStage }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="km-btn km-btn-ot" (click)="$event.stopPropagation(); openModal(row.id)">View</button>
|
||||
</td>
|
||||
@@ -165,7 +191,10 @@
|
||||
<div class="km-cb">
|
||||
<div class="km-ntl">
|
||||
<div class="km-nt">
|
||||
<div class="km-nd-col"><div class="km-nd km-nd1">1</div><div class="km-nl"></div></div>
|
||||
<div class="km-nd-col">
|
||||
<div class="km-nd km-nd1">1</div>
|
||||
<div class="km-nl"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="km-nh">Notice 1 — Alert window opens</div>
|
||||
<div class="km-ns">31 March 2027 · Auto-scheduled · <span class="km-ok">✓ Delivered</span></div>
|
||||
@@ -176,7 +205,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-nt">
|
||||
<div class="km-nd-col"><div class="km-nd km-nd2">2</div><div class="km-nl"></div></div>
|
||||
<div class="km-nd-col">
|
||||
<div class="km-nd km-nd2">2</div>
|
||||
<div class="km-nl"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="km-nh">Notice 2 — Follow-up</div>
|
||||
<div class="km-ns">10 April 2027 · +10 days · <span class="km-pending">⏳ Pending</span></div>
|
||||
@@ -189,7 +221,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-nt">
|
||||
<div class="km-nd-col"><div class="km-nd km-nd3">3</div><div class="km-nl"></div></div>
|
||||
<div class="km-nd-col">
|
||||
<div class="km-nd km-nd3">3</div>
|
||||
<div class="km-nl"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="km-nh">Notice 3 — Final notice</div>
|
||||
<div class="km-ns">20 April 2027 · +20 days · <span class="km-fail">✗ Not dispatched</span></div>
|
||||
@@ -198,16 +233,23 @@
|
||||
<span class="km-cp km-cp-mail">Email</span>
|
||||
<span class="km-cp km-cp-ivr">IVR</span>
|
||||
<span class="km-cp km-cp-post">Reg. Post</span>
|
||||
<span class="km-cp km-cp-vis">Branch Visit</span>
|
||||
<span class="km-cp km-cp-vis">Home Visit</span>
|
||||
</div>
|
||||
<div class="km-row-actions">
|
||||
<button class="km-btn km-btn-t" (click)="toast('Notice 3 scheduled for 20 Apr 2027')">Schedule Notice 3</button>
|
||||
<button class="km-btn km-btn-ot" (click)="toast('Video KYC link added to Notice 3')">+ Video KYC Link</button>
|
||||
<button class="km-btn km-btn-t" (click)="toast('Notice 3 scheduled for 20 Apr 2027')">
|
||||
Schedule Notice 3
|
||||
</button>
|
||||
<button class="km-btn km-btn-ot" (click)="toast('Video KYC link added to Notice 3')">
|
||||
+ Video KYC Link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-nt">
|
||||
<div class="km-nd-col"><div class="km-nd km-ndf">!</div><div class="km-nl"></div></div>
|
||||
<div class="km-nd-col">
|
||||
<div class="km-nd km-ndf">!</div>
|
||||
<div class="km-nl"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="km-nh km-warn">Debit Freeze — if no action</div>
|
||||
<div class="km-ns">30 April 2027 · Auto-triggered on expiry</div>
|
||||
@@ -219,7 +261,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-nt">
|
||||
<div class="km-nd-col"><div class="km-nd km-ndi">!</div><div class="km-nl"></div></div>
|
||||
<div class="km-nd-col">
|
||||
<div class="km-nd km-ndi">!</div>
|
||||
<div class="km-nl"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="km-nh km-warn-o">Inoperative — +60 days</div>
|
||||
<div class="km-ns">30 June 2027 · No compliance</div>
|
||||
@@ -270,7 +315,7 @@
|
||||
</div>
|
||||
<div class="km-channel" (click)="toast('Branch visit toggled')">
|
||||
<div class="km-channel-i">🏦</div>
|
||||
<div class="km-channel-n">Branch Visit</div>
|
||||
<div class="km-channel-n">Home Visit</div>
|
||||
<div class="km-channel-d">Manual</div>
|
||||
</div>
|
||||
<div class="km-channel" (click)="toast('Video KYC toggled')">
|
||||
@@ -287,17 +332,28 @@
|
||||
<div class="km-ct">India Post Notice</div>
|
||||
</div>
|
||||
<div class="km-cb">
|
||||
<div class="km-mi"><div class="km-ml">Dispatch Date</div><div class="km-mv">10 April 2027</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Reg. Post Docket No.</div><div class="km-mv km-mono">RP-BPL-20270410-443</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Status</div><div class="km-mv"><span class="km-b km-b-bl">In Transit</span></div></div>
|
||||
<button class="km-btn km-btn-g km-w" (click)="toast('Tracking RP-BPL-20270410-443 on India Post...')">Track Delivery</button>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Dispatch Date</div>
|
||||
<div class="km-mv">10 April 2027</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Reg. Post Docket No.</div>
|
||||
<div class="km-mv km-mono">RP-BPL-20270410-443</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Status</div>
|
||||
<div class="km-mv"><span class="km-b km-b-bl">In Transit</span></div>
|
||||
</div>
|
||||
<button class="km-btn km-btn-g km-w" (click)="toast('Tracking RP-BPL-20270410-443 on India Post...')">
|
||||
Track Delivery
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="km-card">
|
||||
<div class="km-ch">
|
||||
<div class="km-ci km-ci-t"><fa-icon icon="building"></fa-icon></div>
|
||||
<div class="km-ct">Branch Visit</div>
|
||||
<div class="km-ct">Home Visit</div>
|
||||
</div>
|
||||
<div class="km-cb">
|
||||
<div class="km-ml">Scheduled Date</div>
|
||||
@@ -334,15 +390,26 @@
|
||||
|
||||
<div class="km-filters">
|
||||
<select class="km-fsel">
|
||||
<option>All Channels</option><option>SMS</option><option>Email</option><option>IVR</option>
|
||||
<option>Reg. Post</option><option>Branch Visit</option><option>Video KYC</option>
|
||||
<option>All Channels</option>
|
||||
<option>SMS</option>
|
||||
<option>Email</option>
|
||||
<option>IVR</option>
|
||||
<option>Reg. Post</option>
|
||||
<option>Home Visit</option>
|
||||
<option>Video KYC</option>
|
||||
</select>
|
||||
<select class="km-fsel">
|
||||
<option>All Statuses</option><option>Delivered</option><option>In Transit</option>
|
||||
<option>Pending</option><option>Failed</option>
|
||||
<option>All Statuses</option>
|
||||
<option>Delivered</option>
|
||||
<option>In Transit</option>
|
||||
<option>Pending</option>
|
||||
<option>Failed</option>
|
||||
</select>
|
||||
<select class="km-fsel">
|
||||
<option>All Notice Nos.</option><option>Notice 1</option><option>Notice 2</option><option>Notice 3</option>
|
||||
<option>All Notice Nos.</option>
|
||||
<option>Notice 1</option>
|
||||
<option>Notice 2</option>
|
||||
<option>Notice 3</option>
|
||||
</select>
|
||||
<input class="km-finp" type="text" placeholder="Search account, name or reference..." />
|
||||
<button class="km-btn km-btn-t" (click)="toast('Filters applied')">Apply</button>
|
||||
@@ -357,15 +424,24 @@
|
||||
<table class="km-tbl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th><th>Account / Customer</th><th>Notice</th><th>Channel</th>
|
||||
<th>Dispatched</th><th>Reference / Docket</th><th>Delivery</th>
|
||||
<th>Client Action</th><th>Officer</th>
|
||||
<th>#</th>
|
||||
<th>Account / Customer</th>
|
||||
<th>Notice</th>
|
||||
<th>Channel</th>
|
||||
<th>Dispatched</th>
|
||||
<th>Reference / Docket</th>
|
||||
<th>Delivery</th>
|
||||
<th>Client Action</th>
|
||||
<th>Officer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr (click)="openModal('rajesh')">
|
||||
<td class="km-num">001</td>
|
||||
<td><div class="km-an">Rajesh K. Sharma</div><div class="km-ai">ACC-BPL-2024-00847</div></td>
|
||||
<td>
|
||||
<div class="km-an">Rajesh K. Sharma</div>
|
||||
<div class="km-ai">ACC-BPL-2024-00847</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-bl">Notice 1</span></td>
|
||||
<td>SMS + Email</td>
|
||||
<td>31 Mar 2027</td>
|
||||
@@ -376,7 +452,10 @@
|
||||
</tr>
|
||||
<tr (click)="openModal('rajesh')">
|
||||
<td class="km-num">002</td>
|
||||
<td><div class="km-an">Rajesh K. Sharma</div><div class="km-ai">ACC-BPL-2024-00847</div></td>
|
||||
<td>
|
||||
<div class="km-an">Rajesh K. Sharma</div>
|
||||
<div class="km-ai">ACC-BPL-2024-00847</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-am">Notice 2</span></td>
|
||||
<td>Reg. Post + IVR</td>
|
||||
<td>10 Apr 2027</td>
|
||||
@@ -387,7 +466,10 @@
|
||||
</tr>
|
||||
<tr (click)="openModal('priya')">
|
||||
<td class="km-num">003</td>
|
||||
<td><div class="km-an">Priya Malhotra</div><div class="km-ai">ACC-BPL-2021-00231</div></td>
|
||||
<td>
|
||||
<div class="km-an">Priya Malhotra</div>
|
||||
<div class="km-ai">ACC-BPL-2021-00231</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-bl">Notice 1</span></td>
|
||||
<td>SMS + Email</td>
|
||||
<td>10 Mar 2027</td>
|
||||
@@ -398,7 +480,10 @@
|
||||
</tr>
|
||||
<tr (click)="openModal('priya')">
|
||||
<td class="km-num">004</td>
|
||||
<td><div class="km-an">Priya Malhotra</div><div class="km-ai">ACC-BPL-2021-00231</div></td>
|
||||
<td>
|
||||
<div class="km-an">Priya Malhotra</div>
|
||||
<div class="km-ai">ACC-BPL-2021-00231</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-am">Notice 2</span></td>
|
||||
<td>Reg. Post</td>
|
||||
<td>20 Mar 2027</td>
|
||||
@@ -409,9 +494,12 @@
|
||||
</tr>
|
||||
<tr (click)="openModal('priya')">
|
||||
<td class="km-num">005</td>
|
||||
<td><div class="km-an">Priya Malhotra</div><div class="km-ai">ACC-BPL-2021-00231</div></td>
|
||||
<td>
|
||||
<div class="km-an">Priya Malhotra</div>
|
||||
<div class="km-ai">ACC-BPL-2021-00231</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-or">Notice 3</span></td>
|
||||
<td>Branch Visit</td>
|
||||
<td>Home Visit</td>
|
||||
<td>30 Mar 2027</td>
|
||||
<td><span class="km-ref">VIS-BPL-20270330-012</span></td>
|
||||
<td><span class="km-del km-d-ok">✓ Done</span></td>
|
||||
@@ -420,7 +508,10 @@
|
||||
</tr>
|
||||
<tr (click)="openModal('suresh')">
|
||||
<td class="km-num">006</td>
|
||||
<td><div class="km-an">Suresh Patel</div><div class="km-ai">ACC-BPL-2019-00112</div></td>
|
||||
<td>
|
||||
<div class="km-an">Suresh Patel</div>
|
||||
<div class="km-ai">ACC-BPL-2019-00112</div>
|
||||
</td>
|
||||
<td><span class="km-b km-b-or">Notice 3</span></td>
|
||||
<td>Video KYC</td>
|
||||
<td>5 Feb 2027</td>
|
||||
@@ -454,19 +545,29 @@
|
||||
|
||||
<div class="km-sc-row">
|
||||
<div class="km-sc km-sc-ac" (click)="toast('Filtering: Active')">
|
||||
<div class="km-sc-l">Active</div><div class="km-sc-n">1,847</div><div class="km-sc-d">KYC valid</div>
|
||||
<div class="km-sc-l">Active</div>
|
||||
<div class="km-sc-n">1,847</div>
|
||||
<div class="km-sc-d">KYC valid</div>
|
||||
</div>
|
||||
<div class="km-sc km-sc-al" (click)="toast('Filtering: Alert window')">
|
||||
<div class="km-sc-l">Alert Window</div><div class="km-sc-n">47</div><div class="km-sc-d">Expiring < 30d</div>
|
||||
<div class="km-sc-l">Alert Window</div>
|
||||
<div class="km-sc-n">47</div>
|
||||
<div class="km-sc-d">Expiring < 30d</div>
|
||||
</div>
|
||||
<div class="km-sc km-sc-fr" (click)="toast('Filtering: Debit Freeze')">
|
||||
<div class="km-sc-l">Debit Freeze</div><div class="km-sc-n">23</div><div class="km-sc-d">Debits blocked</div>
|
||||
<div class="km-sc-l">Debit Freeze</div>
|
||||
<div class="km-sc-n">23</div>
|
||||
<div class="km-sc-d">Debits blocked</div>
|
||||
</div>
|
||||
<div class="km-sc km-sc-in" (click)="toast('Filtering: Inoperative')">
|
||||
<div class="km-sc-l">Inoperative</div><div class="km-sc-n">8</div><div class="km-sc-d">All txns blocked</div>
|
||||
<div class="km-sc-l">Inoperative</div>
|
||||
<div class="km-sc-n">8</div>
|
||||
<div class="km-sc-d">All txns blocked</div>
|
||||
</div>
|
||||
<div class="km-sc km-sc-do" (click)="toast('Filtering: Dormant')">
|
||||
<div class="km-sc-l">Dormant</div><div class="km-sc-n">3</div><div class="km-sc-d">RBI reportable</div>
|
||||
<div class="km-sc-l">Dormant</div>
|
||||
<div class="km-sc-n">3</div>
|
||||
<div class="km-sc-d">RBI reportable</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -478,20 +579,28 @@
|
||||
</div>
|
||||
<div class="km-cb-flush">
|
||||
<div class="km-rule">
|
||||
<div class="km-rule-h"><span class="km-rule-t">Active → Debit Freeze</span><span class="km-b km-b-gr">Enabled</span></div>
|
||||
<div class="km-rule-d">KYC expires + 3 notices sent + no response → debits blocked, credits allowed</div>
|
||||
<div class="km-rule-h">
|
||||
<span class="km-rule-t">Active → Debit Freeze</span><span class="km-b km-b-gr">Enabled</span>
|
||||
</div>
|
||||
<div class="km-rule-d">
|
||||
KYC expires + 3 notices sent + no response → debits blocked, credits allowed
|
||||
</div>
|
||||
<div class="km-rule-tags">
|
||||
<span class="km-b km-b-gy">Window: 31 Mar – 30 Apr</span>
|
||||
<span class="km-b km-b-gy">3/3 notices</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-rule">
|
||||
<div class="km-rule-h"><span class="km-rule-t">Debit Freeze → Inoperative</span><span class="km-b km-b-gr">Enabled</span></div>
|
||||
<div class="km-rule-h">
|
||||
<span class="km-rule-t">Debit Freeze → Inoperative</span><span class="km-b km-b-gr">Enabled</span>
|
||||
</div>
|
||||
<div class="km-rule-d">+60 days from expiry, still unresolved → all transactions blocked</div>
|
||||
<div class="km-rule-tags"><span class="km-b km-b-gy">Apr 30 – Jun 30</span></div>
|
||||
</div>
|
||||
<div class="km-rule km-rule-last">
|
||||
<div class="km-rule-h"><span class="km-rule-t">Inoperative → Dormant</span><span class="km-b km-b-gr">Enabled</span></div>
|
||||
<div class="km-rule-h">
|
||||
<span class="km-rule-t">Inoperative → Dormant</span><span class="km-b km-b-gr">Enabled</span>
|
||||
</div>
|
||||
<div class="km-rule-d">+150 days from expiry → dormant, RBI Dormant Account reporting triggered</div>
|
||||
<div class="km-rule-tags">
|
||||
<span class="km-b km-b-gy">Jun 30 – Sep 30</span>
|
||||
@@ -533,7 +642,9 @@
|
||||
</div>
|
||||
<div class="km-warn-box">
|
||||
<div class="km-warn-t">⚠ Maker-Checker Required</div>
|
||||
<div class="km-warn-d">All manual changes require second officer approval and are logged in audit inventory.</div>
|
||||
<div class="km-warn-d">
|
||||
All manual changes require second officer approval and are logged in audit inventory.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -547,35 +658,64 @@
|
||||
</div>
|
||||
<table class="km-tbl">
|
||||
<thead>
|
||||
<tr><th>Account</th><th>From</th><th>To</th><th>Trigger</th><th>Date</th><th>By</th><th>Action</th></tr>
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>From</th>
|
||||
<th>To</th>
|
||||
<th>Trigger</th>
|
||||
<th>Date</th>
|
||||
<th>By</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr (click)="openModal('priya')">
|
||||
<td><div class="km-an">Priya Malhotra</div><div class="km-ai">ACC-BPL-2021-00231</div></td>
|
||||
<td>
|
||||
<div class="km-an">Priya Malhotra</div>
|
||||
<div class="km-ai">ACC-BPL-2021-00231</div>
|
||||
</td>
|
||||
<td><span class="km-sp km-sp-ac">Active</span></td>
|
||||
<td><span class="km-sp km-sp-fr">Debit Freeze</span></td>
|
||||
<td><span class="km-b km-b-am">Auto — KYC Expired</span></td>
|
||||
<td>10 Apr 2027</td>
|
||||
<td class="km-small">Scheduler</td>
|
||||
<td><button class="km-btn km-btn-ot" (click)="$event.stopPropagation(); toast('Unfreeze initiated')">Unfreeze</button></td>
|
||||
<td>
|
||||
<button class="km-btn km-btn-ot" (click)="$event.stopPropagation(); toast('Unfreeze initiated')">
|
||||
Unfreeze
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr (click)="openModal('suresh')">
|
||||
<td><div class="km-an">Suresh Patel</div><div class="km-ai">ACC-BPL-2019-00112</div></td>
|
||||
<td>
|
||||
<div class="km-an">Suresh Patel</div>
|
||||
<div class="km-ai">ACC-BPL-2019-00112</div>
|
||||
</td>
|
||||
<td><span class="km-sp km-sp-fr">Debit Freeze</span></td>
|
||||
<td><span class="km-sp km-sp-in">Inoperative</span></td>
|
||||
<td><span class="km-b km-b-or">Auto — 60d elapsed</span></td>
|
||||
<td>15 May 2027</td>
|
||||
<td class="km-small">Scheduler</td>
|
||||
<td><button class="km-btn km-btn-g" (click)="$event.stopPropagation(); toast('Override needs approval')">Override</button></td>
|
||||
<td>
|
||||
<button class="km-btn km-btn-g" (click)="$event.stopPropagation(); toast('Override needs approval')">
|
||||
Override
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr (click)="openModal('kavitha')">
|
||||
<td><div class="km-an">Kavitha Nair</div><div class="km-ai">ACC-BPL-2018-00088</div></td>
|
||||
<td>
|
||||
<div class="km-an">Kavitha Nair</div>
|
||||
<div class="km-ai">ACC-BPL-2018-00088</div>
|
||||
</td>
|
||||
<td><span class="km-sp km-sp-in">Inoperative</span></td>
|
||||
<td><span class="km-sp km-sp-do">Dormant</span></td>
|
||||
<td><span class="km-b km-b-re">Auto — 150d elapsed</span></td>
|
||||
<td>1 Jun 2027</td>
|
||||
<td class="km-small">Scheduler</td>
|
||||
<td><button class="km-btn km-btn-g" (click)="$event.stopPropagation(); toast('Reversal needs RM + RBI')">Reverse</button></td>
|
||||
<td>
|
||||
<button class="km-btn km-btn-g" (click)="$event.stopPropagation(); toast('Reversal needs RM + RBI')">
|
||||
Reverse
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -600,11 +740,21 @@
|
||||
</div>
|
||||
<div class="km-mbody">
|
||||
<div class="km-mtab-bar">
|
||||
<button class="km-mtab" [class.active]="modalTab === 'overview'" (click)="showMTab('overview')">Overview</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'timeline'" (click)="showMTab('timeline')">Alert Timeline</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'notices'" (click)="showMTab('notices')">Notices Sent</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'evidence'" (click)="showMTab('evidence')">Evidence</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'action'" (click)="showMTab('action')">Take Action</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'overview'" (click)="showMTab('overview')">
|
||||
Overview
|
||||
</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'timeline'" (click)="showMTab('timeline')">
|
||||
Alert Timeline
|
||||
</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'notices'" (click)="showMTab('notices')">
|
||||
Notices Sent
|
||||
</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'evidence'" (click)="showMTab('evidence')">
|
||||
Evidence
|
||||
</button>
|
||||
<button class="km-mtab" [class.active]="modalTab === 'action'" (click)="showMTab('action')">
|
||||
Take Action
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
@@ -623,36 +773,86 @@
|
||||
<div class="km-nb-icon">⚡</div>
|
||||
<div>
|
||||
<div class="km-nb-title">{{ stateLabel(current.state) }} — {{ current.daysLeft }} days to expiry</div>
|
||||
<div class="km-nb-sub">Next pending: <strong>{{ current.noticePending }}</strong>. Next stage: <strong>{{ current.nextStage }}</strong>.</div>
|
||||
<div class="km-nb-sub">
|
||||
Next pending: <strong>{{ current.noticePending }}</strong
|
||||
>. Next stage: <strong>{{ current.nextStage }}</strong
|
||||
>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="km-mstat-row">
|
||||
<div class="km-mstat"><div class="km-mstat-n">{{ current.noticesSent }}</div><div class="km-mstat-l">Notices Sent</div></div>
|
||||
<div class="km-mstat"><div class="km-mstat-n">{{ noticesPending(current) }}</div><div class="km-mstat-l">Notices Pending</div></div>
|
||||
<div class="km-mstat"><div class="km-mstat-n">{{ current.actionTaken.length }}</div><div class="km-mstat-l">Actions Taken</div></div>
|
||||
<div class="km-mstat"><div class="km-mstat-n">{{ current.pendingActions.length }}</div><div class="km-mstat-l">Pending Actions</div></div>
|
||||
<div class="km-mstat">
|
||||
<div class="km-mstat-n">{{ current.noticesSent }}</div>
|
||||
<div class="km-mstat-l">Notices Sent</div>
|
||||
</div>
|
||||
<div class="km-mstat">
|
||||
<div class="km-mstat-n">{{ noticesPending(current) }}</div>
|
||||
<div class="km-mstat-l">Notices Pending</div>
|
||||
</div>
|
||||
<div class="km-mstat">
|
||||
<div class="km-mstat-n">{{ current.actionTaken.length }}</div>
|
||||
<div class="km-mstat-l">Actions Taken</div>
|
||||
</div>
|
||||
<div class="km-mstat">
|
||||
<div class="km-mstat-n">{{ current.pendingActions.length }}</div>
|
||||
<div class="km-mstat-l">Pending Actions</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="km-r2">
|
||||
<div>
|
||||
<div class="km-slbl">KYC Information</div>
|
||||
<div class="km-mg">
|
||||
<div class="km-mi"><div class="km-ml">PAN</div><div class="km-mv km-mono">{{ current.kyc.pan }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">PAN Status</div><div class="km-mv"><span class="km-b km-b-gr">{{ current.kyc.panStatus }}</span></div></div>
|
||||
<div class="km-mi"><div class="km-ml">Aadhaar</div><div class="km-mv km-mono">{{ current.kyc.aadhaar }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Aadhaar Status</div><div class="km-mv"><span class="km-b km-b-gr">{{ current.kyc.aadhaarStatus }}</span></div></div>
|
||||
<div class="km-mi"><div class="km-ml">KYC Validity</div><div class="km-mv">{{ current.kyc.validity }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Expiry Date</div><div class="km-mv km-red">{{ current.expiry }}</div></div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">PAN</div>
|
||||
<div class="km-mv km-mono">{{ current.kyc.pan }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">PAN Status</div>
|
||||
<div class="km-mv">
|
||||
<span class="km-b km-b-gr">{{ current.kyc.panStatus }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Aadhaar</div>
|
||||
<div class="km-mv km-mono">{{ current.kyc.aadhaar }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Aadhaar Status</div>
|
||||
<div class="km-mv">
|
||||
<span class="km-b km-b-gr">{{ current.kyc.aadhaarStatus }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">KYC Validity</div>
|
||||
<div class="km-mv">{{ current.kyc.validity }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Expiry Date</div>
|
||||
<div class="km-mv km-red">{{ current.expiry }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="km-slbl">Contact Details</div>
|
||||
<div class="km-mg">
|
||||
<div class="km-mi"><div class="km-ml">Mobile</div><div class="km-mv">{{ current.contact.mobile }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Email</div><div class="km-mv km-small">{{ current.contact.email }}</div></div>
|
||||
<div class="km-mi km-mi-span"><div class="km-ml">Address</div><div class="km-mv km-small">{{ current.contact.address }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Branch</div><div class="km-mv">{{ current.contact.branch }}</div></div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Mobile</div>
|
||||
<div class="km-mv">{{ current.contact.mobile }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Email</div>
|
||||
<div class="km-mv km-small">{{ current.contact.email }}</div>
|
||||
</div>
|
||||
<div class="km-mi km-mi-span">
|
||||
<div class="km-ml">Address</div>
|
||||
<div class="km-mv km-small">{{ current.contact.address }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Branch</div>
|
||||
<div class="km-mv">{{ current.contact.branch }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -688,22 +888,44 @@
|
||||
<div class="km-slbl">All Notices Dispatched</div>
|
||||
<table class="km-tbl">
|
||||
<thead>
|
||||
<tr><th>#</th><th>Notice</th><th>Channel</th><th>Date</th><th>Reference</th><th>Delivery</th><th>Response</th></tr>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Notice</th>
|
||||
<th>Channel</th>
|
||||
<th>Date</th>
|
||||
<th>Reference</th>
|
||||
<th>Delivery</th>
|
||||
<th>Response</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (n of current.notices; track n.ref; let i = $index) {
|
||||
<tr>
|
||||
<td class="km-num">{{ i + 1 }}</td>
|
||||
<td><span class="km-b" [ngClass]="i === 0 ? 'km-b-bl' : i === 1 ? 'km-b-am' : 'km-b-or'">{{ n.no }}</span></td>
|
||||
<td>
|
||||
<span class="km-b" [ngClass]="i === 0 ? 'km-b-bl' : i === 1 ? 'km-b-am' : 'km-b-or'">{{
|
||||
n.no
|
||||
}}</span>
|
||||
</td>
|
||||
<td class="km-small">{{ n.channel }}</td>
|
||||
<td>{{ n.date }}</td>
|
||||
<td><span class="km-ref">{{ n.ref }}</span></td>
|
||||
<td><span class="km-del" [ngClass]="deliveryClass(n.delivery)">{{ n.delivery }}</span></td>
|
||||
<td><span class="km-del" [ngClass]="responseClass(n.response)">{{ n.response }}</span></td>
|
||||
<td>
|
||||
<span class="km-ref">{{ n.ref }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="km-del" [ngClass]="deliveryClass(n.delivery)">{{ n.delivery }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="km-del" [ngClass]="responseClass(n.response)">{{ n.response }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (noticesPending(current) > 0) {
|
||||
<tr><td colspan="7" class="km-pending-row">⏳ {{ noticesPending(current) }} notice(s) still pending dispatch</td></tr>
|
||||
<tr>
|
||||
<td colspan="7" class="km-pending-row">
|
||||
⏳ {{ noticesPending(current) }} notice(s) still pending dispatch
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -718,28 +940,55 @@
|
||||
<div class="km-empty-s">Evidence is captured during branch visits or video KYC sessions.</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="km-slbl">{{ current.evidence.type === 'visit' ? 'Branch Visit Evidence' : 'Video KYC Session Log' }}</div>
|
||||
<div class="km-slbl">
|
||||
{{ current.evidence.type === 'visit' ? 'Home Visit Evidence' : 'Video KYC Session Log' }}
|
||||
</div>
|
||||
<div class="km-r2 km-mb">
|
||||
<div class="km-mi"><div class="km-ml">Date</div><div class="km-mv">{{ current.evidence.date }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Officer / Agent</div><div class="km-mv">{{ current.evidence.officer }}</div></div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Date</div>
|
||||
<div class="km-mv">{{ current.evidence.date }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Officer / Agent</div>
|
||||
<div class="km-mv">{{ current.evidence.officer }}</div>
|
||||
</div>
|
||||
@if (current.evidence.type === 'visit') {
|
||||
<div class="km-mi"><div class="km-ml">GPS Coordinates</div><div class="km-mv km-mono">{{ current.evidence.gps }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Location</div><div class="km-mv km-small">{{ current.evidence.location }}</div></div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">GPS Coordinates</div>
|
||||
<div class="km-mv km-mono">{{ current.evidence.gps }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Location</div>
|
||||
<div class="km-mv km-small">{{ current.evidence.location }}</div>
|
||||
</div>
|
||||
}
|
||||
<div class="km-mi"><div class="km-ml">Reference / Docket</div><div class="km-mv km-mono">{{ current.evidence.docket || current.evidence.ref }}</div></div>
|
||||
<div class="km-mi"><div class="km-ml">Outcome</div><div class="km-mv"><span class="km-del km-d-fa">No Compliance</span></div></div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Reference / Docket</div>
|
||||
<div class="km-mv km-mono">{{ current.evidence.docket || current.evidence.ref }}</div>
|
||||
</div>
|
||||
<div class="km-mi">
|
||||
<div class="km-ml">Outcome</div>
|
||||
<div class="km-mv"><span class="km-del km-d-fa">No Compliance</span></div>
|
||||
</div>
|
||||
</div>
|
||||
@if (current.evidence.type === 'visit') {
|
||||
<div class="km-slbl">Map Placeholder</div>
|
||||
<div class="km-map">{{ current.evidence.gps }}<div class="km-small">{{ current.evidence.location }}</div></div>
|
||||
<div class="km-map">
|
||||
{{ current.evidence.gps }}
|
||||
<div class="km-small">{{ current.evidence.location }}</div>
|
||||
</div>
|
||||
<div class="km-slbl">Photo Evidence</div>
|
||||
<div class="km-photo">Visit photo uploaded · Tap to view</div>
|
||||
}
|
||||
<div class="km-slbl">Officer Notes</div>
|
||||
<div class="km-notes">{{ current.evidence.outcome }}</div>
|
||||
<div class="km-row-actions">
|
||||
<button class="km-btn km-btn-t" (click)="toast('Downloading evidence package...')">Download Package</button>
|
||||
<button class="km-btn km-btn-g" (click)="toast('Sharing with RBI audit team...')">Share for Audit</button>
|
||||
<button class="km-btn km-btn-t" (click)="toast('Downloading evidence package...')">
|
||||
Download Package
|
||||
</button>
|
||||
<button class="km-btn km-btn-g" (click)="toast('Sharing with RBI audit team...')">
|
||||
Share for Audit
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -754,7 +1003,7 @@
|
||||
<div class="km-action-t">{{ action }}</div>
|
||||
<div class="km-action-d">Initiate via available channels</div>
|
||||
</div>
|
||||
<button class="km-btn km-btn-t" (click)="toast(action + ' initiated for ' + current.name)">Take Action</button>
|
||||
<button class="km-btn km-btn-t" (click)="takeAction(action)">Take Action</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -764,6 +1013,158 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- HOME VISIT SCHEDULE DIALOG -->
|
||||
@if (homeVisitOpen && current) {
|
||||
<div class="km-overlay" (click)="closeHomeVisitDialog()">
|
||||
<div class="km-modal hv-modal" (click)="$event.stopPropagation()">
|
||||
<div class="km-mh">
|
||||
<div class="km-mh-av">{{ current.av }}</div>
|
||||
<div>
|
||||
<div class="km-mh-name">Schedule Home Visit</div>
|
||||
<div class="km-mh-meta">{{ current.name }} · {{ current.account }}</div>
|
||||
</div>
|
||||
<div class="km-mclose" (click)="closeHomeVisitDialog()">✕</div>
|
||||
</div>
|
||||
|
||||
<div class="km-mbody hv-body">
|
||||
<div class="hv-addr">
|
||||
<div class="hv-addr-label">Visit Address</div>
|
||||
<div class="hv-addr-name">{{ current.name }}</div>
|
||||
<div class="hv-addr-text">{{ current.contact.address }}</div>
|
||||
<div class="hv-addr-branch">Branch: {{ current.contact.branch }}</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Bank Officer<span class="hv-req">*</span></label>
|
||||
<select class="hv-input" [(ngModel)]="homeVisitOfficer">
|
||||
<option value="" disabled>Select an officer…</option>
|
||||
@for (officer of bankOfficers; track officer) {
|
||||
<option [value]="officer">{{ officer }}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Visit Date & Time<span class="hv-req">*</span></label>
|
||||
<input type="datetime-local" class="hv-input" [(ngModel)]="homeVisitDateTime" />
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Notes (optional)</label>
|
||||
<textarea
|
||||
class="hv-input hv-textarea"
|
||||
rows="2"
|
||||
placeholder="Any specific instructions for the officer…"
|
||||
[(ngModel)]="homeVisitNote"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-footer">
|
||||
<button class="km-btn" (click)="closeHomeVisitDialog()">Cancel</button>
|
||||
<button
|
||||
class="km-btn km-btn-t"
|
||||
[disabled]="!homeVisitOfficer || !homeVisitDateTime"
|
||||
(click)="saveHomeVisit()"
|
||||
>
|
||||
Save Visit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- VIDEO KYC LINK DIALOG -->
|
||||
@if (vkycOpen && current) {
|
||||
<div class="km-overlay" (click)="closeVkycDialog()">
|
||||
<div class="km-modal hv-modal" (click)="$event.stopPropagation()">
|
||||
<div class="km-mh">
|
||||
<div class="km-mh-av">{{ current.av }}</div>
|
||||
<div>
|
||||
<div class="km-mh-name">Send Video KYC Link</div>
|
||||
<div class="km-mh-meta">{{ current.name }} · {{ current.account }}</div>
|
||||
</div>
|
||||
<div class="km-mclose" (click)="closeVkycDialog()">✕</div>
|
||||
</div>
|
||||
|
||||
<div class="km-mbody hv-body">
|
||||
<div class="hv-addr">
|
||||
<div class="hv-addr-label">Customer Contact</div>
|
||||
<div class="hv-addr-name">{{ current.name }}</div>
|
||||
<div class="hv-addr-text">
|
||||
<fa-icon icon="mobile-alt" class="vkyc-ic"></fa-icon> {{ current.contact.mobile }}
|
||||
</div>
|
||||
<div class="hv-addr-text">
|
||||
<fa-icon icon="envelope" class="vkyc-ic"></fa-icon> {{ current.contact.email }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Send Via<span class="hv-req">*</span></label>
|
||||
<div class="vkyc-chans">
|
||||
<label class="vkyc-chan">
|
||||
<input type="checkbox" [(ngModel)]="vkycChannels.sms" />
|
||||
<span>SMS</span>
|
||||
</label>
|
||||
<label class="vkyc-chan">
|
||||
<input type="checkbox" [(ngModel)]="vkycChannels.email" />
|
||||
<span>Email</span>
|
||||
</label>
|
||||
<label class="vkyc-chan">
|
||||
<input type="checkbox" [(ngModel)]="vkycChannels.whatsapp" />
|
||||
<span>WhatsApp</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Assign KYC Officer<span class="hv-req">*</span></label>
|
||||
<select class="hv-input" [(ngModel)]="vkycOfficer">
|
||||
<option value="" disabled>Select an officer…</option>
|
||||
@for (officer of bankOfficers; track officer) {
|
||||
<option [value]="officer">{{ officer }}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Link Expiry<span class="hv-req">*</span></label>
|
||||
<input type="datetime-local" class="hv-input" [(ngModel)]="vkycExpiry" />
|
||||
<div class="vkyc-hint">Default: 48 hours (RBI Video-based KYC norms)</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Session Link Preview</label>
|
||||
<div class="vkyc-link">
|
||||
<span class="vkyc-link-text">{{ vkycLink }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-row">
|
||||
<label class="hv-label">Custom Message (optional)</label>
|
||||
<textarea
|
||||
class="hv-input hv-textarea"
|
||||
rows="2"
|
||||
placeholder="e.g. Please complete your Video KYC at your earliest convenience…"
|
||||
[(ngModel)]="vkycMessage"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hv-footer">
|
||||
<button class="km-btn" (click)="closeVkycDialog()">Cancel</button>
|
||||
<button
|
||||
class="km-btn km-btn-t"
|
||||
[disabled]="!vkycOfficer || !vkycExpiry || vkycSelectedChannels.length === 0"
|
||||
(click)="saveVkyc()"
|
||||
>
|
||||
Send Link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- TOAST -->
|
||||
<div class="km-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,11 @@
|
||||
--km-g900: #0f172a;
|
||||
|
||||
display: block;
|
||||
font-family: 'DM Sans', system-ui, -apple-system, sans-serif;
|
||||
font-family:
|
||||
'DM Sans',
|
||||
system-ui,
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
background: var(--km-g50);
|
||||
color: var(--km-g800);
|
||||
font-size: 14px;
|
||||
@@ -130,7 +134,7 @@
|
||||
background: #fff;
|
||||
border: 1px solid var(--km-g200);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 8%);
|
||||
}
|
||||
|
||||
.km-ch {
|
||||
@@ -172,11 +176,30 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.km-ci-t { background: var(--km-teal-l); color: var(--km-teal); }
|
||||
.km-ci-a { background: var(--km-amber-l); color: var(--km-amber); }
|
||||
.km-ci-r { background: var(--km-red-l); color: var(--km-red); }
|
||||
.km-ci-b { background: var(--km-blue-l); color: var(--km-blue); }
|
||||
.km-ci-g { background: var(--km-green-l); color: var(--km-green); }
|
||||
.km-ci-t {
|
||||
background: var(--km-teal-l);
|
||||
color: var(--km-teal);
|
||||
}
|
||||
|
||||
.km-ci-a {
|
||||
background: var(--km-amber-l);
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-ci-r {
|
||||
background: var(--km-red-l);
|
||||
color: var(--km-red);
|
||||
}
|
||||
|
||||
.km-ci-b {
|
||||
background: var(--km-blue-l);
|
||||
color: var(--km-blue);
|
||||
}
|
||||
|
||||
.km-ci-g {
|
||||
background: var(--km-green-l);
|
||||
color: var(--km-green);
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
.km-b {
|
||||
@@ -189,17 +212,53 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.km-b-gr { background: var(--km-green-l); color: var(--km-green); }
|
||||
.km-b-am { background: var(--km-amber-l); color: var(--km-amber); }
|
||||
.km-b-re { background: var(--km-red-l); color: var(--km-red); }
|
||||
.km-b-or { background: var(--km-orange-l); color: var(--km-orange); }
|
||||
.km-b-bl { background: var(--km-blue-l); color: var(--km-blue); }
|
||||
.km-b-te { background: var(--km-teal-l); color: var(--km-teal); }
|
||||
.km-b-gy { background: var(--km-g100); color: var(--km-g600); }
|
||||
.km-b-nv { background: #e8edf5; color: var(--km-navy); }
|
||||
.km-b-gr {
|
||||
background: var(--km-green-l);
|
||||
color: var(--km-green);
|
||||
}
|
||||
|
||||
.km-ml-auto { margin-left: auto; }
|
||||
.km-ml-12 { margin-left: 12px; }
|
||||
.km-b-am {
|
||||
background: var(--km-amber-l);
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-b-re {
|
||||
background: var(--km-red-l);
|
||||
color: var(--km-red);
|
||||
}
|
||||
|
||||
.km-b-or {
|
||||
background: var(--km-orange-l);
|
||||
color: var(--km-orange);
|
||||
}
|
||||
|
||||
.km-b-bl {
|
||||
background: var(--km-blue-l);
|
||||
color: var(--km-blue);
|
||||
}
|
||||
|
||||
.km-b-te {
|
||||
background: var(--km-teal-l);
|
||||
color: var(--km-teal);
|
||||
}
|
||||
|
||||
.km-b-gy {
|
||||
background: var(--km-g100);
|
||||
color: var(--km-g600);
|
||||
}
|
||||
|
||||
.km-b-nv {
|
||||
background: #e8edf5;
|
||||
color: var(--km-navy);
|
||||
}
|
||||
|
||||
.km-ml-auto {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.km-ml-12 {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.km-btn {
|
||||
@@ -216,14 +275,57 @@
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.km-btn-t { background: var(--km-teal); border-color: var(--km-teal); color: #fff; &:hover { opacity: 0.9; } }
|
||||
.km-btn-ot { background: #fff; border-color: var(--km-teal); color: var(--km-teal); &:hover { background: var(--km-teal-l); } }
|
||||
.km-btn-n { background: var(--km-navy); border-color: var(--km-navy); color: #fff; }
|
||||
.km-btn-a { background: var(--km-amber); border-color: var(--km-amber); color: #fff; }
|
||||
.km-btn-r { background: var(--km-red); border-color: var(--km-red); color: #fff; }
|
||||
.km-btn-g { background: #fff; border-color: var(--km-g300); color: var(--km-g600); &:hover { background: var(--km-g50); } }
|
||||
.km-btn-t {
|
||||
background: var(--km-teal);
|
||||
border-color: var(--km-teal);
|
||||
color: #fff;
|
||||
|
||||
.km-w { width: 100%; }
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
.km-btn-ot {
|
||||
background: #fff;
|
||||
border-color: var(--km-teal);
|
||||
color: var(--km-teal);
|
||||
|
||||
&:hover {
|
||||
background: var(--km-teal-l);
|
||||
}
|
||||
}
|
||||
|
||||
.km-btn-n {
|
||||
background: var(--km-navy);
|
||||
border-color: var(--km-navy);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.km-btn-a {
|
||||
background: var(--km-amber);
|
||||
border-color: var(--km-amber);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.km-btn-r {
|
||||
background: var(--km-red);
|
||||
border-color: var(--km-red);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.km-btn-g {
|
||||
background: #fff;
|
||||
border-color: var(--km-g300);
|
||||
color: var(--km-g600);
|
||||
|
||||
&:hover {
|
||||
background: var(--km-g50);
|
||||
}
|
||||
}
|
||||
|
||||
.km-w {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Stat row */
|
||||
.km-stat-row {
|
||||
@@ -238,12 +340,12 @@
|
||||
border: 1px solid var(--km-g200);
|
||||
border-radius: 12px;
|
||||
padding: 14px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 8%);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 4px 12px rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,11 +472,30 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-sp-ac { background: var(--km-green-l); color: var(--km-green); }
|
||||
.km-sp-fr { background: var(--km-amber-l); color: var(--km-amber); }
|
||||
.km-sp-in { background: var(--km-orange-l); color: var(--km-orange); }
|
||||
.km-sp-do { background: var(--km-red-l); color: var(--km-red); }
|
||||
.km-sp-al { background: #fef9c3; color: #92400e; }
|
||||
.km-sp-ac {
|
||||
background: var(--km-green-l);
|
||||
color: var(--km-green);
|
||||
}
|
||||
|
||||
.km-sp-fr {
|
||||
background: var(--km-amber-l);
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-sp-in {
|
||||
background: var(--km-orange-l);
|
||||
color: var(--km-orange);
|
||||
}
|
||||
|
||||
.km-sp-do {
|
||||
background: var(--km-red-l);
|
||||
color: var(--km-red);
|
||||
}
|
||||
|
||||
.km-sp-al {
|
||||
background: #fef9c3;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
/* Progress bar */
|
||||
.km-pbar {
|
||||
@@ -424,10 +545,25 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-d-ok { background: var(--km-green-l); color: var(--km-green); }
|
||||
.km-d-pe { background: var(--km-amber-l); color: var(--km-amber); }
|
||||
.km-d-fa { background: var(--km-red-l); color: var(--km-red); }
|
||||
.km-d-tr { background: var(--km-blue-l); color: var(--km-blue); }
|
||||
.km-d-ok {
|
||||
background: var(--km-green-l);
|
||||
color: var(--km-green);
|
||||
}
|
||||
|
||||
.km-d-pe {
|
||||
background: var(--km-amber-l);
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-d-fa {
|
||||
background: var(--km-red-l);
|
||||
color: var(--km-red);
|
||||
}
|
||||
|
||||
.km-d-tr {
|
||||
background: var(--km-blue-l);
|
||||
color: var(--km-blue);
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
.km-pagination {
|
||||
@@ -489,12 +625,41 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.km-nd1 { background: var(--km-blue-l); border-color: #93c5fd; color: var(--km-blue); }
|
||||
.km-nd2 { background: var(--km-amber-l); border-color: #fcd34d; color: var(--km-amber); }
|
||||
.km-nd3 { background: var(--km-orange-l); border-color: #fdba74; color: var(--km-orange); }
|
||||
.km-ndf { background: var(--km-red-l); border-color: #fca5a5; color: var(--km-red); }
|
||||
.km-ndi { background: #fee2e2; border-color: #f87171; color: #991b1b; }
|
||||
.km-ndd { background: var(--km-g100); border-color: var(--km-g300); color: var(--km-g500); }
|
||||
.km-nd1 {
|
||||
background: var(--km-blue-l);
|
||||
border-color: #93c5fd;
|
||||
color: var(--km-blue);
|
||||
}
|
||||
|
||||
.km-nd2 {
|
||||
background: var(--km-amber-l);
|
||||
border-color: #fcd34d;
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-nd3 {
|
||||
background: var(--km-orange-l);
|
||||
border-color: #fdba74;
|
||||
color: var(--km-orange);
|
||||
}
|
||||
|
||||
.km-ndf {
|
||||
background: var(--km-red-l);
|
||||
border-color: #fca5a5;
|
||||
color: var(--km-red);
|
||||
}
|
||||
|
||||
.km-ndi {
|
||||
background: #fee2e2;
|
||||
border-color: #f87171;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.km-ndd {
|
||||
background: var(--km-g100);
|
||||
border-color: var(--km-g300);
|
||||
color: var(--km-g500);
|
||||
}
|
||||
|
||||
.km-nl {
|
||||
width: 1px;
|
||||
@@ -509,9 +674,13 @@
|
||||
color: var(--km-g800);
|
||||
}
|
||||
|
||||
.km-warn { color: var(--km-amber); }
|
||||
.km-warn-o { color: var(--km-orange); }
|
||||
.km-warn-d { color: var(--km-g600); }
|
||||
.km-warn {
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-warn-o {
|
||||
color: var(--km-orange);
|
||||
}
|
||||
|
||||
.km-ns {
|
||||
font-size: 11px;
|
||||
@@ -520,9 +689,20 @@
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.km-ok { color: var(--km-green); font-weight: 600; }
|
||||
.km-pending { color: var(--km-amber); font-weight: 600; }
|
||||
.km-fail { color: var(--km-red); font-weight: 600; }
|
||||
.km-ok {
|
||||
color: var(--km-green);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-pending {
|
||||
color: var(--km-amber);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-fail {
|
||||
color: var(--km-red);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-ntags {
|
||||
display: flex;
|
||||
@@ -541,12 +721,41 @@
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.km-cp-sms { background: #eff6ff; color: #1d4ed8; border-color: #93c5fd; }
|
||||
.km-cp-mail { background: #f0fdf4; color: #15803d; border-color: #86efac; }
|
||||
.km-cp-ivr { background: #faf5ff; color: #7c3aed; border-color: #c4b5fd; }
|
||||
.km-cp-post { background: #fff7ed; color: #c2410c; border-color: #fdba74; }
|
||||
.km-cp-vis { background: var(--km-teal-l); color: var(--km-teal); border-color: #5eead4; }
|
||||
.km-cp-vid { background: #ede9fe; color: #5b21b6; border-color: #a78bfa; }
|
||||
.km-cp-sms {
|
||||
background: #eff6ff;
|
||||
color: #1d4ed8;
|
||||
border-color: #93c5fd;
|
||||
}
|
||||
|
||||
.km-cp-mail {
|
||||
background: #f0fdf4;
|
||||
color: #15803d;
|
||||
border-color: #86efac;
|
||||
}
|
||||
|
||||
.km-cp-ivr {
|
||||
background: #faf5ff;
|
||||
color: #7c3aed;
|
||||
border-color: #c4b5fd;
|
||||
}
|
||||
|
||||
.km-cp-post {
|
||||
background: #fff7ed;
|
||||
color: #c2410c;
|
||||
border-color: #fdba74;
|
||||
}
|
||||
|
||||
.km-cp-vis {
|
||||
background: var(--km-teal-l);
|
||||
color: var(--km-teal);
|
||||
border-color: #5eead4;
|
||||
}
|
||||
|
||||
.km-cp-vid {
|
||||
background: #ede9fe;
|
||||
color: #5b21b6;
|
||||
border-color: #a78bfa;
|
||||
}
|
||||
|
||||
.km-row-actions {
|
||||
margin-top: 8px;
|
||||
@@ -574,9 +783,20 @@
|
||||
background: var(--km-teal-l);
|
||||
}
|
||||
|
||||
.km-channel-i { font-size: 16px; margin-bottom: 3px; }
|
||||
.km-channel-n { font-size: 11px; font-weight: 600; }
|
||||
.km-channel-d { font-size: 10px; color: var(--km-g500); }
|
||||
.km-channel-i {
|
||||
font-size: 16px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.km-channel-n {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-channel-d {
|
||||
font-size: 10px;
|
||||
color: var(--km-g500);
|
||||
}
|
||||
|
||||
/* Meta items */
|
||||
.km-mi {
|
||||
@@ -618,15 +838,79 @@
|
||||
transition: all 0.15s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 4px 12px rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.km-sc-ac { border-color: #86efac; background: var(--km-green-l); .km-sc-l, .km-sc-d { color: #166534; } .km-sc-n { color: var(--km-green); } }
|
||||
.km-sc-fr { border-color: #fcd34d; background: var(--km-amber-l); .km-sc-l, .km-sc-d { color: #92400e; } .km-sc-n { color: var(--km-amber); } }
|
||||
.km-sc-in { border-color: #fdba74; background: var(--km-orange-l); .km-sc-l, .km-sc-d { color: #7c2d12; } .km-sc-n { color: var(--km-orange); } }
|
||||
.km-sc-do { border-color: #fca5a5; background: var(--km-red-l); .km-sc-l, .km-sc-d { color: #7f1d1d; } .km-sc-n { color: var(--km-red); } }
|
||||
.km-sc-al { border-color: #fde047; background: #fef9c3; .km-sc-l, .km-sc-d { color: #713f12; } .km-sc-n { color: #92400e; } }
|
||||
.km-sc-ac {
|
||||
border-color: #86efac;
|
||||
background: var(--km-green-l);
|
||||
|
||||
.km-sc-l,
|
||||
.km-sc-d {
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.km-sc-n {
|
||||
color: var(--km-green);
|
||||
}
|
||||
}
|
||||
|
||||
.km-sc-fr {
|
||||
border-color: #fcd34d;
|
||||
background: var(--km-amber-l);
|
||||
|
||||
.km-sc-l,
|
||||
.km-sc-d {
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.km-sc-n {
|
||||
color: var(--km-amber);
|
||||
}
|
||||
}
|
||||
|
||||
.km-sc-in {
|
||||
border-color: #fdba74;
|
||||
background: var(--km-orange-l);
|
||||
|
||||
.km-sc-l,
|
||||
.km-sc-d {
|
||||
color: #7c2d12;
|
||||
}
|
||||
|
||||
.km-sc-n {
|
||||
color: var(--km-orange);
|
||||
}
|
||||
}
|
||||
|
||||
.km-sc-do {
|
||||
border-color: #fca5a5;
|
||||
background: var(--km-red-l);
|
||||
|
||||
.km-sc-l,
|
||||
.km-sc-d {
|
||||
color: #7f1d1d;
|
||||
}
|
||||
|
||||
.km-sc-n {
|
||||
color: var(--km-red);
|
||||
}
|
||||
}
|
||||
|
||||
.km-sc-al {
|
||||
border-color: #fde047;
|
||||
background: #fef9c3;
|
||||
|
||||
.km-sc-l,
|
||||
.km-sc-d {
|
||||
color: #713f12;
|
||||
}
|
||||
|
||||
.km-sc-n {
|
||||
color: #92400e;
|
||||
}
|
||||
}
|
||||
|
||||
.km-sc-l {
|
||||
font-size: 10px;
|
||||
@@ -719,7 +1003,7 @@
|
||||
.km-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
background: rgb(0 0 0 / 45%);
|
||||
z-index: 1200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -735,7 +1019,7 @@
|
||||
max-height: 90vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 20px 60px rgb(0 0 0 / 20%);
|
||||
}
|
||||
|
||||
.km-mh {
|
||||
@@ -787,7 +1071,9 @@
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover { background: var(--km-g100); }
|
||||
&:hover {
|
||||
background: var(--km-g100);
|
||||
}
|
||||
}
|
||||
|
||||
.km-mbody {
|
||||
@@ -863,7 +1149,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.km-ps-done::after { background: var(--km-teal); }
|
||||
.km-ps-done::after {
|
||||
background: var(--km-teal);
|
||||
}
|
||||
|
||||
.km-ps-dot {
|
||||
width: 28px;
|
||||
@@ -881,9 +1169,23 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.km-ps-done .km-ps-dot { background: var(--km-teal); border-color: var(--km-teal); color: #fff; }
|
||||
.km-ps-current .km-ps-dot { background: #fff; border-color: var(--km-amber); color: var(--km-amber); }
|
||||
.km-ps-danger .km-ps-dot { background: #fff; border-color: var(--km-red); color: var(--km-red); }
|
||||
.km-ps-done .km-ps-dot {
|
||||
background: var(--km-teal);
|
||||
border-color: var(--km-teal);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.km-ps-current .km-ps-dot {
|
||||
background: #fff;
|
||||
border-color: var(--km-amber);
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-ps-danger .km-ps-dot {
|
||||
background: #fff;
|
||||
border-color: var(--km-red);
|
||||
color: var(--km-red);
|
||||
}
|
||||
|
||||
.km-ps-label {
|
||||
font-size: 10px;
|
||||
@@ -893,9 +1195,19 @@
|
||||
max-width: 70px;
|
||||
}
|
||||
|
||||
.km-ps-done .km-ps-label { color: var(--km-teal); }
|
||||
.km-ps-current .km-ps-label { color: var(--km-amber); font-weight: 600; }
|
||||
.km-ps-danger .km-ps-label { color: var(--km-red); font-weight: 600; }
|
||||
.km-ps-done .km-ps-label {
|
||||
color: var(--km-teal);
|
||||
}
|
||||
|
||||
.km-ps-current .km-ps-label {
|
||||
color: var(--km-amber);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-ps-danger .km-ps-label {
|
||||
color: var(--km-red);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Next action banner */
|
||||
.km-next-banner {
|
||||
@@ -908,15 +1220,45 @@
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.km-nb-alert { background: var(--km-amber-l); border-color: #fcd34d; }
|
||||
.km-nb-urgent { background: var(--km-orange-l); border-color: #fdba74; }
|
||||
.km-nb-freeze { background: var(--km-amber-l); border-color: #fcd34d; }
|
||||
.km-nb-inop { background: var(--km-orange-l); border-color: #fdba74; }
|
||||
.km-nb-dormant { background: var(--km-red-l); border-color: #fca5a5; }
|
||||
.km-nb-alert {
|
||||
background: var(--km-amber-l);
|
||||
border-color: #fcd34d;
|
||||
}
|
||||
|
||||
.km-nb-icon { font-size: 22px; flex-shrink: 0; }
|
||||
.km-nb-title { font-size: 13px; font-weight: 700; margin-bottom: 2px; }
|
||||
.km-nb-sub { font-size: 12px; }
|
||||
.km-nb-urgent {
|
||||
background: var(--km-orange-l);
|
||||
border-color: #fdba74;
|
||||
}
|
||||
|
||||
.km-nb-freeze {
|
||||
background: var(--km-amber-l);
|
||||
border-color: #fcd34d;
|
||||
}
|
||||
|
||||
.km-nb-inop {
|
||||
background: var(--km-orange-l);
|
||||
border-color: #fdba74;
|
||||
}
|
||||
|
||||
.km-nb-dormant {
|
||||
background: var(--km-red-l);
|
||||
border-color: #fca5a5;
|
||||
}
|
||||
|
||||
.km-nb-icon {
|
||||
font-size: 22px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.km-nb-title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.km-nb-sub {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Modal stat strip */
|
||||
.km-mstat-row {
|
||||
@@ -969,7 +1311,9 @@
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid var(--km-g100);
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.km-mti-dot {
|
||||
@@ -985,14 +1329,36 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.km-mti-done { background: var(--km-green-l); border-color: var(--km-green); color: var(--km-green); }
|
||||
.km-mti-pend { background: var(--km-amber-l); border-color: var(--km-amber); color: var(--km-amber); }
|
||||
.km-mti-done {
|
||||
background: var(--km-green-l);
|
||||
border-color: var(--km-green);
|
||||
color: var(--km-green);
|
||||
}
|
||||
|
||||
.km-mti-text { font-size: 13px; font-weight: 500; }
|
||||
.km-done { color: var(--km-g700); }
|
||||
.km-pend { color: var(--km-amber); }
|
||||
.km-mti-pend {
|
||||
background: var(--km-amber-l);
|
||||
border-color: var(--km-amber);
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-mti-sub { font-size: 11px; color: var(--km-g400); margin-top: 2px; }
|
||||
.km-mti-text {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.km-done {
|
||||
color: var(--km-g700);
|
||||
}
|
||||
|
||||
.km-pend {
|
||||
color: var(--km-amber);
|
||||
}
|
||||
|
||||
.km-mti-sub {
|
||||
font-size: 11px;
|
||||
color: var(--km-g400);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.km-pending-row {
|
||||
text-align: center;
|
||||
@@ -1009,8 +1375,15 @@
|
||||
color: var(--km-g400);
|
||||
}
|
||||
|
||||
.km-empty-i { font-size: 28px; margin-bottom: 8px; }
|
||||
.km-empty-s { font-size: 12px; margin-top: 4px; }
|
||||
.km-empty-i {
|
||||
font-size: 28px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.km-empty-s {
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Evidence */
|
||||
.km-map {
|
||||
@@ -1069,8 +1442,15 @@
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.km-action-t { font-size: 13px; font-weight: 600; }
|
||||
.km-action-d { font-size: 12px; color: var(--km-g500); }
|
||||
.km-action-t {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.km-action-d {
|
||||
font-size: 12px;
|
||||
color: var(--km-g500);
|
||||
}
|
||||
|
||||
/* Toast */
|
||||
.km-toast {
|
||||
@@ -1094,12 +1474,178 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
@media (width <= 900px) {
|
||||
.km-stat-row,
|
||||
.km-sc-row { grid-template-columns: repeat(2, 1fr); }
|
||||
.km-sc-row {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.km-r2,
|
||||
.km-notif-grid { grid-template-columns: 1fr; }
|
||||
.km-mstat-row { grid-template-columns: repeat(2, 1fr); }
|
||||
.km-prog-steps { flex-wrap: wrap; gap: 10px; }
|
||||
.km-ps::after { display: none; }
|
||||
.km-notif-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.km-mstat-row {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.km-prog-steps {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.km-ps::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Home Visit Schedule Dialog */
|
||||
.hv-modal {
|
||||
width: 520px;
|
||||
}
|
||||
|
||||
.hv-body {
|
||||
padding: 18px 22px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.hv-addr {
|
||||
background: #f8fafc;
|
||||
border: 1px solid var(--km-g200);
|
||||
border-radius: 10px;
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.hv-addr-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: #64748b;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.hv-addr-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #0f172a;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.hv-addr-text {
|
||||
font-size: 13px;
|
||||
color: #334155;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.hv-addr-branch {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.hv-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.hv-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.hv-req {
|
||||
color: #dc2626;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.hv-input {
|
||||
width: 100%;
|
||||
padding: 9px 12px;
|
||||
border: 1px solid var(--km-g200);
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
color: #0f172a;
|
||||
background: #fff;
|
||||
font-family: inherit;
|
||||
transition:
|
||||
border-color 0.15s,
|
||||
box-shadow 0.15s;
|
||||
}
|
||||
|
||||
.hv-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--km-teal);
|
||||
box-shadow: 0 0 0 3px rgb(20 184 166 / 15%);
|
||||
}
|
||||
|
||||
.hv-textarea {
|
||||
resize: vertical;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.hv-footer {
|
||||
padding: 14px 22px;
|
||||
border-top: 1px solid var(--km-g200);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.km-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Video KYC Dialog */
|
||||
.vkyc-ic {
|
||||
color: var(--km-teal);
|
||||
margin-right: 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.vkyc-chans {
|
||||
display: flex;
|
||||
gap: 18px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.vkyc-chan {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
color: #334155;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.vkyc-chan input {
|
||||
accent-color: var(--km-teal);
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vkyc-hint {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.vkyc-link {
|
||||
background: #f1f5f9;
|
||||
border: 1px dashed #cbd5e1;
|
||||
border-radius: 8px;
|
||||
padding: 9px 12px;
|
||||
font-family: 'Roboto Mono', 'DM Mono', monospace;
|
||||
font-size: 12px;
|
||||
color: #0f172a;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,38 @@ export class KycManagementComponent {
|
||||
toastVisible = false;
|
||||
private toastTimer: any;
|
||||
|
||||
/** Home Visit scheduling dialog */
|
||||
homeVisitOpen = false;
|
||||
homeVisitOfficer = '';
|
||||
homeVisitDateTime = '';
|
||||
homeVisitNote = '';
|
||||
bankOfficers = [
|
||||
'Amit Sharma — Branch Officer (Bhopal Main)',
|
||||
'Neha Verma — KYC Officer (Bhopal Main)',
|
||||
'Ravi Kulkarni — Field Officer (Bhopal Zone-2)',
|
||||
'Sunita Patel — Compliance Officer (Bhopal Main)',
|
||||
'Manoj Tiwari — Field Officer (Indore Zone-1)'
|
||||
];
|
||||
scheduledHomeVisits: { client: string; address: string; officer: string; dateTime: string; note: string }[] = [];
|
||||
|
||||
/** Video KYC link dialog */
|
||||
vkycOpen = false;
|
||||
vkycOfficer = '';
|
||||
vkycExpiry = '';
|
||||
vkycChannels = { sms: true, email: true, whatsapp: false };
|
||||
vkycMessage = '';
|
||||
vkycSessionId = '';
|
||||
sentVkycLinks: {
|
||||
client: string;
|
||||
mobile: string;
|
||||
email: string;
|
||||
officer: string;
|
||||
expiry: string;
|
||||
channels: string[];
|
||||
sessionId: string;
|
||||
link: string;
|
||||
}[] = [];
|
||||
|
||||
clients: Record<string, KmClient> = {
|
||||
rajesh: {
|
||||
id: 'rajesh',
|
||||
@@ -119,14 +151,35 @@ export class KycManagementComponent {
|
||||
branch: 'Bhopal Main'
|
||||
},
|
||||
notices: [
|
||||
{ no: 'N1', channel: 'SMS + Email', date: '31 Mar 2027', ref: 'MSG-2027-0331-001', delivery: 'Delivered', response: 'No Action' },
|
||||
{ no: 'N2', channel: 'Reg. Post + IVR', date: '10 Apr 2027', ref: 'RP-BPL-20270410-443', delivery: 'In Transit', response: 'Pending' }
|
||||
{
|
||||
no: 'N1',
|
||||
channel: 'SMS + Email',
|
||||
date: '31 Mar 2027',
|
||||
ref: 'MSG-2027-0331-001',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Action'
|
||||
},
|
||||
{
|
||||
no: 'N2',
|
||||
channel: 'Reg. Post + IVR',
|
||||
date: '10 Apr 2027',
|
||||
ref: 'RP-BPL-20270410-443',
|
||||
delivery: 'In Transit',
|
||||
response: 'Pending'
|
||||
}
|
||||
],
|
||||
noticesSent: 2,
|
||||
noticePending: 'Notice 3',
|
||||
nextStage: 'Debit Freeze',
|
||||
pendingActions: ['Send Notice 3 (due 20 Apr 2027)', 'Schedule Branch Visit', 'Send Video KYC link'],
|
||||
actionTaken: ['Notice 1 delivered', 'Notice 2 dispatched via Reg. Post'],
|
||||
pendingActions: [
|
||||
'Send Notice 3 (due 20 Apr 2027)',
|
||||
'Schedule Home Visit',
|
||||
'Send Video KYC link'
|
||||
],
|
||||
actionTaken: [
|
||||
'Notice 1 delivered',
|
||||
'Notice 2 dispatched via Reg. Post'
|
||||
],
|
||||
evidence: null
|
||||
},
|
||||
priya: {
|
||||
@@ -158,15 +211,45 @@ export class KycManagementComponent {
|
||||
branch: 'Bhopal Main'
|
||||
},
|
||||
notices: [
|
||||
{ no: 'N1', channel: 'SMS + Email', date: '10 Mar 2027', ref: 'MSG-2027-0310-003', delivery: 'Delivered', response: 'No Response' },
|
||||
{ no: 'N2', channel: 'Reg. Post', date: '20 Mar 2027', ref: 'RP-BPL-20270320-091', delivery: 'Delivered', response: 'No Response' },
|
||||
{ no: 'N3', channel: 'Branch Visit', date: '30 Mar 2027', ref: 'VIS-BPL-20270330-012', delivery: 'Visit Done', response: 'Refused' }
|
||||
{
|
||||
no: 'N1',
|
||||
channel: 'SMS + Email',
|
||||
date: '10 Mar 2027',
|
||||
ref: 'MSG-2027-0310-003',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
},
|
||||
{
|
||||
no: 'N2',
|
||||
channel: 'Reg. Post',
|
||||
date: '20 Mar 2027',
|
||||
ref: 'RP-BPL-20270320-091',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
},
|
||||
{
|
||||
no: 'N3',
|
||||
channel: 'Home Visit',
|
||||
date: '30 Mar 2027',
|
||||
ref: 'VIS-BPL-20270330-012',
|
||||
delivery: 'Visit Done',
|
||||
response: 'Refused'
|
||||
}
|
||||
],
|
||||
noticesSent: 3,
|
||||
noticePending: 'None — all 3 sent',
|
||||
nextStage: 'Inoperative by 30 Jun 2027',
|
||||
pendingActions: ['Account in Debit Freeze', 'Inoperative transition due 30 Jun 2027', 'Maker-checker unfreeze pending'],
|
||||
actionTaken: ['Notice 1 delivered', 'Notice 2 delivered via Reg. Post', 'Notice 3 — Branch visit done, client refused', 'Debit Freeze applied 10 Apr 2027'],
|
||||
pendingActions: [
|
||||
'Account in Debit Freeze',
|
||||
'Inoperative transition due 30 Jun 2027',
|
||||
'Maker-checker unfreeze pending'
|
||||
],
|
||||
actionTaken: [
|
||||
'Notice 1 delivered',
|
||||
'Notice 2 delivered via Reg. Post',
|
||||
'Notice 3 — Branch visit done, client refused',
|
||||
'Debit Freeze applied 10 Apr 2027'
|
||||
],
|
||||
evidence: {
|
||||
type: 'visit',
|
||||
date: '30 Mar 2027',
|
||||
@@ -206,15 +289,46 @@ export class KycManagementComponent {
|
||||
branch: 'Bhopal South'
|
||||
},
|
||||
notices: [
|
||||
{ no: 'N1', channel: 'SMS + Email', date: '13 Feb 2027', ref: 'MSG-2027-0213-006', delivery: 'Delivered', response: 'No Response' },
|
||||
{ no: 'N2', channel: 'Reg. Post + IVR', date: '23 Feb 2027', ref: 'RP-BPL-20270223-044', delivery: 'Delivered', response: 'No Response' },
|
||||
{ no: 'N3', channel: 'Video KYC', date: '5 Mar 2027', ref: 'VKYC-2027-0305-007', delivery: 'No Response', response: 'No Action' }
|
||||
{
|
||||
no: 'N1',
|
||||
channel: 'SMS + Email',
|
||||
date: '13 Feb 2027',
|
||||
ref: 'MSG-2027-0213-006',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
},
|
||||
{
|
||||
no: 'N2',
|
||||
channel: 'Reg. Post + IVR',
|
||||
date: '23 Feb 2027',
|
||||
ref: 'RP-BPL-20270223-044',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
},
|
||||
{
|
||||
no: 'N3',
|
||||
channel: 'Video KYC',
|
||||
date: '5 Mar 2027',
|
||||
ref: 'VKYC-2027-0305-007',
|
||||
delivery: 'No Response',
|
||||
response: 'No Action'
|
||||
}
|
||||
],
|
||||
noticesSent: 3,
|
||||
noticePending: 'None',
|
||||
nextStage: 'Dormant by 30 Sep 2027',
|
||||
pendingActions: ['Account Inoperative — all txns blocked', 'Dormant transition due 30 Sep 2027', 'RBI Dormant Account reporting'],
|
||||
actionTaken: ['Notice 1 delivered', 'Notice 2 delivered via Reg. Post', 'Notice 3 — Video KYC invite sent (no response)', 'Debit Freeze 15 Mar 2027', 'Inoperative 15 May 2027'],
|
||||
pendingActions: [
|
||||
'Account Inoperative — all txns blocked',
|
||||
'Dormant transition due 30 Sep 2027',
|
||||
'RBI Dormant Account reporting'
|
||||
],
|
||||
actionTaken: [
|
||||
'Notice 1 delivered',
|
||||
'Notice 2 delivered via Reg. Post',
|
||||
'Notice 3 — Video KYC invite sent (no response)',
|
||||
'Debit Freeze 15 Mar 2027',
|
||||
'Inoperative 15 May 2027'
|
||||
],
|
||||
evidence: {
|
||||
type: 'vkyc',
|
||||
date: '5 Mar 2027',
|
||||
@@ -252,22 +366,54 @@ export class KycManagementComponent {
|
||||
branch: 'Bhopal East'
|
||||
},
|
||||
notices: [
|
||||
{ no: 'N1', channel: 'SMS + Email', date: '1 Dec 2026', ref: 'MSG-2026-1201-009', delivery: 'Delivered', response: 'No Response' },
|
||||
{ no: 'N2', channel: 'Reg. Post', date: '11 Dec 2026', ref: 'RP-BPL-20261211-077', delivery: 'Delivered', response: 'No Response' },
|
||||
{ no: 'N3', channel: 'Branch Visit', date: '22 Dec 2026', ref: 'VIS-BPL-20261222-019', delivery: 'Not Found', response: 'Not Found at Address' }
|
||||
{
|
||||
no: 'N1',
|
||||
channel: 'SMS + Email',
|
||||
date: '1 Dec 2026',
|
||||
ref: 'MSG-2026-1201-009',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
},
|
||||
{
|
||||
no: 'N2',
|
||||
channel: 'Reg. Post',
|
||||
date: '11 Dec 2026',
|
||||
ref: 'RP-BPL-20261211-077',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
},
|
||||
{
|
||||
no: 'N3',
|
||||
channel: 'Home Visit',
|
||||
date: '22 Dec 2026',
|
||||
ref: 'VIS-BPL-20261222-019',
|
||||
delivery: 'Not Found',
|
||||
response: 'Not Found at Address'
|
||||
}
|
||||
],
|
||||
noticesSent: 3,
|
||||
noticePending: 'None',
|
||||
nextStage: 'Dormant (Final) — RBI Reporting',
|
||||
pendingActions: ['RBI Dormant Account Report submission', 'Branch Manager approval for any reversal', 'Regional Manager sign-off required'],
|
||||
actionTaken: ['Notice 1–3 sent, all no response', 'Debit Freeze 1 Jan 2027', 'Inoperative 2 Mar 2027', 'Dormant 1 Jun 2027', 'RBI report auto-generated'],
|
||||
pendingActions: [
|
||||
'RBI Dormant Account Report submission',
|
||||
'Branch Manager approval for any reversal',
|
||||
'Regional Manager sign-off required'
|
||||
],
|
||||
actionTaken: [
|
||||
'Notice 1–3 sent, all no response',
|
||||
'Debit Freeze 1 Jan 2027',
|
||||
'Inoperative 2 Mar 2027',
|
||||
'Dormant 1 Jun 2027',
|
||||
'RBI report auto-generated'
|
||||
],
|
||||
evidence: {
|
||||
type: 'visit',
|
||||
date: '22 Dec 2026',
|
||||
officer: 'Rekha Sharma',
|
||||
gps: '23.2491° N, 77.4384° E',
|
||||
location: 'Awadhpuri, Bhopal',
|
||||
outcome: 'Client not found at registered address. Neighbours confirmed relocation. Address verification required.',
|
||||
outcome:
|
||||
'Client not found at registered address. Neighbours confirmed relocation. Address verification required.',
|
||||
docket: 'VIS-BPL-20261222-019'
|
||||
}
|
||||
},
|
||||
@@ -300,12 +446,23 @@ export class KycManagementComponent {
|
||||
branch: 'Bhopal Main'
|
||||
},
|
||||
notices: [
|
||||
{ no: 'N1', channel: 'SMS + Email', date: '5 Apr 2027', ref: 'MSG-2027-0405-011', delivery: 'Delivered', response: 'No Action' }
|
||||
{
|
||||
no: 'N1',
|
||||
channel: 'SMS + Email',
|
||||
date: '5 Apr 2027',
|
||||
ref: 'MSG-2027-0405-011',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Action'
|
||||
}
|
||||
],
|
||||
noticesSent: 1,
|
||||
noticePending: 'Notice 2 & 3',
|
||||
nextStage: 'Debit Freeze if no action',
|
||||
pendingActions: ['Send Notice 2 (due 15 Apr 2027)', 'Send Notice 3 (due 25 Apr 2027)', 'Branch visit if needed'],
|
||||
pendingActions: [
|
||||
'Send Notice 2 (due 15 Apr 2027)',
|
||||
'Send Notice 3 (due 25 Apr 2027)',
|
||||
'Branch visit if needed'
|
||||
],
|
||||
actionTaken: ['Notice 1 delivered 5 Apr 2027'],
|
||||
evidence: null
|
||||
},
|
||||
@@ -338,14 +495,35 @@ export class KycManagementComponent {
|
||||
branch: 'Bhopal North'
|
||||
},
|
||||
notices: [
|
||||
{ no: 'N1', channel: 'SMS + Email', date: '29 Mar 2027', ref: 'MSG-2027-0329-014', delivery: 'Delivered', response: 'No Action' },
|
||||
{ no: 'N2', channel: 'Reg. Post + IVR', date: '8 Apr 2027', ref: 'RP-BPL-20270408-088', delivery: 'Delivered', response: 'No Response' }
|
||||
{
|
||||
no: 'N1',
|
||||
channel: 'SMS + Email',
|
||||
date: '29 Mar 2027',
|
||||
ref: 'MSG-2027-0329-014',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Action'
|
||||
},
|
||||
{
|
||||
no: 'N2',
|
||||
channel: 'Reg. Post + IVR',
|
||||
date: '8 Apr 2027',
|
||||
ref: 'RP-BPL-20270408-088',
|
||||
delivery: 'Delivered',
|
||||
response: 'No Response'
|
||||
}
|
||||
],
|
||||
noticesSent: 2,
|
||||
noticePending: 'URGENT: Notice 3',
|
||||
nextStage: 'Debit Freeze in 3 days',
|
||||
pendingActions: ['URGENT: Send Notice 3 NOW', 'Schedule Branch Visit immediately', 'Consider Video KYC as last resort'],
|
||||
actionTaken: ['Notice 1 delivered', 'Notice 2 delivered via Reg. Post + IVR'],
|
||||
pendingActions: [
|
||||
'URGENT: Send Notice 3 NOW',
|
||||
'Schedule Home Visit immediately',
|
||||
'Consider Video KYC as last resort'
|
||||
],
|
||||
actionTaken: [
|
||||
'Notice 1 delivered',
|
||||
'Notice 2 delivered via Reg. Post + IVR'
|
||||
],
|
||||
evidence: null
|
||||
}
|
||||
};
|
||||
@@ -384,6 +562,108 @@ export class KycManagementComponent {
|
||||
this.toastTimer = setTimeout(() => (this.toastVisible = false), 2800);
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes a "Take Action" click. Opens the Home Visit dialog if the action is
|
||||
* a home-visit scheduling action; otherwise falls back to a toast confirmation.
|
||||
*/
|
||||
takeAction(action: string): void {
|
||||
if (!this.current) return;
|
||||
const lower = action.toLowerCase();
|
||||
if (lower.includes('home visit')) {
|
||||
this.openHomeVisitDialog();
|
||||
return;
|
||||
}
|
||||
if (lower.includes('video kyc')) {
|
||||
this.openVkycDialog();
|
||||
return;
|
||||
}
|
||||
this.toast(action + ' initiated for ' + this.current.name);
|
||||
}
|
||||
|
||||
openHomeVisitDialog(): void {
|
||||
this.homeVisitOfficer = '';
|
||||
this.homeVisitNote = '';
|
||||
// Default to tomorrow at 10:00 AM (datetime-local format: YYYY-MM-DDTHH:mm)
|
||||
const t = new Date();
|
||||
t.setDate(t.getDate() + 1);
|
||||
t.setHours(10, 0, 0, 0);
|
||||
const pad = (n: number) => n.toString().padStart(2, '0');
|
||||
this.homeVisitDateTime = `${t.getFullYear()}-${pad(t.getMonth() + 1)}-${pad(t.getDate())}T${pad(t.getHours())}:${pad(t.getMinutes())}`;
|
||||
this.homeVisitOpen = true;
|
||||
}
|
||||
|
||||
closeHomeVisitDialog(): void {
|
||||
this.homeVisitOpen = false;
|
||||
}
|
||||
|
||||
saveHomeVisit(): void {
|
||||
if (!this.current || !this.homeVisitOfficer || !this.homeVisitDateTime) return;
|
||||
this.scheduledHomeVisits.push({
|
||||
client: this.current.name,
|
||||
address: this.current.contact.address,
|
||||
officer: this.homeVisitOfficer,
|
||||
dateTime: this.homeVisitDateTime,
|
||||
note: this.homeVisitNote
|
||||
});
|
||||
const when = new Date(this.homeVisitDateTime).toLocaleString('en-IN', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
this.toast(`Home Visit scheduled for ${this.current.name} on ${when}`);
|
||||
this.homeVisitOpen = false;
|
||||
}
|
||||
|
||||
openVkycDialog(): void {
|
||||
this.vkycOfficer = '';
|
||||
this.vkycMessage = '';
|
||||
this.vkycChannels = { sms: true, email: true, whatsapp: false };
|
||||
// Default: link expires 48 hours from now (RBI Video-based KYC norms)
|
||||
const t = new Date();
|
||||
t.setHours(t.getHours() + 48);
|
||||
const pad = (n: number) => n.toString().padStart(2, '0');
|
||||
this.vkycExpiry = `${t.getFullYear()}-${pad(t.getMonth() + 1)}-${pad(t.getDate())}T${pad(t.getHours())}:${pad(t.getMinutes())}`;
|
||||
// Generate a session id (token preview only — server would issue the real one)
|
||||
this.vkycSessionId = 'VKYC-' + Math.random().toString(36).slice(2, 10).toUpperCase();
|
||||
this.vkycOpen = true;
|
||||
}
|
||||
|
||||
closeVkycDialog(): void {
|
||||
this.vkycOpen = false;
|
||||
}
|
||||
|
||||
get vkycSelectedChannels(): string[] {
|
||||
const out: string[] = [];
|
||||
if (this.vkycChannels.sms) out.push('SMS');
|
||||
if (this.vkycChannels.email) out.push('Email');
|
||||
if (this.vkycChannels.whatsapp) out.push('WhatsApp');
|
||||
return out;
|
||||
}
|
||||
|
||||
get vkycLink(): string {
|
||||
return `https://vkyc.bank.example/session/${this.vkycSessionId}`;
|
||||
}
|
||||
|
||||
saveVkyc(): void {
|
||||
if (!this.current || !this.vkycOfficer || !this.vkycExpiry) return;
|
||||
const channels = this.vkycSelectedChannels;
|
||||
if (channels.length === 0) return;
|
||||
this.sentVkycLinks.push({
|
||||
client: this.current.name,
|
||||
mobile: this.current.contact.mobile,
|
||||
email: this.current.contact.email,
|
||||
officer: this.vkycOfficer,
|
||||
expiry: this.vkycExpiry,
|
||||
channels,
|
||||
sessionId: this.vkycSessionId,
|
||||
link: this.vkycLink
|
||||
});
|
||||
this.toast(`Video KYC link sent to ${this.current.name} via ${channels.join(' + ')}`);
|
||||
this.vkycOpen = false;
|
||||
}
|
||||
|
||||
/** Compliance journey stepper state for a given client */
|
||||
getStepperState(c: KmClient): { label: string; state: 'done' | 'pending' | 'current' | 'danger' }[] {
|
||||
return [
|
||||
@@ -393,19 +673,20 @@ export class KycManagementComponent {
|
||||
{
|
||||
label: 'Notice 3',
|
||||
state:
|
||||
c.noticesSent >= 3
|
||||
? 'done'
|
||||
: c.noticesSent >= 2
|
||||
? c.state === 'urgent'
|
||||
? 'danger'
|
||||
: 'current'
|
||||
: 'pending'
|
||||
c.noticesSent >= 3 ? 'done' : c.noticesSent >= 2 ? (c.state === 'urgent' ? 'danger' : 'current') : 'pending'
|
||||
},
|
||||
{
|
||||
label: 'Debit Freeze',
|
||||
state: ['freeze', 'inop', 'dormant'].includes(c.state) ? 'done' : c.noticesSent >= 3 ? 'danger' : 'pending'
|
||||
state: [
|
||||
'freeze',
|
||||
'inop',
|
||||
'dormant'
|
||||
].includes(c.state) ? 'done' : c.noticesSent >= 3 ? 'danger' : 'pending'
|
||||
},
|
||||
{ label: 'Inoperative', state: ['inop', 'dormant'].includes(c.state) ? 'done' : 'pending' },
|
||||
{ label: 'Inoperative', state: [
|
||||
'inop',
|
||||
'dormant'
|
||||
].includes(c.state) ? 'done' : 'pending' },
|
||||
{ label: 'Dormant', state: c.state === 'dormant' ? 'danger' : 'pending' }
|
||||
];
|
||||
}
|
||||
@@ -418,26 +699,30 @@ export class KycManagementComponent {
|
||||
|
||||
stateLabel(state: string): string {
|
||||
return (
|
||||
{
|
||||
alert: 'Alert Window',
|
||||
freeze: 'Debit Freeze',
|
||||
inop: 'Inoperative',
|
||||
dormant: 'Dormant',
|
||||
urgent: 'Urgent Alert'
|
||||
} as Record<string, string>
|
||||
)[state] || state;
|
||||
(
|
||||
{
|
||||
alert: 'Alert Window',
|
||||
freeze: 'Debit Freeze',
|
||||
inop: 'Inoperative',
|
||||
dormant: 'Dormant',
|
||||
urgent: 'Urgent Alert'
|
||||
} as Record<string, string>
|
||||
)[state] || state
|
||||
);
|
||||
}
|
||||
|
||||
stateClass(state: string): string {
|
||||
return (
|
||||
{
|
||||
alert: 'sp-al',
|
||||
freeze: 'sp-fr',
|
||||
inop: 'sp-in',
|
||||
dormant: 'sp-do',
|
||||
urgent: 'sp-fr'
|
||||
} as Record<string, string>
|
||||
)[state] || 'sp-al';
|
||||
(
|
||||
{
|
||||
alert: 'sp-al',
|
||||
freeze: 'sp-fr',
|
||||
inop: 'sp-in',
|
||||
dormant: 'sp-do',
|
||||
urgent: 'sp-fr'
|
||||
} as Record<string, string>
|
||||
)[state] || 'sp-al'
|
||||
);
|
||||
}
|
||||
|
||||
riskClass(risk: string): string {
|
||||
|
||||
Reference in New Issue
Block a user