feat: KYC re-verify UX, family/nominee tab gating, savings dialogs, cfcfrms shell
- KYC tab: fix Verify (PAN) and Send OTP (Aadhaar) being disabled in edit mode; unmask Aadhaar input and show on-file masked value as hint; resolve kycId from id/kycId/resourceId fallbacks. - Client stepper/view: add familyAllowed / nomineeAllowed predicates + CanActivate route guards. Family tab hidden for non-individuals, Nominee tab hidden for non-proprietor entities. Family-members step accepts a nomineeOnly input for proprietorship clients. Add/Edit/Delete buttons inside family-members and nominee tabs gated by canAdd. - cfcfrms: add cfcfrms-shell wrapper, restyle complaint/fraud/mule/escalate pages and dashboard. - Savings: identity-verify and transaction-confirm dialogs, manage / activate / add-charge flows, account preview styling. - Tasks, core shell, account-nominees, icons: minor style and behaviour updates. 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
bf3e26a0d0
commit
b149fef72e
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
/* Shared Nexora skin for CFCFRMS form pages (escalate, report-suspect,
|
||||
report-mule, report-fraud-txn, fmr-submission). Each component @use's
|
||||
this partial and @include's `cfc-form-skin($accent)`.
|
||||
|
||||
$accent: 'blue' | 'red' — controls the title-bar gradient + submit
|
||||
button colour. */
|
||||
|
||||
@mixin cfc-form-skin($accent: 'blue') {
|
||||
$accent-from: #3b82f6;
|
||||
$accent-to: #1e40af;
|
||||
$accent-shadow: rgb(30 64 175 / 30%);
|
||||
$submit-from: #1e88e5;
|
||||
$submit-to: #1e40af;
|
||||
|
||||
@if $accent == 'red' {
|
||||
$accent-from: #ef4444;
|
||||
$accent-to: #991b1b;
|
||||
$accent-shadow: rgb(153 27 27 / 35%);
|
||||
$submit-from: #dc2626;
|
||||
$submit-to: #991b1b;
|
||||
}
|
||||
|
||||
/* ─── Card chrome (overrides Material's mat-card) ─────────────────── */
|
||||
.report-card,
|
||||
.escalate-card,
|
||||
.instructions-card {
|
||||
border-radius: 14px !important;
|
||||
border: 1px solid #e2e8f0 !important;
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 4%) !important;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
|
||||
::ng-deep .mat-mdc-card-header {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
display: block;
|
||||
background: #f8fafc;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-card-title {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin: 0 !important;
|
||||
padding: 14px 18px;
|
||||
font-size: 14.5px !important;
|
||||
font-weight: 700 !important;
|
||||
color: #0d1b2a;
|
||||
letter-spacing: 0.01em;
|
||||
line-height: 1;
|
||||
|
||||
/* Promote the FA icon into a small gradient tile. */
|
||||
.fa-icon,
|
||||
fa-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, $accent-from 0%, $accent-to 100%);
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
box-shadow: 0 2px 6px -2px $accent-shadow;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-card-content {
|
||||
padding: 22px !important;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Form fields (consistent compact density) ────────────────────── */
|
||||
.full-width,
|
||||
.half-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Tighten the default Material outlined field — the dashboard hero +
|
||||
pill tabs are compact, so the form fields should match. */
|
||||
::ng-deep .mat-mdc-form-field {
|
||||
margin-bottom: 2px;
|
||||
|
||||
.mat-mdc-text-field-wrapper {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.mdc-notched-outline__leading,
|
||||
.mdc-notched-outline__notch,
|
||||
.mdc-notched-outline__trailing {
|
||||
border-color: #cbd5e1 !important;
|
||||
}
|
||||
|
||||
&.mat-focused {
|
||||
.mdc-notched-outline__leading,
|
||||
.mdc-notched-outline__notch,
|
||||
.mdc-notched-outline__trailing {
|
||||
border-color: $accent-to !important;
|
||||
border-width: 2px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-form-field-infix {
|
||||
min-height: 48px;
|
||||
padding-top: 12px !important;
|
||||
padding-bottom: 12px !important;
|
||||
}
|
||||
|
||||
.mat-mdc-form-field-icon-suffix {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Datepicker icon size + tone */
|
||||
::ng-deep .mat-datepicker-toggle .mat-mdc-icon-button {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* ─── Form layout helpers ────────────────────────────────────────── */
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
|
||||
@media (width <= 720px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.ticket-lookup-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: 12px;
|
||||
align-items: start;
|
||||
|
||||
.ticket-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.lookup-btn {
|
||||
height: 48px !important;
|
||||
margin-top: 0;
|
||||
border-radius: 10px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Submit button ───────────────────────────────────────────────── */
|
||||
.submit-btn {
|
||||
margin-top: 10px;
|
||||
height: 46px !important;
|
||||
border-radius: 12px !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 700 !important;
|
||||
letter-spacing: 0.02em !important;
|
||||
background: linear-gradient(135deg, $submit-from 0%, $submit-to 100%) !important;
|
||||
color: #fff !important;
|
||||
box-shadow: 0 4px 12px -2px $accent-shadow !important;
|
||||
transition:
|
||||
filter 0.15s ease,
|
||||
transform 0.1s ease;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
filter: brightness(1.05);
|
||||
}
|
||||
|
||||
&:active:not(:disabled) {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.55;
|
||||
filter: grayscale(0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.inline-spinner {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* ─── Success result panel ───────────────────────────────────────── */
|
||||
.success-result {
|
||||
text-align: center;
|
||||
padding: 14px 0 6px;
|
||||
|
||||
.success-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: 0 auto 14px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #34d399 0%, #047857 100%);
|
||||
color: #fff;
|
||||
box-shadow: 0 8px 22px -8px rgb(4 120 87 / 50%);
|
||||
|
||||
fa-icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 18px;
|
||||
color: #065f46;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
}
|
||||
|
||||
.result-details {
|
||||
text-align: left;
|
||||
max-width: 520px;
|
||||
margin: 0 auto;
|
||||
background: #f0fdf4;
|
||||
border: 1px solid #bbf7d0;
|
||||
border-radius: 12px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px dashed #bbf7d0;
|
||||
font-size: 13px;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
color: #475569;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-weight: 700;
|
||||
color: #0d1b2a;
|
||||
text-align: right;
|
||||
|
||||
&.mono {
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
color: #1e40af;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-flagged {
|
||||
color: #b91c1c !important;
|
||||
font-weight: 800 !important;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mr-05 {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.mt-16 {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Two-column "form + side panel" layout ─────────────────────────── */
|
||||
@mixin cfc-side-layout {
|
||||
.report-layout,
|
||||
.escalate-layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 16px;
|
||||
|
||||
/* Promote to two-column once the right-hand panel exists (escalate). */
|
||||
&:has(.instructions-card) {
|
||||
grid-template-columns: minmax(0, 1fr) 360px;
|
||||
|
||||
@media (width <= 1100px) {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { Route } from '../core/route/route.service';
|
||||
import { CfcfrmsShellComponent } from './cfcfrms-shell/cfcfrms-shell.component';
|
||||
import { CfcfrmsDashboardComponent } from './dashboard/cfcfrms-dashboard.component';
|
||||
import { ComplaintListComponent } from './complaint-list/complaint-list.component';
|
||||
import { ComplaintDetailComponent } from './complaint-detail/complaint-detail.component';
|
||||
@@ -23,6 +24,7 @@ const routes: Routes = [
|
||||
Route.withShell([
|
||||
{
|
||||
path: 'cfcfrms',
|
||||
component: CfcfrmsShellComponent,
|
||||
data: { title: 'CFCFRMS', breadcrumb: 'CFCFRMS' },
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<!--
|
||||
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="cfc-container">
|
||||
<!-- Hero header -->
|
||||
<div class="cfc-header">
|
||||
<div class="cfc-header__left">
|
||||
<fa-icon icon="user-shield" class="cfc-header__icon"></fa-icon>
|
||||
<div>
|
||||
<h2 class="cfc-header__title">CFCFRMS</h2>
|
||||
<div class="cfc-header__sub">
|
||||
Cyber Fraud Complaint Management & Reporting — track complaints, escalate, and report suspect / mule
|
||||
/ fraud transactions.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pill-style tab navigation -->
|
||||
<nav mat-tab-nav-bar class="cfc-tabs" [tabPanel]="tabPanel">
|
||||
<a
|
||||
mat-tab-link
|
||||
class="cfc-tab"
|
||||
[routerLink]="['./dashboard']"
|
||||
routerLinkActive
|
||||
#dashboard="routerLinkActive"
|
||||
[active]="dashboard.isActive"
|
||||
>
|
||||
<fa-icon icon="chart-line" class="cfc-tab__ic"></fa-icon>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="cfc-tab"
|
||||
[routerLink]="['./complaints']"
|
||||
routerLinkActive
|
||||
#complaints="routerLinkActive"
|
||||
[active]="complaints.isActive"
|
||||
>
|
||||
<fa-icon icon="list-alt" class="cfc-tab__ic"></fa-icon>
|
||||
<span>Complaints</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="cfc-tab"
|
||||
[routerLink]="['./escalate']"
|
||||
routerLinkActive
|
||||
#escalate="routerLinkActive"
|
||||
[active]="escalate.isActive"
|
||||
>
|
||||
<fa-icon icon="arrow-up" class="cfc-tab__ic"></fa-icon>
|
||||
<span>Escalate</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="cfc-tab cfc-tab--danger"
|
||||
[routerLink]="['./report-suspect']"
|
||||
routerLinkActive
|
||||
#suspect="routerLinkActive"
|
||||
[active]="suspect.isActive"
|
||||
>
|
||||
<fa-icon icon="user-slash" class="cfc-tab__ic"></fa-icon>
|
||||
<span>Report Suspect</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="cfc-tab cfc-tab--danger"
|
||||
[routerLink]="['./report-mule']"
|
||||
routerLinkActive
|
||||
#mule="routerLinkActive"
|
||||
[active]="mule.isActive"
|
||||
>
|
||||
<fa-icon icon="ban" class="cfc-tab__ic"></fa-icon>
|
||||
<span>Report Mule</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="cfc-tab cfc-tab--danger"
|
||||
[routerLink]="['./report-fraud-txn']"
|
||||
routerLinkActive
|
||||
#fraud="routerLinkActive"
|
||||
[active]="fraud.isActive"
|
||||
>
|
||||
<fa-icon icon="exclamation-triangle" class="cfc-tab__ic"></fa-icon>
|
||||
<span>Report Fraud Txn</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<mat-tab-nav-panel #tabPanel>
|
||||
<div class="cfc-body">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</mat-tab-nav-panel>
|
||||
</div>
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
$navy: #0d1b2a;
|
||||
$blue: #1e88e5;
|
||||
$blue-d: #1e40af;
|
||||
$indigo: #4f46e5;
|
||||
$red: #dc2626;
|
||||
$red-d: #991b1b;
|
||||
|
||||
.cfc-container {
|
||||
padding: 20px 24px;
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cfc-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&__left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, $blue 0%, $indigo 100%);
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
box-shadow: 0 2px 8px rgb(29 78 216 / 25%);
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
color: $navy;
|
||||
line-height: 1.1;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
&__sub {
|
||||
margin-top: 2px;
|
||||
font-size: 12.5px;
|
||||
color: #64748b;
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pill-style tab navigation */
|
||||
.cfc-tabs {
|
||||
margin-bottom: 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 14px;
|
||||
padding: 6px;
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
|
||||
overflow: hidden;
|
||||
|
||||
::ng-deep {
|
||||
.mat-mdc-tab-link-container {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.mat-mdc-tab-links {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.mdc-tab-indicator__content--underline,
|
||||
.mat-mdc-tab-header-pagination-controls-enabled .mdc-tab-indicator__content--underline {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cfc-tab {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 38px !important;
|
||||
min-width: 0 !important;
|
||||
padding: 0 18px !important;
|
||||
border-radius: 10px !important;
|
||||
font-family: Inter, 'DM Sans', Roboto, sans-serif !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
letter-spacing: 0.01em !important;
|
||||
color: #64748b !important;
|
||||
background: transparent !important;
|
||||
transition: all 0.15s ease;
|
||||
white-space: nowrap;
|
||||
border: 1px solid transparent !important;
|
||||
opacity: 1 !important;
|
||||
|
||||
&__ic {
|
||||
font-size: 13px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&:hover:not(.mdc-tab--active) {
|
||||
background: #f1f5f9 !important;
|
||||
color: $navy !important;
|
||||
}
|
||||
|
||||
&.mdc-tab--active,
|
||||
&.mat-mdc-tab-link-active {
|
||||
background: linear-gradient(135deg, $blue 0%, $blue-d 100%) !important;
|
||||
color: #fff !important;
|
||||
box-shadow: 0 2px 6px -1px rgb(30 64 175 / 35%);
|
||||
border-color: $blue-d !important;
|
||||
|
||||
::ng-deep .mdc-tab__text-label,
|
||||
::ng-deep .mat-mdc-tab-link-content,
|
||||
::ng-deep span,
|
||||
.cfc-tab__ic {
|
||||
color: #fff !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Danger-flavour tabs (the three reporting tabs) glow red when active so
|
||||
users can see at a glance that they're on a high-impact submission flow. */
|
||||
&--danger {
|
||||
&.mdc-tab--active,
|
||||
&.mat-mdc-tab-link-active {
|
||||
background: linear-gradient(135deg, $red 0%, $red-d 100%) !important;
|
||||
box-shadow: 0 2px 6px -1px rgb(153 27 27 / 40%);
|
||||
border-color: $red-d !important;
|
||||
}
|
||||
|
||||
&:hover:not(.mdc-tab--active) {
|
||||
background: #fef2f2 !important;
|
||||
color: $red-d !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cfc-body {
|
||||
/* Sub-pages no longer carry their own page-header (the hero above already
|
||||
does that). Add a little breathing room and let their content cards
|
||||
stand on their own. */
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (width <= 768px) {
|
||||
.cfc-tabs {
|
||||
overflow-x: auto;
|
||||
|
||||
::ng-deep .mat-mdc-tab-links {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.cfc-tab {
|
||||
padding: 0 14px !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { MatTabNav, MatTabLink, MatTabNavPanel } from '@angular/material/tabs';
|
||||
import { RouterLinkActive, RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
/**
|
||||
* CFCFRMS Shell — single landing page that exposes the full Cyber Fraud
|
||||
* Complaint Management workflow (Dashboard, Complaints, Escalate, Suspect /
|
||||
* Mule / Fraud reporting) as pill-style tabs above a router-outlet.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-cfcfrms-shell',
|
||||
templateUrl: './cfcfrms-shell.component.html',
|
||||
styleUrls: ['./cfcfrms-shell.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatTabNav,
|
||||
MatTabLink,
|
||||
RouterLinkActive,
|
||||
MatTabNavPanel,
|
||||
RouterOutlet,
|
||||
FaIconComponent
|
||||
]
|
||||
})
|
||||
export class CfcfrmsShellComponent {}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CfcfrmsRoutingModule } from './cfcfrms-routing.module';
|
||||
import { CfcfrmsShellComponent } from './cfcfrms-shell/cfcfrms-shell.component';
|
||||
import { CfcfrmsDashboardComponent } from './dashboard/cfcfrms-dashboard.component';
|
||||
import { ComplaintListComponent } from './complaint-list/complaint-list.component';
|
||||
import { ComplaintDetailComponent } from './complaint-detail/complaint-detail.component';
|
||||
@@ -21,6 +22,7 @@ import { CfrLookupComponent } from './cfr-lookup/cfr-lookup.component';
|
||||
@NgModule({
|
||||
imports: [
|
||||
CfcfrmsRoutingModule,
|
||||
CfcfrmsShellComponent,
|
||||
CfcfrmsDashboardComponent,
|
||||
ComplaintListComponent,
|
||||
ComplaintDetailComponent,
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
-->
|
||||
|
||||
<div class="cfr-lookup-page">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.text.CFR Lookup' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Query RBI Central Fraud Registry before customer onboarding' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Search Card -->
|
||||
<mat-card class="search-card">
|
||||
<mat-card-content>
|
||||
|
||||
@@ -7,27 +7,12 @@
|
||||
*/
|
||||
|
||||
.cfr-lookup-page {
|
||||
padding: 24px;
|
||||
/* Wrapper hero already handles outer padding. */
|
||||
padding: 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,22 @@
|
||||
-->
|
||||
|
||||
<div class="complaint-detail-page">
|
||||
<div class="page-header">
|
||||
<a mat-icon-button routerLink="/cfcfrms/complaints" matTooltip="{{ 'labels.text.Back to Complaints' | translate }}">
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
<!-- Sub-toolbar: back-link + ticket id chip. The wrapper hero owns the
|
||||
page title so we just need contextual navigation here. -->
|
||||
<div class="cfc-subtoolbar">
|
||||
<a
|
||||
mat-stroked-button
|
||||
class="cfc-back-btn"
|
||||
routerLink="/cfcfrms/complaints"
|
||||
matTooltip="{{ 'labels.text.Back to Complaints' | translate }}"
|
||||
>
|
||||
<fa-icon icon="arrow-left" class="mr-05"></fa-icon>
|
||||
{{ 'labels.text.Back' | translate }}
|
||||
</a>
|
||||
<div>
|
||||
<h2>{{ 'labels.menus.Complaint Detail' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Ticket ID' | translate }}: {{ ticketId }}</p>
|
||||
</div>
|
||||
<span class="cfc-subtoolbar__ticket">
|
||||
<fa-icon icon="hashtag"></fa-icon>
|
||||
{{ ticketId }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@if (isLoading) {
|
||||
|
||||
@@ -7,29 +7,38 @@
|
||||
*/
|
||||
|
||||
.complaint-detail-page {
|
||||
padding: 24px;
|
||||
padding: 0;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
/* Sub-toolbar (back-button + ticket chip). Lives under the wrapper hero. */
|
||||
.cfc-subtoolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
margin-bottom: 18px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #0d1b2a;
|
||||
&__ticket {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
background: #eff6ff;
|
||||
color: #1e40af;
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
border: 1px solid #bfdbfe;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 2px 0 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
}
|
||||
.cfc-back-btn {
|
||||
height: 36px !important;
|
||||
border-radius: 10px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
-->
|
||||
|
||||
<div class="complaint-list-page">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h2>{{ 'labels.menus.Complaint Management' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.I4C/MHA CFCFRMS Complaint Tickets' | translate }}</p>
|
||||
</div>
|
||||
<!-- Toolbar (export sits at the right; the wrapper's hero header
|
||||
already conveys the page title) -->
|
||||
<div class="cfc-subtoolbar">
|
||||
<span class="cfc-subtoolbar__hint">{{ 'labels.text.I4C/MHA CFCFRMS Complaint Tickets' | translate }}</span>
|
||||
<span class="cfc-subtoolbar__spacer"></span>
|
||||
<button mat-raised-button color="accent" (click)="exportCsv()" [disabled]="complaints.length === 0">
|
||||
<fa-icon icon="file-csv" class="mr-05"></fa-icon> {{ 'labels.text.Export CSV' | translate }}
|
||||
</button>
|
||||
|
||||
@@ -6,46 +6,73 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
$navy: #0d1b2a;
|
||||
$slate: #475569;
|
||||
$muted: #64748b;
|
||||
$border: #e2e8f0;
|
||||
$soft: #f8fafc;
|
||||
|
||||
.complaint-list-page {
|
||||
padding: 24px;
|
||||
/* Wrapper hero owns the page chrome — sub-page just needs to breathe. */
|
||||
padding: 0;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
/* ─── Sub-toolbar (hint + export) ───────────────────────────────────── */
|
||||
.cfc-subtoolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #0d1b2a;
|
||||
&__hint {
|
||||
font-size: 13px;
|
||||
color: $muted;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
&__spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-raised-button {
|
||||
border-radius: 10px !important;
|
||||
height: 38px !important;
|
||||
font-weight: 600 !important;
|
||||
letter-spacing: 0.01em !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Status pill-chip bar ──────────────────────────────────────────── */
|
||||
.filter-chips {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
gap: 8px;
|
||||
margin-bottom: 14px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
button {
|
||||
border-radius: 20px !important;
|
||||
font-size: 13px;
|
||||
height: 34px !important;
|
||||
padding: 0 14px !important;
|
||||
border-radius: 999px !important;
|
||||
font-size: 12.5px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1px solid $border !important;
|
||||
background: #fff !important;
|
||||
color: $slate !important;
|
||||
transition: all 0.15s ease;
|
||||
|
||||
&:hover:not(.active-chip) {
|
||||
background: #f1f5f9 !important;
|
||||
color: $navy !important;
|
||||
}
|
||||
}
|
||||
|
||||
.active-chip {
|
||||
background: #1e88e5 !important;
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1e40af 100%) !important;
|
||||
color: #fff !important;
|
||||
border-color: #1e88e5 !important;
|
||||
border-color: #1e40af !important;
|
||||
box-shadow: 0 2px 6px -1px rgb(30 64 175 / 35%);
|
||||
}
|
||||
|
||||
.chip-dot {
|
||||
@@ -69,12 +96,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Filter bar (Nexora card chrome) ───────────────────────────────── */
|
||||
.filter-bar {
|
||||
margin-bottom: 16px;
|
||||
border-radius: 8px !important;
|
||||
border-radius: 12px !important;
|
||||
border: 1px solid $border !important;
|
||||
background: #fff !important;
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 4%) !important;
|
||||
|
||||
mat-card-content {
|
||||
padding: 12px 16px !important;
|
||||
::ng-deep .mat-mdc-card-content {
|
||||
padding: 14px 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,13 +118,48 @@
|
||||
.filter-field {
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.table-card {
|
||||
border-radius: 8px !important;
|
||||
/* Compact form-field density inside the filter bar */
|
||||
::ng-deep .filter-bar .mat-mdc-form-field {
|
||||
.mat-mdc-text-field-wrapper {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
mat-card-content {
|
||||
.mat-mdc-form-field-infix {
|
||||
min-height: 42px;
|
||||
padding-top: 9px !important;
|
||||
padding-bottom: 9px !important;
|
||||
}
|
||||
|
||||
.mdc-notched-outline__leading,
|
||||
.mdc-notched-outline__notch,
|
||||
.mdc-notched-outline__trailing {
|
||||
border-color: #cbd5e1 !important;
|
||||
}
|
||||
|
||||
&.mat-focused {
|
||||
.mdc-notched-outline__leading,
|
||||
.mdc-notched-outline__notch,
|
||||
.mdc-notched-outline__trailing {
|
||||
border-color: #1e40af !important;
|
||||
border-width: 2px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Table card ────────────────────────────────────────────────────── */
|
||||
.table-card {
|
||||
border-radius: 12px !important;
|
||||
border: 1px solid $border !important;
|
||||
background: #fff !important;
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 4%) !important;
|
||||
overflow: hidden;
|
||||
|
||||
::ng-deep .mat-mdc-card-content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
@@ -106,10 +172,41 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::ng-deep .table-card {
|
||||
.mat-mdc-header-cell {
|
||||
background: $soft;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: $slate;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid $border;
|
||||
}
|
||||
|
||||
.mat-mdc-cell {
|
||||
font-size: 13.5px;
|
||||
color: $navy;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.mat-mdc-row:hover {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.mat-mdc-paginator {
|
||||
border-top: 1px solid $border;
|
||||
background: $soft;
|
||||
}
|
||||
}
|
||||
|
||||
.ticket-link {
|
||||
color: #1e88e5;
|
||||
color: #1e40af;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
@@ -117,31 +214,46 @@
|
||||
}
|
||||
|
||||
.amount-cell {
|
||||
font-weight: 600;
|
||||
color: #0d1b2a;
|
||||
font-weight: 700;
|
||||
color: $navy;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
color: $navy;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 48px;
|
||||
padding: 56px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 64px;
|
||||
color: #94a3b8;
|
||||
padding: 56px 24px;
|
||||
color: $muted;
|
||||
|
||||
fa-icon {
|
||||
color: #cbd5e1;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 12px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: $slate;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 4px;
|
||||
border-radius: 8px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,133 +7,137 @@
|
||||
-->
|
||||
|
||||
<div class="cfcfrms-dashboard">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.menus.CFCFRMS Dashboard' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Cyber Fraud Complaint Management Overview' | translate }}</p>
|
||||
<!-- KPI strip — gradient icon block + value/label -->
|
||||
<div class="kpi-strip">
|
||||
<div class="kpi-card kpi-card--blue">
|
||||
<div class="kpi-card__ico">
|
||||
<fa-icon icon="file-alt"></fa-icon>
|
||||
</div>
|
||||
<div class="kpi-card__body">
|
||||
<div class="kpi-card__value">{{ stats?.totalComplaints || 0 }}</div>
|
||||
<div class="kpi-card__label">{{ 'labels.text.Total Complaints' | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kpi-card kpi-card--amber">
|
||||
<div class="kpi-card__ico">
|
||||
<fa-icon icon="clock"></fa-icon>
|
||||
</div>
|
||||
<div class="kpi-card__body">
|
||||
<div class="kpi-card__value">{{ stats?.pendingReview || 0 }}</div>
|
||||
<div class="kpi-card__label">{{ 'labels.text.Pending Review' | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kpi-card kpi-card--purple">
|
||||
<div class="kpi-card__ico">
|
||||
<fa-icon icon="lock"></fa-icon>
|
||||
</div>
|
||||
<div class="kpi-card__body">
|
||||
<div class="kpi-card__value">{{ stats?.lienMarked || 0 }}</div>
|
||||
<div class="kpi-card__label">{{ 'labels.text.Lien Marked' | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kpi-card kpi-card--green">
|
||||
<div class="kpi-card__ico">
|
||||
<fa-icon icon="check-circle"></fa-icon>
|
||||
</div>
|
||||
<div class="kpi-card__body">
|
||||
<div class="kpi-card__value">{{ formatCurrency(stats?.fundsRecovered || 0) }}</div>
|
||||
<div class="kpi-card__label">{{ 'labels.text.Funds Recovered' | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stat Cards -->
|
||||
<div class="stat-cards">
|
||||
<mat-card class="stat-card stat-total">
|
||||
<mat-card-content>
|
||||
<div class="stat-icon"><fa-icon icon="file-alt" size="2x"></fa-icon></div>
|
||||
<div class="stat-info">
|
||||
<span class="stat-value">{{ stats?.totalComplaints || 0 }}</span>
|
||||
<span class="stat-label">{{ 'labels.text.Total Complaints' | translate }}</span>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="stat-card stat-pending">
|
||||
<mat-card-content>
|
||||
<div class="stat-icon"><fa-icon icon="clock" size="2x"></fa-icon></div>
|
||||
<div class="stat-info">
|
||||
<span class="stat-value">{{ stats?.pendingReview || 0 }}</span>
|
||||
<span class="stat-label">{{ 'labels.text.Pending Review' | translate }}</span>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="stat-card stat-lien">
|
||||
<mat-card-content>
|
||||
<div class="stat-icon"><fa-icon icon="lock" size="2x"></fa-icon></div>
|
||||
<div class="stat-info">
|
||||
<span class="stat-value">{{ stats?.lienMarked || 0 }}</span>
|
||||
<span class="stat-label">{{ 'labels.text.Lien Marked' | translate }}</span>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="stat-card stat-recovered">
|
||||
<mat-card-content>
|
||||
<div class="stat-icon"><fa-icon icon="check-circle" size="2x"></fa-icon></div>
|
||||
<div class="stat-info">
|
||||
<span class="stat-value">{{ formatCurrency(stats?.fundsRecovered || 0) }}</span>
|
||||
<span class="stat-label">{{ 'labels.text.Funds Recovered' | translate }}</span>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<!-- Charts Row -->
|
||||
<!-- Charts row — two side-by-side analytics cards -->
|
||||
<div class="charts-row">
|
||||
<mat-card class="chart-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'labels.text.Status Distribution' | translate }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<section class="nx-card">
|
||||
<header class="nx-card__head">
|
||||
<fa-icon icon="chart-pie" class="nx-card__ico"></fa-icon>
|
||||
<h3 class="nx-card__title">{{ 'labels.text.Status Distribution' | translate }}</h3>
|
||||
</header>
|
||||
<div class="nx-card__body">
|
||||
<div class="chart-container">
|
||||
<canvas #donutCanvas></canvas>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="chart-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'labels.text.Fraud Amount by Status' | translate }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
</div>
|
||||
</section>
|
||||
<section class="nx-card">
|
||||
<header class="nx-card__head">
|
||||
<fa-icon icon="chart-bar" class="nx-card__ico"></fa-icon>
|
||||
<h3 class="nx-card__title">{{ 'labels.text.Fraud Amount by Status' | translate }}</h3>
|
||||
</header>
|
||||
<div class="nx-card__body">
|
||||
<div class="chart-container">
|
||||
<canvas #barCanvas></canvas>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Recent Complaints Table -->
|
||||
<mat-card class="recent-complaints-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'labels.text.Recent Complaints' | translate }}</mat-card-title>
|
||||
<span class="spacer"></span>
|
||||
<a mat-stroked-button color="primary" routerLink="/cfcfrms/complaints">{{
|
||||
'labels.text.View All' | translate
|
||||
}}</a>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<!-- Recent complaints -->
|
||||
<section class="nx-card">
|
||||
<header class="nx-card__head">
|
||||
<fa-icon icon="inbox" class="nx-card__ico"></fa-icon>
|
||||
<h3 class="nx-card__title">{{ 'labels.text.Recent Complaints' | translate }}</h3>
|
||||
<span class="nx-card__spacer"></span>
|
||||
<a mat-stroked-button color="primary" routerLink="/cfcfrms/complaints" class="nx-card__action">
|
||||
{{ 'labels.text.View All' | translate }}
|
||||
<fa-icon icon="arrow-right" class="ml-04"></fa-icon>
|
||||
</a>
|
||||
</header>
|
||||
<div class="nx-card__body nx-card__body--flush">
|
||||
@if (isLoading) {
|
||||
<div class="loading-container">
|
||||
<div class="nx-state">
|
||||
<mat-spinner diameter="40"></mat-spinner>
|
||||
</div>
|
||||
} @else if (recentComplaints.length === 0) {
|
||||
<div class="empty-state">
|
||||
<fa-icon icon="inbox" size="3x"></fa-icon>
|
||||
<p>{{ 'labels.text.No complaints found' | translate }}</p>
|
||||
<div class="nx-state nx-state--empty">
|
||||
<fa-icon icon="inbox" class="nx-state__ico"></fa-icon>
|
||||
<div class="nx-state__title">{{ 'labels.text.No complaints found' | translate }}</div>
|
||||
<div class="nx-state__sub">Recent activity will appear here.</div>
|
||||
</div>
|
||||
} @else {
|
||||
<table mat-table [dataSource]="recentComplaints" class="full-width">
|
||||
<ng-container matColumnDef="ticketId">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Ticket ID' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<a [routerLink]="['/cfcfrms/complaints', row.ticketId]" class="ticket-link">{{ row.ticketId }}</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="complainantName">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Complainant' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">{{ row.complainantName }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="fraudAmount">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Fraud Amount' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">{{ formatCurrency(row.fraudAmount) }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Status' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mifosx-cfcfrms-status-badge [status]="row.status"></mifosx-cfcfrms-status-badge>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="createdAt">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Created' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">{{ formatDate(row.createdAt) }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Actions' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<a mat-icon-button color="primary" [routerLink]="['/cfcfrms/complaints', row.ticketId]">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
<div class="nx-table-wrap">
|
||||
<table mat-table [dataSource]="recentComplaints" class="nx-table">
|
||||
<ng-container matColumnDef="ticketId">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Ticket ID' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<a [routerLink]="['/cfcfrms/complaints', row.ticketId]" class="ticket-link">{{ row.ticketId }}</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="complainantName">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Complainant' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">{{ row.complainantName }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="fraudAmount">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Fraud Amount' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row" class="amount-cell">{{ formatCurrency(row.fraudAmount) }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Status' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mifosx-cfcfrms-status-badge [status]="row.status"></mifosx-cfcfrms-status-badge>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="createdAt">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.text.Created' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let row">{{ formatDate(row.createdAt) }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="text-right">
|
||||
{{ 'labels.text.Actions' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let row" class="text-right">
|
||||
<a mat-icon-button color="primary" [routerLink]="['/cfcfrms/complaints', row.ticketId]">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -6,147 +6,193 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
$navy: #0d1b2a;
|
||||
$slate: #475569;
|
||||
$muted: #64748b;
|
||||
$border: #e2e8f0;
|
||||
$soft: #f8fafc;
|
||||
|
||||
.cfcfrms-dashboard {
|
||||
padding: 24px;
|
||||
/* Wrapper hero handles outer padding/centering. */
|
||||
padding: 0;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #0d1b2a;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-cards {
|
||||
/* ─── KPI strip ─────────────────────────────────────────────────────── */
|
||||
.kpi-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 24px;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@media (width <= 1280px) {
|
||||
@media (width <= 1100px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
border-left: 4px solid;
|
||||
border-radius: 8px !important;
|
||||
|
||||
mat-card-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 20px !important;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
&.stat-total {
|
||||
border-color: #1e88e5;
|
||||
|
||||
.stat-icon {
|
||||
background: #1e88e5;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
color: #1e88e5;
|
||||
}
|
||||
}
|
||||
|
||||
&.stat-pending {
|
||||
border-color: #f59e0b;
|
||||
|
||||
.stat-icon {
|
||||
background: #f59e0b;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
color: #f59e0b;
|
||||
}
|
||||
}
|
||||
|
||||
&.stat-lien {
|
||||
border-color: #eab308;
|
||||
|
||||
.stat-icon {
|
||||
background: #eab308;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
color: #92400e;
|
||||
}
|
||||
}
|
||||
|
||||
&.stat-recovered {
|
||||
border-color: #10b981;
|
||||
|
||||
.stat-icon {
|
||||
background: #10b981;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
color: #10b981;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.charts-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
@media (width <= 1280px) {
|
||||
@media (width <= 640px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
border-radius: 8px !important;
|
||||
.kpi-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
background: #fff;
|
||||
border: 1px solid $border;
|
||||
border-radius: 14px;
|
||||
padding: 16px 18px;
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
|
||||
transition:
|
||||
transform 0.15s ease,
|
||||
box-shadow 0.15s ease,
|
||||
border-color 0.15s ease;
|
||||
|
||||
mat-card-header {
|
||||
padding: 16px 16px 0;
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px -6px rgb(15 23 42 / 12%);
|
||||
}
|
||||
|
||||
mat-card-content {
|
||||
padding: 16px !important;
|
||||
&__ico {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-size: 17px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__value {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: $navy;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
&__label {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: $muted;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Variant tint — left accent stripe + gradient icon. */
|
||||
&--blue {
|
||||
border-left: 3px solid #1e88e5;
|
||||
|
||||
.kpi-card__ico {
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
|
||||
box-shadow: 0 4px 10px -4px rgb(30 64 175 / 50%);
|
||||
}
|
||||
}
|
||||
|
||||
&--amber {
|
||||
border-left: 3px solid #f59e0b;
|
||||
|
||||
.kpi-card__ico {
|
||||
background: linear-gradient(135deg, #fbbf24 0%, #d97706 100%);
|
||||
box-shadow: 0 4px 10px -4px rgb(217 119 6 / 50%);
|
||||
}
|
||||
}
|
||||
|
||||
&--purple {
|
||||
border-left: 3px solid #8b5cf6;
|
||||
|
||||
.kpi-card__ico {
|
||||
background: linear-gradient(135deg, #a78bfa 0%, #6d28d9 100%);
|
||||
box-shadow: 0 4px 10px -4px rgb(109 40 217 / 50%);
|
||||
}
|
||||
}
|
||||
|
||||
&--green {
|
||||
border-left: 3px solid #10b981;
|
||||
|
||||
.kpi-card__ico {
|
||||
background: linear-gradient(135deg, #34d399 0%, #047857 100%);
|
||||
box-shadow: 0 4px 10px -4px rgb(4 120 87 / 50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Charts row ────────────────────────────────────────────────────── */
|
||||
.charts-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@media (width <= 1100px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Generic Nexora card ───────────────────────────────────────────── */
|
||||
.nx-card {
|
||||
background: #fff;
|
||||
border: 1px solid $border;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
|
||||
overflow: hidden;
|
||||
|
||||
&__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 14px 18px;
|
||||
border-bottom: 1px solid $border;
|
||||
background: $soft;
|
||||
}
|
||||
|
||||
&__ico {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: $navy;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
&__spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__action {
|
||||
height: 32px !important;
|
||||
border-radius: 8px !important;
|
||||
font-size: 12.5px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 18px;
|
||||
|
||||
&--flush {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,53 +201,87 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.recent-complaints-card {
|
||||
border-radius: 8px !important;
|
||||
|
||||
mat-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
mat-card-content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
/* ─── Table ─────────────────────────────────────────────────────────── */
|
||||
.nx-table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
.nx-table {
|
||||
width: 100%;
|
||||
|
||||
::ng-deep .mat-mdc-header-cell {
|
||||
background: $soft;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: $slate;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-cell {
|
||||
font-size: 13.5px;
|
||||
color: $navy;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-row:hover {
|
||||
background: #f1f5f9;
|
||||
}
|
||||
}
|
||||
|
||||
.ticket-link {
|
||||
color: #1e88e5;
|
||||
color: #1e40af;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 40px;
|
||||
.amount-cell {
|
||||
font-weight: 700;
|
||||
color: $navy;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ml-04 {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/* ─── States (loading / empty) ──────────────────────────────────────── */
|
||||
.nx-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 48px;
|
||||
color: #94a3b8;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 56px 24px;
|
||||
color: $muted;
|
||||
|
||||
p {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
&--empty {
|
||||
.nx-state__ico {
|
||||
font-size: 38px;
|
||||
color: #cbd5e1;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.nx-state__title {
|
||||
font-size: 14.5px;
|
||||
font-weight: 700;
|
||||
color: $slate;
|
||||
}
|
||||
|
||||
.nx-state__sub {
|
||||
font-size: 12.5px;
|
||||
color: $muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,15 @@
|
||||
import { Component, OnInit, inject, ViewChild, ElementRef } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { Chart, registerables } from 'chart.js';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CfcfrmsService } from '../cfcfrms.service';
|
||||
import { StatusBadgeComponent } from '../components/status-badge/status-badge.component';
|
||||
import { Complaint, DashboardStats, ComplaintStatus } from '../models/cfcfrms.models';
|
||||
import { Complaint, DashboardStats } from '../models/cfcfrms.models';
|
||||
|
||||
Chart.register(...registerables);
|
||||
|
||||
@@ -29,11 +27,9 @@ Chart.register(...registerables);
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
MatCardModule,
|
||||
MatTableModule,
|
||||
MatButtonModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatIconModule,
|
||||
FaIconComponent,
|
||||
TranslateModule,
|
||||
StatusBadgeComponent
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
-->
|
||||
|
||||
<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">
|
||||
|
||||
@@ -6,206 +6,138 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
@use '../cfc-form' as *;
|
||||
|
||||
.escalate-page {
|
||||
padding: 24px;
|
||||
/* Wrapper hero already handles outer padding. */
|
||||
padding: 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #0d1b2a;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.escalate-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 360px;
|
||||
gap: 24px;
|
||||
grid-template-columns: minmax(0, 1fr) 360px;
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
|
||||
@media (width <= 1280px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.escalate-card,
|
||||
.instructions-card {
|
||||
border-radius: 8px !important;
|
||||
|
||||
mat-card-header {
|
||||
padding: 16px 20px 0;
|
||||
}
|
||||
|
||||
mat-card-content {
|
||||
padding: 16px 20px 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ticket-lookup-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
|
||||
.ticket-field {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.lookup-btn {
|
||||
margin-top: 4px;
|
||||
height: 56px;
|
||||
@media (width <= 1100px) {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.lookup-result {
|
||||
background: #f0f9ff;
|
||||
border: 1px solid #bae6fd;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
background: #eff6ff;
|
||||
border: 1px solid #bfdbfe;
|
||||
border-radius: 12px;
|
||||
padding: 14px 16px;
|
||||
margin-bottom: 18px;
|
||||
|
||||
.lookup-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
gap: 10px;
|
||||
padding: 5px 0;
|
||||
font-size: 13px;
|
||||
|
||||
span {
|
||||
color: #64748b;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: #0d1b2a;
|
||||
font-weight: 700;
|
||||
|
||||
&.mono {
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
color: #1e40af;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 8px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.inline-spinner {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mr-05 {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.mt-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
// Success result
|
||||
.success-result {
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
|
||||
.success-icon {
|
||||
color: #10b981;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 20px;
|
||||
color: #065f46;
|
||||
font-size: 20px;
|
||||
/* ─── Instructions side panel ───────────────────────────────────────── */
|
||||
.instructions-card {
|
||||
::ng-deep .mat-mdc-card-content {
|
||||
padding: 18px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.result-details {
|
||||
text-align: left;
|
||||
background: #f0fdf4;
|
||||
border: 1px solid #bbf7d0;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 6px 0;
|
||||
font-size: 14px;
|
||||
|
||||
.result-label {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instructions card
|
||||
.guidelines {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.guideline-item {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
padding: 8px 0;
|
||||
padding: 7px 0;
|
||||
|
||||
.guideline-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
background: #ecfdf5;
|
||||
color: #10b981;
|
||||
margin-top: 2px;
|
||||
font-size: 11px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 1px;
|
||||
|
||||
&.warn {
|
||||
color: #f59e0b;
|
||||
background: #fffbeb;
|
||||
color: #d97706;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
font-size: 12.5px;
|
||||
color: #334155;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.bank-info {
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid #e2e8f0;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 10px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 800;
|
||||
color: #0d1b2a;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.bank-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
align-items: center;
|
||||
padding: 5px 0;
|
||||
font-size: 13px;
|
||||
|
||||
span {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: #0d1b2a;
|
||||
font-weight: 700;
|
||||
|
||||
&.mono {
|
||||
font-family: 'JetBrains Mono', 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
color: #1e40af;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include cfc-form-skin('blue');
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
-->
|
||||
|
||||
<div class="report-page">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.text.FMR Submission' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Submit Fraud Monitoring Return to RBI FUA System' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="report-layout">
|
||||
<mat-card class="report-card wide-card">
|
||||
<mat-card-header>
|
||||
|
||||
@@ -7,27 +7,12 @@
|
||||
*/
|
||||
|
||||
.report-page {
|
||||
padding: 24px;
|
||||
/* Wrapper hero already handles outer padding. */
|
||||
padding: 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.report-layout {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
-->
|
||||
|
||||
<div class="report-page">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.text.Report Fraud Transaction' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Report a detected fraud transaction to I4C' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="report-layout">
|
||||
<mat-card class="report-card">
|
||||
<mat-card-header>
|
||||
|
||||
@@ -6,114 +6,23 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
@use '../cfc-form' as *;
|
||||
|
||||
.report-page {
|
||||
padding: 24px;
|
||||
/* Wrapper hero already handles outer padding. */
|
||||
padding: 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.report-layout {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.report-card {
|
||||
flex: 1;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mr-05 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 8px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.inline-spinner {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.success-result {
|
||||
text-align: center;
|
||||
padding: 32px 16px;
|
||||
|
||||
.success-icon {
|
||||
color: #10b981;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #10b981;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.result-details {
|
||||
text-align: left;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.result-label {
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.half-width {
|
||||
flex: 1;
|
||||
}
|
||||
/* Layered Nexora skin: red-accented for the high-impact fraud report. */
|
||||
@include cfc-form-skin('red');
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
-->
|
||||
|
||||
<div class="report-page">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.text.Report Mule Account' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Flag a mule account proactively to I4C/CFCFRMS' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="report-layout">
|
||||
<mat-card class="report-card">
|
||||
<mat-card-header>
|
||||
|
||||
@@ -6,110 +6,21 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
@use '../cfc-form' as *;
|
||||
|
||||
.report-page {
|
||||
padding: 24px;
|
||||
padding: 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.report-layout {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.report-card {
|
||||
flex: 1;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mr-05 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 8px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.inline-spinner {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.success-result {
|
||||
text-align: center;
|
||||
padding: 32px 16px;
|
||||
|
||||
.success-icon {
|
||||
color: #10b981;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #10b981;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.result-details {
|
||||
text-align: left;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.result-label {
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
}
|
||||
|
||||
.status-flagged {
|
||||
color: #ef4444;
|
||||
font-weight: 700;
|
||||
}
|
||||
@include cfc-form-skin('red');
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
-->
|
||||
|
||||
<div class="report-page">
|
||||
<div class="page-header">
|
||||
<h2>{{ 'labels.text.Report Suspect Account' | translate }}</h2>
|
||||
<p class="subtitle">{{ 'labels.text.Report internally detected suspect account to I4C' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div class="report-layout">
|
||||
<mat-card class="report-card">
|
||||
<mat-card-header>
|
||||
|
||||
@@ -6,105 +6,21 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
@use '../cfc-form' as *;
|
||||
|
||||
.report-page {
|
||||
padding: 24px;
|
||||
padding: 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 4px 0 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.report-layout {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.report-card {
|
||||
flex: 1;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mr-05 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 8px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.inline-spinner {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.success-result {
|
||||
text-align: center;
|
||||
padding: 32px 16px;
|
||||
|
||||
.success-icon {
|
||||
color: #10b981;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #10b981;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.result-details {
|
||||
text-align: left;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.result-label {
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
}
|
||||
@include cfc-form-skin('red');
|
||||
|
||||
Reference in New Issue
Block a user