feat: add CFCFRMS module, bank menus, mock backend, and dashboard redesign
- CFCFRMS cyber fraud complaint management with dashboard, complaints, escalation, report suspect/mule/fraud txn, FMR submission, CFR lookup - Mock HTTP interceptor with 20 dummy complaints and all endpoints - Simulator service for I4C/MHA integration testing - 3-row menu bar with 22 items (7+8+8 layout) - Mega menus for General Ledger, Sub Ledger, Deposits, Share, Others, HRM, RBI with search and grouped columns - Dropdowns for Cashier, Clearing, NPA, CKYC, Advances, Letter Mgmt, Insurance, Digital - Dashboard redesign with regulatory, financial health, deposits, risk/NPA sections using static banking data - All translations added to en-US.json - FontAwesome icons registered for all new menu items Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
0a32d7135e
commit
b3a4cce0cf
@@ -0,0 +1,220 @@
|
||||
<!--
|
||||
Copyright since 2025 Mifos Initiative
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
|
||||
<div class="escalate-page">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.menus.Escalate Complaint' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Forward complaint to the next bank in the transaction chain' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="escalate-layout">
|
||||
<!-- Escalation Form -->
|
||||
<mat-card class="escalate-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<fa-icon icon="arrow-up" class="mr-05"></fa-icon> {{ 'labels.text.Escalation Form' | translate }}
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
@if (escalationResult) {
|
||||
<div class="success-result">
|
||||
<div class="success-icon">
|
||||
<fa-icon icon="check-circle" size="3x"></fa-icon>
|
||||
</div>
|
||||
<h3>{{ 'labels.text.Escalation Successful' | translate }}</h3>
|
||||
<div class="result-details">
|
||||
<div class="result-row">
|
||||
<span class="result-label">{{ 'labels.text.Reference Number' | translate }}</span>
|
||||
<span class="result-value mono">{{ escalationResult.referenceNumber }}</span>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span class="result-label">{{ 'labels.text.Ticket ID' | translate }}</span>
|
||||
<span class="result-value">{{ escalationResult.ticketId }}</span>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span class="result-label">{{ 'labels.text.Escalated To' | translate }}</span>
|
||||
<span class="result-value">{{ escalationResult.escalatedTo }}</span>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span class="result-label">{{ 'labels.text.Bank IFSC' | translate }}</span>
|
||||
<span class="result-value mono">{{ escalationResult.escalatedBankIfsc }}</span>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span class="result-label">{{ 'labels.text.Status' | translate }}</span>
|
||||
<span class="result-value">{{ escalationResult.status }}</span>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span class="result-label">{{ 'labels.text.Timestamp' | translate }}</span>
|
||||
<span class="result-value">{{ escalationResult.timestamp }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button mat-raised-button color="primary" (click)="resetForm()" class="mt-16">
|
||||
<fa-icon icon="plus" class="mr-05"></fa-icon> {{ 'labels.text.New Escalation' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
} @else {
|
||||
<form [formGroup]="escalateForm" (ngSubmit)="onSubmit()">
|
||||
<div class="ticket-lookup-row">
|
||||
<mat-form-field appearance="outline" class="ticket-field">
|
||||
<mat-label>{{ 'labels.text.Ticket ID' | translate }}</mat-label>
|
||||
<input matInput formControlName="ticketId" placeholder="e.g. CFCFRMS-2024-00001" />
|
||||
@if (escalateForm.get('ticketId')?.hasError('required') && escalateForm.get('ticketId')?.touched) {
|
||||
<mat-error>{{ 'labels.text.Ticket ID' | translate }} is required</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<button
|
||||
mat-raised-button
|
||||
type="button"
|
||||
(click)="lookupTicket()"
|
||||
[disabled]="isLookingUp"
|
||||
class="lookup-btn"
|
||||
>
|
||||
@if (isLookingUp) {
|
||||
<mat-spinner diameter="20"></mat-spinner>
|
||||
} @else {
|
||||
<fa-icon icon="search" class="mr-05"></fa-icon> {{ 'labels.text.Lookup' | translate }}
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (lookedUpComplaint) {
|
||||
<div class="lookup-result">
|
||||
<div class="lookup-row">
|
||||
<span>{{ 'labels.text.Complainant' | translate }}:</span>
|
||||
<strong>{{ lookedUpComplaint.complainantName }}</strong>
|
||||
</div>
|
||||
<div class="lookup-row">
|
||||
<span>{{ 'labels.text.Fraud Amount' | translate }}:</span>
|
||||
<strong>{{ formatCurrency(lookedUpComplaint.fraudAmount) }}</strong>
|
||||
</div>
|
||||
<div class="lookup-row">
|
||||
<span>{{ 'labels.text.Suspect Account' | translate }}:</span>
|
||||
<strong class="mono">{{ lookedUpComplaint.suspectAccountNumber }}</strong>
|
||||
</div>
|
||||
<div class="lookup-row">
|
||||
<span>{{ 'labels.text.Current Status' | translate }}:</span>
|
||||
<cfcfrms-status-badge [status]="lookedUpComplaint.status"></cfcfrms-status-badge>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>{{ 'labels.text.Next Hop Account Number' | translate }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
formControlName="nextHopAccountNumber"
|
||||
placeholder="{{ 'labels.text.Account Number' | translate }}"
|
||||
/>
|
||||
@if (
|
||||
escalateForm.get('nextHopAccountNumber')?.hasError('required') &&
|
||||
escalateForm.get('nextHopAccountNumber')?.touched
|
||||
) {
|
||||
<mat-error>{{ 'labels.text.Account number is required' | translate }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>{{ 'labels.text.Next Hop Bank IFSC' | translate }}</mat-label>
|
||||
<input matInput formControlName="nextHopBankIfsc" placeholder="e.g. SBIN0000001" />
|
||||
@if (
|
||||
escalateForm.get('nextHopBankIfsc')?.hasError('required') &&
|
||||
escalateForm.get('nextHopBankIfsc')?.touched
|
||||
) {
|
||||
<mat-error>{{ 'labels.text.IFSC code is required' | translate }}</mat-error>
|
||||
}
|
||||
@if (
|
||||
escalateForm.get('nextHopBankIfsc')?.hasError('pattern') && escalateForm.get('nextHopBankIfsc')?.touched
|
||||
) {
|
||||
<mat-error>{{ 'labels.text.Invalid IFSC format' | translate }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>{{ 'labels.text.Remarks' | translate }}</mat-label>
|
||||
<textarea
|
||||
matInput
|
||||
formControlName="remarks"
|
||||
rows="4"
|
||||
placeholder="{{ 'labels.text.Reason for escalation...' | translate }}"
|
||||
></textarea>
|
||||
@if (escalateForm.get('remarks')?.hasError('required') && escalateForm.get('remarks')?.touched) {
|
||||
<mat-error>{{ 'labels.text.Remarks are required' | translate }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
type="submit"
|
||||
[disabled]="isSubmitting"
|
||||
class="full-width submit-btn"
|
||||
>
|
||||
@if (isSubmitting) {
|
||||
<mat-spinner diameter="20" class="inline-spinner"></mat-spinner>
|
||||
} @else {
|
||||
<fa-icon icon="paper-plane" class="mr-05"></fa-icon> {{ 'labels.text.Submit Escalation' | translate }}
|
||||
}
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<!-- Instructions Panel -->
|
||||
<mat-card class="instructions-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<fa-icon icon="info-circle" class="mr-05"></fa-icon> {{ 'labels.text.Escalation Guidelines' | translate }}
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="guidelines">
|
||||
<div class="guideline-item">
|
||||
<fa-icon icon="check" class="guideline-icon"></fa-icon>
|
||||
<p>{{ 'labels.text.Verify the complaint details before escalating to the next bank.' | translate }}</p>
|
||||
</div>
|
||||
<div class="guideline-item">
|
||||
<fa-icon icon="check" class="guideline-icon"></fa-icon>
|
||||
<p>
|
||||
{{
|
||||
'labels.text.Ensure the Next Hop Account and IFSC belong to the next bank in the fraud transaction chain.'
|
||||
| translate
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="guideline-item">
|
||||
<fa-icon icon="check" class="guideline-icon"></fa-icon>
|
||||
<p>{{ 'labels.text.Provide clear and detailed remarks explaining the escalation reason.' | translate }}</p>
|
||||
</div>
|
||||
<div class="guideline-item">
|
||||
<fa-icon icon="exclamation-triangle" class="guideline-icon warn"></fa-icon>
|
||||
<p>{{ 'labels.text.Escalation must be completed within the I4C/MHA mandated timeline.' | translate }}</p>
|
||||
</div>
|
||||
<div class="guideline-item">
|
||||
<fa-icon icon="exclamation-triangle" class="guideline-icon warn"></fa-icon>
|
||||
<p>
|
||||
{{
|
||||
'labels.text.Once escalated, the complaint will be forwarded to the target bank for action.' | translate
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bank-info">
|
||||
<h4>{{ 'labels.text.Current Bank Info' | translate }}</h4>
|
||||
<div class="bank-row">
|
||||
<span>{{ 'labels.text.Bank Name' | translate }}:</span> <strong>LincPay</strong>
|
||||
</div>
|
||||
<div class="bank-row">
|
||||
<span>{{ 'labels.text.Bank IFSC' | translate }}:</span> <strong class="mono">LINC0000001</strong>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user