feat: Nexora UI upgrade for Current Account, FD, and RD account views

- Current Account: hero header with navy gradient, pill tabs, Nexora card layout for general tab, txn-tab/chg-tab table styles, bank statement passbook
- Fixed Deposits: fd-* prefixed hero header, KPI tiles, pill tab nav, nx-card general tab layout, txn-tab transactions, chg-tab charges
- Recurring Deposits: rd-* prefixed hero header with three KPI tiles, pill tab nav, nx-card general tab layout, txn-tab transactions, chg-tab charges
- Fix: removed broken FA4-format icon references from action menu buttons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-05-25 11:02:15 +05:30
co-authored by Claude Sonnet 4.6
parent ad6f629c3f
commit b7d009b22a
30 changed files with 4149 additions and 2090 deletions
@@ -6,25 +6,22 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="tab-container mat-typography"> <div class="chg-tab">
<div class="layout-row align-start"> <div class="chg-tab__card">
<div class="m-b-10"> <div class="chg-tab__toolbar">
<h3>{{ 'labels.inputs.Charges' | translate }}</h3> <h3 class="chg-tab__title">{{ 'labels.inputs.Charges' | translate }}</h3>
</div> <span class="chg-tab__spacer"></span>
@if (this.chargesData) { @if (this.chargesData) {
<div class="action-button m-b-20"> <button mat-flat-button class="chg-tab__toggle" (click)="toggleCharges()">
<button mat-raised-button color="primary" (click)="toggleCharges()">
{{ {{
showInactiveCharges showInactiveCharges
? viewAllChargeButtons('View Active Charges') ? viewAllChargeButtons('View Active Charges')
: viewAllChargeButtons('View Inactive Charges') : viewAllChargeButtons('View Inactive Charges')
}} }}
</button> </button>
</div> }
} </div>
</div>
<div class="mat-elevation-z1 m-b-25">
<table mat-table #chargesTable [dataSource]="dataSource"> <table mat-table #chargesTable [dataSource]="dataSource">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th> <th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th>
@@ -6,30 +6,107 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
.tab-container { $navy: #0d1b2a;
padding: 1%; $slate: #475569;
margin: 1%; $muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
$blue: #1e40af;
h3 { .chg-tab {
margin: 1% auto; width: 100%;
}
.chg-tab__card {
background: #fff;
border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
overflow: hidden;
}
.chg-tab__toolbar {
display: flex;
align-items: center;
gap: 14px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
}
.chg-tab__title {
margin: 0;
font-size: 14px;
font-weight: 700;
color: $navy;
letter-spacing: 0.01em;
}
.chg-tab__spacer {
flex: 1;
}
.chg-tab__toggle {
height: 34px !important;
border-radius: 8px !important;
font-weight: 600 !important;
font-size: 13px !important;
padding: 0 14px !important;
background: linear-gradient(135deg, #1e88e5 0%, $blue 100%) !important;
color: #fff !important;
}
table {
width: 100%;
}
::ng-deep .chg-tab__card {
.mat-mdc-header-row {
background: $soft;
} }
.action-button { .mat-mdc-header-cell {
margin-left: auto; font-size: 11.5px;
font-weight: 800;
color: $slate;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 14px;
border-bottom: 1px solid $border;
} }
table { .mat-mdc-cell {
width: 100%; font-size: 13px;
color: $navy;
padding: 11px 14px;
border-bottom: 1px solid #f1f5f9;
}
.mat-mdc-row:hover {
background: #f8fafc;
cursor: pointer;
}
/* Right-align monetary columns. */
.mat-column-due,
.mat-column-paid,
.mat-column-waived,
.mat-column-outstanding {
text-align: right;
font-variant-numeric: tabular-nums;
}
.mat-column-actions {
text-align: center;
width: 140px;
.account-action-button { .account-action-button {
min-width: 26px; min-width: 30px !important;
padding: 0 6px; padding: 0 8px !important;
margin: 4px; margin: 0 3px !important;
line-height: 25px; height: 30px !important;
} line-height: 30px !important;
border-radius: 7px !important;
.select-row:hover {
cursor: pointer;
} }
} }
} }
@@ -6,239 +6,232 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<mat-card class="account-card"> <div class="cur-view">
<mat-card-header class="header layout-column"> <!-- ─── Gradient hero header ─────────────────────────────────────── -->
<mat-card-title-group class="header-title-group"> <header class="cur-hero">
<div class="profile-image-container"> <div class="cur-hero__left">
<div> <div class="cur-hero__avatar">
<img <fa-icon icon="university"></fa-icon>
mat-card-md-image
class="profile-image"
matTooltip="{{ 'tooltips.Current Account' | translate }}"
[src]="'assets/images/current_account_placeholder.png'"
/>
</div>
</div> </div>
<div class="mat-typography account-card-title"> <div class="cur-hero__info">
<mat-card-title class="layout-row layout-lt-md-column"> <!-- Status pill -->
<div class="flex-60"> <div class="cur-hero__status-row">
<h3> @if (!currentAccountData.subStatus.block) {
@if (!currentAccountData.subStatus.block) { <span
<i class="cur-status-pill"
class="fa fa-stop" [ngClass]="currentAccountData.status.code | statusLookup"
[ngClass]="currentAccountData.status.code | statusLookup" [matTooltip]="currentAccountData.status.value"
[matTooltip]="currentAccountData.status.value" >
></i> <span class="cur-status-pill__dot"></span>
} {{ currentAccountData.status.value }}
@if (currentAccountData.subStatus.block) {
<i
class="fa fa-stop"
[ngClass]="currentAccountData.subStatus.value | statusLookup"
[matTooltip]="currentAccountData.subStatus.value"
></i>
}
</h3>
<!-- Product Name Row -->
<span class="product-row">
<span class="m-r-5">{{ 'labels.inputs.Current Account Product' | translate }} :</span>
<span class="m-r-5">
<mifosx-long-text textValue="{{ currentAccountData.currentAccountProductName }}"></mifosx-long-text>
</span>
</span> </span>
<!-- Account Number Row --> } @else {
<span class="account-number-row"> <span
<span class="m-r-5">{{ 'labels.inputs.Account Number' | translate }} :</span> class="cur-status-pill cur-status-pill--warn"
<span class="m-r-5"> [ngClass]="currentAccountData.subStatus.value | statusLookup"
<mifosx-account-number [matTooltip]="currentAccountData.subStatus.value"
accountNo="{{ currentAccountData.accountNo }}" >
display="left" <span class="cur-status-pill__dot"></span>
></mifosx-account-number> {{ currentAccountData.subStatus.value }}
</span>
</span> </span>
<!-- External ID Row --> }
@if (currentAccountData.externalId) { </div>
<span class="external-id-row">
<span class="m-r-5">{{ 'labels.inputs.External Id' | translate }} :</span> <h2 class="cur-hero__title">
<span>{{ currentAccountData.externalId }}</span> <mifosx-long-text textValue="{{ currentAccountData.currentAccountProductName }}"></mifosx-long-text>
</span> </h2>
}
<span class="account-overview"> <div class="cur-hero__meta">
{{ 'labels.text.' + entityType | translate }} {{ 'labels.inputs.name' | translate }}: <span class="cur-hero__meta-item">
<span class="cur-hero__meta-label">{{ 'labels.inputs.Account Number' | translate }}</span>
<mifosx-account-number
accountNo="{{ currentAccountData.accountNo }}"
display="left"
></mifosx-account-number>
</span>
<span class="cur-hero__meta-item">
<span class="cur-hero__meta-label">
{{ 'labels.text.' + entityType | translate }} {{ 'labels.inputs.name' | translate }}
</span>
<span class="cur-hero__meta-value">
{{ currentAccountData.clientName || currentAccountData.groupName }} {{ currentAccountData.clientName || currentAccountData.groupName }}
@if (currentAccountData.clientAccountNo) { @if (currentAccountData.clientAccountNo) {
<span class="m-l-10"> <mifosx-account-number accountNo="{{ currentAccountData.clientAccountNo }}"></mifosx-account-number>
<mifosx-account-number accountNo="{{ currentAccountData.clientAccountNo }}"></mifosx-account-number>
</span>
} }
</span> </span>
</div> </span>
</div>
@if (!currentAccountData.status.rejected && !currentAccountData.status.submittedAndPendingApproval) {
<div class="flex-30">
<h3>{{ 'labels.heading.Account Overview' | translate }}</h3>
<table class="account-overview">
<tbody>
<tr>
<td>{{ 'labels.inputs.Current Balance' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.accountBalance | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Available Balance' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.availableBalance
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
</tbody>
</table>
</div>
}
<div class="flex-5">
<button
mat-icon-button
[matMenuTriggerFor]="accountMenu"
aria-label="Loan account actions"
yPosition="below"
>
<mat-icon matListIcon class="actions-menu">
<fa-icon icon="bars" size="sm"></fa-icon>
</mat-icon>
</button>
</div>
</mat-card-title>
</div> </div>
</div>
<mat-menu #accountMenu="matMenu"> <!-- Balance KPI strip -->
@for (item of buttonConfig.singleButtons; track item) { @if (!currentAccountData.status.rejected && !currentAccountData.status.submittedAndPendingApproval) {
<button mat-menu-item *mifosxHasPermission="item.taskPermissionName" (click)="doAction(item.name)"> <div class="cur-hero__kpis">
<mat-icon matListIcon> <div class="cur-kpi">
<fa-icon icon="{{ item.icon }}" size="sm"></fa-icon> <span class="cur-kpi__label">{{ 'labels.inputs.Current Balance' | translate }}</span>
</mat-icon> <span class="cur-kpi__value">
<span> {{ 'labels.menus.' + item.name | translate }} </span> {{ currentAccountData.summary.accountBalance | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</button> </span>
} </div>
<div class="cur-kpi cur-kpi--available">
@if (buttonConfig.options && !currentAccountData.subStatus.block) { <span class="cur-kpi__label">{{ 'labels.inputs.Available Balance' | translate }}</span>
<button mat-menu-item [matMenuTriggerFor]="More">{{ 'labels.menus.More' | translate }}</button> <span class="cur-kpi__value">
<mat-menu #More="matMenu"> {{ currentAccountData.summary.availableBalance | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
@for (option of buttonConfig.options; track option) { </span>
<span> </div>
<button mat-menu-item *mifosxHasPermission="option.taskPermissionName" (click)="doAction(option.name)"> </div>
{{ 'labels.menus.' + option.name | translate }}
</button>
</span>
}
</mat-menu>
}
</mat-menu>
</mat-card-title-group>
</mat-card-header>
<mat-card-content class="content">
@if (isActive) {
<nav mat-tab-nav-bar class="navigation-tabs" [tabPanel]="tabPanel">
<a
mat-tab-link
[routerLink]="['./general']"
routerLinkActive
#general="routerLinkActive"
[active]="general.isActive"
>
{{ 'labels.inputs.General' | translate }}
</a>
<a
mat-tab-link
[routerLink]="['./transactions']"
routerLinkActive
#transactions="routerLinkActive"
[active]="transactions.isActive"
>
{{ 'labels.inputs.Transactions' | translate }}
</a>
<a
mat-tab-link
[routerLink]="['./passbook']"
routerLinkActive
#passbook="routerLinkActive"
[active]="passbook.isActive"
>
{{ 'labels.inputs.Passbook' | translate }}
</a>
<a
mat-tab-link
[routerLink]="['./charges']"
routerLinkActive
#charges="routerLinkActive"
[active]="charges.isActive"
>
{{ 'labels.inputs.Charges' | translate }}
</a>
<a
mat-tab-link
[routerLink]="['./documents']"
routerLinkActive
#currentAccountDocuments="routerLinkActive"
[active]="currentAccountDocuments.isActive"
>
{{ 'labels.inputs.Documents' | translate }}
</a>
<a
mat-tab-link
*mifosxHasPermission="'READ_CURRENTACCOUNTNOTE'"
[routerLink]="['./notes']"
routerLinkActive
#notes="routerLinkActive"
[active]="notes.isActive"
>
{{ 'labels.inputs.Notes' | translate }}
</a>
<ng-container *mifosxHasPermission="'READ_CURRENTACCOUNTCHARGE'">
@if (currentAccountData.clientId) {
<a
mat-tab-link
[routerLink]="['./standing-instructions']"
routerLinkActive
#standingInstructions="routerLinkActive"
[active]="standingInstructions.isActive"
>
{{ 'labels.inputs.Standing Instructions' | translate }}
</a>
}
</ng-container>
<a
mat-tab-link
[routerLink]="['./nominees']"
routerLinkActive
#nominees="routerLinkActive"
[active]="nominees.isActive"
>
Nominees
</a>
@for (currentAccountDatatable of currentAccountDatatables; track currentAccountDatatable) {
<a
mat-tab-link
*mifosxHasPermission="'READ_' + currentAccountDatatable.registeredTableName"
[routerLink]="['./datatables', currentAccountDatatable.registeredTableName]"
routerLinkActive
#datatable="routerLinkActive"
[active]="datatable.isActive"
>
{{ currentAccountDatatable.registeredTableName }}
</a>
}
</nav>
} }
<mat-tab-nav-panel #tabPanel> <!-- Action menu (kebab) -->
<div class="cur-hero__actions">
<button mat-icon-button [matMenuTriggerFor]="accountMenu" aria-label="Account actions" yPosition="below">
<fa-icon icon="ellipsis-v"></fa-icon>
</button>
</div>
<mat-menu #accountMenu="matMenu">
@for (item of buttonConfig.singleButtons; track item) {
<button mat-menu-item *mifosxHasPermission="item.taskPermissionName" (click)="doAction(item.name)">
<mat-icon matListIcon>
<fa-icon icon="{{ item.icon }}" size="sm"></fa-icon>
</mat-icon>
<span> {{ 'labels.menus.' + item.name | translate }} </span>
</button>
}
@if (buttonConfig.options && !currentAccountData.subStatus.block) {
<button mat-menu-item [matMenuTriggerFor]="More">{{ 'labels.menus.More' | translate }}</button>
<mat-menu #More="matMenu">
@for (option of buttonConfig.options; track option) {
<span>
<button mat-menu-item *mifosxHasPermission="option.taskPermissionName" (click)="doAction(option.name)">
{{ 'labels.menus.' + option.name | translate }}
</button>
</span>
}
</mat-menu>
}
</mat-menu>
</header>
<!-- ─── Pill-style tab navigation ─────────────────────────────────── -->
@if (isActive) {
<nav mat-tab-nav-bar class="cur-tabs" [tabPanel]="tabPanel">
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./general']"
routerLinkActive
#general="routerLinkActive"
[active]="general.isActive"
>
<fa-icon icon="info-circle" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.General' | translate }}</span>
</a>
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./transactions']"
routerLinkActive
#transactions="routerLinkActive"
[active]="transactions.isActive"
>
<fa-icon icon="exchange-alt" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Transactions' | translate }}</span>
</a>
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./passbook']"
routerLinkActive
#passbook="routerLinkActive"
[active]="passbook.isActive"
>
<fa-icon icon="book" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Passbook' | translate }}</span>
</a>
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./charges']"
routerLinkActive
#charges="routerLinkActive"
[active]="charges.isActive"
>
<fa-icon icon="receipt" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Charges' | translate }}</span>
</a>
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./documents']"
routerLinkActive
#currentAccountDocuments="routerLinkActive"
[active]="currentAccountDocuments.isActive"
>
<fa-icon icon="folder-open" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Documents' | translate }}</span>
</a>
<a
mat-tab-link
class="cur-tab"
*mifosxHasPermission="'READ_CURRENTACCOUNTNOTE'"
[routerLink]="['./notes']"
routerLinkActive
#notes="routerLinkActive"
[active]="notes.isActive"
>
<fa-icon icon="sticky-note" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Notes' | translate }}</span>
</a>
<ng-container *mifosxHasPermission="'READ_CURRENTACCOUNTCHARGE'">
@if (currentAccountData.clientId) {
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./standing-instructions']"
routerLinkActive
#standingInstructions="routerLinkActive"
[active]="standingInstructions.isActive"
>
<fa-icon icon="calendar-check" class="cur-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Standing Instructions' | translate }}</span>
</a>
}
</ng-container>
<a
mat-tab-link
class="cur-tab"
[routerLink]="['./nominees']"
routerLinkActive
#nominees="routerLinkActive"
[active]="nominees.isActive"
>
<fa-icon icon="user-shield" class="cur-tab__ic"></fa-icon>
<span>Nominees</span>
</a>
@for (currentAccountDatatable of currentAccountDatatables; track currentAccountDatatable) {
<a
mat-tab-link
class="cur-tab"
*mifosxHasPermission="'READ_' + currentAccountDatatable.registeredTableName"
[routerLink]="['./datatables', currentAccountDatatable.registeredTableName]"
routerLinkActive
#datatable="routerLinkActive"
[active]="datatable.isActive"
>
<fa-icon icon="table" class="cur-tab__ic"></fa-icon>
<span>{{ currentAccountDatatable.registeredTableName }}</span>
</a>
}
</nav>
}
<mat-tab-nav-panel #tabPanel>
<div class="cur-body">
<router-outlet></router-outlet> <router-outlet></router-outlet>
</mat-tab-nav-panel> </div>
</mat-card-content> </mat-tab-nav-panel>
</mat-card> </div>
@@ -6,12 +6,390 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
mat-card-title { $navy: #0d1b2a;
display: flex; $blue: #1e88e5;
$blue-d: #1e40af;
$border: #e2e8f0;
.cur-view {
max-width: 1440px;
margin: 0 auto;
padding: 12px 20px 22px;
} }
.product-row, /* ─── Gradient hero header ──────────────────────────────────────────── */
.account-number-row, .cur-hero {
.external-id-row { position: relative;
display: block; display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
align-items: stretch;
gap: 14px;
padding: 12px 18px;
border-radius: 12px;
color: #fff;
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 45%, #4338ca 100%);
box-shadow: 0 6px 18px -10px rgb(15 23 42 / 35%);
overflow: hidden;
&::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at top right, rgb(255 255 255 / 12%) 0%, transparent 55%);
pointer-events: none;
}
&__left {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
position: relative;
z-index: 1;
}
&__avatar {
width: 40px;
height: 40px;
border-radius: 10px;
background: linear-gradient(135deg, rgb(255 255 255 / 22%) 0%, rgb(255 255 255 / 10%) 100%);
border: 1px solid rgb(255 255 255 / 28%);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 16px;
flex-shrink: 0;
box-shadow: 0 3px 10px -3px rgb(0 0 0 / 25%);
}
&__info {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 0;
}
&__status-row {
display: flex;
align-items: center;
gap: 6px;
}
&__title {
margin: 0;
font-size: 15px;
font-weight: 800;
letter-spacing: 0.01em;
color: #fff;
line-height: 1.15;
::ng-deep mifosx-long-text {
color: #fff;
}
}
&__meta {
display: flex;
flex-wrap: wrap;
gap: 2px 18px;
margin-top: 1px;
}
&__meta-item {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: rgb(255 255 255 / 90%);
}
&__meta-label {
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: rgb(255 255 255 / 60%);
font-weight: 600;
}
&__meta-value {
font-weight: 600;
color: #fff;
}
&__kpis {
display: flex;
gap: 8px;
align-items: stretch;
position: relative;
z-index: 1;
}
&__actions {
display: flex;
align-items: center;
position: relative;
z-index: 1;
button {
width: 32px !important;
height: 32px !important;
min-width: 32px !important;
padding: 0 !important;
border-radius: 50% !important;
color: #fff !important;
background: rgb(255 255 255 / 10%) !important;
border: 1px solid rgb(255 255 255 / 22%) !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
line-height: 1;
transition:
background 0.15s ease,
border-color 0.15s ease,
transform 0.12s ease;
::ng-deep fa-icon {
font-size: 14px;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
}
::ng-deep .mat-mdc-button-persistent-ripple,
::ng-deep .mat-mdc-button-touch-target {
border-radius: 50% !important;
}
}
button:hover {
background: rgb(255 255 255 / 22%) !important;
border-color: rgb(255 255 255 / 38%) !important;
}
button:active {
transform: scale(0.94);
}
}
}
/* Balance KPI tiles */
.cur-kpi {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 130px;
padding: 7px 14px;
border-radius: 9px;
background: rgb(255 255 255 / 14%);
border: 1px solid rgb(255 255 255 / 22%);
backdrop-filter: blur(8px);
&__label {
font-size: 9.5px;
text-transform: uppercase;
letter-spacing: 0.07em;
font-weight: 700;
color: rgb(255 255 255 / 75%);
}
&__value {
margin-top: 2px;
font-size: 15px;
font-weight: 800;
color: #fff;
font-variant-numeric: tabular-nums;
letter-spacing: -0.01em;
}
&--available {
background: rgb(16 185 129 / 22%);
border-color: rgb(16 185 129 / 35%);
}
}
/* Status pill */
.cur-status-pill {
display: inline-flex;
align-items: center;
gap: 5px;
height: 18px;
padding: 0 8px;
border-radius: 999px;
background: rgb(16 185 129 / 24%);
border: 1px solid rgb(16 185 129 / 40%);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #d1fae5;
&__dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 0 2px rgb(16 185 129 / 30%);
}
&--warn {
background: rgb(245 158 11 / 24%);
border-color: rgb(245 158 11 / 40%);
color: #fef3c7;
.cur-status-pill__dot {
background: #f59e0b;
box-shadow: 0 0 0 3px rgb(245 158 11 / 30%);
}
}
&.statussubmitted,
&.statuspending {
background: rgb(245 158 11 / 24%);
border-color: rgb(245 158 11 / 40%);
color: #fef3c7;
.cur-status-pill__dot {
background: #f59e0b;
}
}
&.statusclosed,
&.statusrejected,
&.statuswithdrawn {
background: rgb(239 68 68 / 24%);
border-color: rgb(239 68 68 / 40%);
color: #fee2e2;
.cur-status-pill__dot {
background: #ef4444;
}
}
}
/* ─── Pill-style tab navigation ─────────────────────────────────────── */
.cur-tabs {
margin-top: 18px;
background: #fff;
border: 1px solid $border;
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;
flex-wrap: wrap;
}
.mdc-tab-indicator__content--underline,
.mat-mdc-tab-header-pagination-controls-enabled .mdc-tab-indicator__content--underline {
display: none !important;
}
}
}
.cur-tab {
display: inline-flex !important;
align-items: center;
gap: 8px;
height: 38px !important;
min-width: 0 !important;
padding: 0 16px !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: 12px;
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,
.cur-tab__ic {
color: #fff !important;
opacity: 1 !important;
}
}
}
.cur-body {
margin-top: 16px;
}
/* ─── Responsive ────────────────────────────────────────────────────── */
@media (width <= 1100px) {
.cur-hero {
grid-template-columns: 1fr;
&__kpis {
width: 100%;
flex-wrap: wrap;
}
&__actions {
position: absolute;
top: 18px;
right: 18px;
}
}
.cur-kpi {
flex: 1 1 auto;
min-width: 0;
}
}
@media (width <= 700px) {
.cur-view {
padding: 12px;
}
.cur-hero {
padding: 18px;
&__title {
font-size: 18px;
}
&__avatar {
width: 52px;
height: 52px;
font-size: 22px;
border-radius: 12px;
}
}
.cur-tab {
padding: 0 12px !important;
font-size: 12px !important;
}
} }
@@ -13,355 +13,390 @@
} }
@if (!isLoading) { @if (!isLoading) {
<div class="current-account-tables layout-row gap-2percent"> <div class="gt-grid">
<div class="flex-49 layout-column gap-4percent"> <!-- ─── LEFT COLUMN ──────────────────────────────────────────── -->
@if (!currentAccountData.status.rejected && !currentAccountData.status.submittedAndPendingApproval) { <div class="gt-col">
<div> <!-- Current Account Details -->
<h4 class="table-headers">{{ 'labels.heading.Current Account Details' | translate }}</h4> <section class="nx-card">
<table> <header class="nx-card__head">
<tbody> <fa-icon icon="info-circle" class="nx-card__ico"></fa-icon>
<tr> <h3 class="nx-card__title">{{ 'labels.heading.Current Account Details' | translate }}</h3>
<td>{{ 'labels.inputs.External Id' | translate }}</td> </header>
<div class="nx-card__body">
@if (!currentAccountData.status.rejected && !currentAccountData.status.submittedAndPendingApproval) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.External Id' | translate }}</span>
<span class="nx-row__value">
@if (currentAccountData.externalId) { @if (currentAccountData.externalId) {
<td>
<mifosx-external-identifier
externalId="{{ currentAccountData.externalId }}"
></mifosx-external-identifier>
</td>
}
@if (!currentAccountData.externalId) {
<td>{{ 'labels.inputs.Not Provided' | translate }}</td>
}
</tr>
<tr>
<td>{{ 'labels.inputs.Activated On' | translate }}</td>
<td>
{{
currentAccountData.timeline.activatedOnDate
? (currentAccountData.timeline.activatedOnDate | dateFormat)
: 'Not Activated'
}}
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Field Officer' | translate }}</td>
<td>{{ currentAccountData.fieldOfficerName ? currentAccountData.fieldOfficerName : 'Unassigned' }}</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Currency' | translate }}</td>
<td>{{ currentAccountData.currency.name }} [{{ currentAccountData.currency.code }}]</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Nominal Interest Rate' | translate }}</td>
<td class="r-amount">
@if (currentAccountData.nominalAnnualInterestRate) {
<span>{{ currentAccountData.nominalAnnualInterestRate | formatNumber }} %</span>
}
@if (!currentAccountData.nominalAnnualInterestRate) {
<span>0 %</span>
}
</td>
</tr>
</tbody>
</table>
</div>
} @else {
<div>
<h4 class="table-headers">{{ 'labels.heading.Current Account Details' | translate }}</h4>
<table>
<tbody>
<tr>
<td>{{ 'labels.inputs.Field Officer' | translate }}</td>
<td>{{ currentAccountData.fieldOfficerName ? currentAccountData.fieldOfficerName : 'Unassigned' }}</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Balance' | translate }}</td>
<td class="r-amount">
{{ currentAccountData.summary.accountBalance | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
</tbody>
</table>
</div>
}
@if (!currentAccountData.status.rejected && !currentAccountData.status.submittedAndPendingApproval) {
<div>
<h4 class="table-headers">{{ 'labels.heading.Performance History' | translate }}</h4>
<table>
<tbody>
@if (currentAccountData.summary.totalDeposits) {
<tr>
<td>{{ 'labels.inputs.Total Deposits' | translate }}</td>
<td class="r-amount">
{{ currentAccountData.summary.totalDeposits | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
}
@if (currentAccountData.summary.totalInterestEarned >= 0) {
<tr>
<td>{{ 'labels.inputs.Total Interest Earned' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.totalInterestEarned
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
@if (isActive) {
<div class="flex-49">
<h4 class="table-headers">{{ 'labels.heading.Account Summary' | translate }}</h4>
<table>
<tbody>
@if (currentAccountData.summary.totalWithdrawals) {
<tr>
<td>{{ 'labels.inputs.Total Withdrawls' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.totalWithdrawals | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.summary.totalWithdrawalFees) {
<tr>
<td>{{ 'labels.inputs.Withdrawals Fees' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.totalWithdrawalFees | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.summary.totalAnnualFees) {
<tr>
<td>{{ 'labels.inputs.Annual Fees' | translate }}</td>
<td class="r-amount">
{{ currentAccountData.summary.totalAnnualFees | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
}
@if (currentAccountData.summary.totalInterestEarned >= 0) {
<tr>
<td>{{ 'labels.inputs.Interest Earned' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.totalInterestEarned | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.summary.totalInterestPosted) {
<tr>
<td>{{ 'labels.inputs.Interest Posted' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.totalInterestPosted | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.summary.interestNotPosted >= 0) {
<tr>
<td>{{ 'labels.inputs.Interest Earned Not Posted' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.interestNotPosted | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.summary.totalOverdraftInterestDerived) {
<tr>
<td>{{ 'labels.inputs.Interest On Overdraft' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.totalOverdraftInterestDerived
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.summary.interestNotPosted < 0) {
<tr>
<td>{{ 'labels.inputs.Overdraft Interest Not Posted' | translate }}</td>
<td class="r-amount">
{{
currentAccountData.summary.interestNotPosted | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.nominalAnnualInterestRate) {
<tr>
<td>{{ 'labels.inputs.Nominal Interest Rate' | translate }}</td>
<td class="r-amount">{{ currentAccountData.nominalAnnualInterestRate | formatNumber }} %</td>
</tr>
}
<tr>
<td>{{ 'labels.inputs.Interest Compounding Period' | translate }}</td>
<td>{{ currentAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs' }}</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest Posting Period' | translate }}</td>
<td>{{ currentAccountData.interestPostingPeriodType.value | translateKey: 'catalogs' }}</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest Calculated Using' | translate }}</td>
<td>{{ currentAccountData.interestCalculationType.value | translateKey: 'catalogs' }}</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Days in Year' | translate }}</td>
<td>{{ currentAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs' }}</td>
</tr>
@if (currentAccountData.withdrawalFee) {
<tr>
<td>{{ 'labels.inputs.Withdrawal Fee' | translate }}</td>
<td class="r-amount">
{{ currentAccountData.withdrawalFee.amount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
}
@if (currentAccountData.lastActiveTransactionDate) {
<tr>
<td>{{ 'labels.inputs.Last Active Transaction Date' | translate }}</td>
<td>{{ currentAccountData.lastActiveTransactionDate | dateFormat }}</td>
</tr>
}
@if (!(currentAccountData.subStatus.id === 0)) {
<tr>
<td>{{ 'labels.inputs.Substatus' | translate }}</td>
<td>{{ currentAccountData.subStatus.value }}</td>
</tr>
}
@if (currentAccountData.daysToInactive) {
<tr>
<td>{{ 'labels.inputs.Days to Inactive' | translate }}</td>
<td>{{ currentAccountData.daysToInactive }}</td>
</tr>
}
@if (currentAccountData.daysToDormancy) {
<tr>
<td>{{ 'labels.inputs.Days to Dormancy' | translate }}</td>
<td>{{ currentAccountData.daysToDormancy }}</td>
</tr>
}
@if (currentAccountData.daysToEscheat) {
<tr>
<td>{{ 'labels.inputs.Days to Escheat' | translate }}</td>
<td>{{ currentAccountData.daysToEscheat }}</td>
</tr>
}
@if (currentAccountData.annualFee) {
<tr>
<td>{{ 'labels.inputs.Annual Fee' | translate }}</td>
<td class="r-amount">
{{ currentAccountData.annualFee.amount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
}
@if (currentAccountData.allowOverdraft) {
<tr>
<td>{{ 'labels.inputs.Overdraft Limit' | translate }}</td>
<td class="r-amount">
{{ currentAccountData.overdraftLimit | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
}
@if (currentAccountData.allowOverdraft) {
<tr>
<td>{{ 'labels.inputs.Minimum Overdraft Required for Interest Calculation' | translate }}</td>
<td>
{{
currentAccountData.minOverdraftForInterestCalculation
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
}
@if (currentAccountData.minBalanceForInterestCalculation) {
<tr>
<td>{{ 'labels.inputs.Min Balance Required for Interest Calculation' | translate }}</td>
<td>{{ currentAccountData.minBalanceForInterestCalculation | formatNumber }}</td>
</tr>
}
@if (currentAccountData.minRequiredBalance) {
<tr>
<td>{{ 'labels.inputs.Minimum Required Balance' | translate }}</td>
<td>{{ currentAccountData.minRequiredBalance | formatNumber }}</td>
</tr>
}
@if (currentAccountData.enforceMinRequiredBalance) {
<tr>
<td>{{ 'labels.inputs.Enforce Minimum Required Balance' | translate }}</td>
<td>{{ currentAccountData.enforceMinRequiredBalance | yesNo }}</td>
</tr>
}
@if (currentAccountData.summary.lastInterestCalculationDate) {
<tr>
<td>{{ 'labels.inputs.Interest Recalculation Date' | translate }}</td>
<td>{{ currentAccountData.summary.lastInterestCalculationDate | dateFormat }}</td>
</tr>
}
@if (currentAccountData.onHoldFunds) {
<tr>
<td>{{ 'labels.inputs.On Hold Funds' | translate }}</td>
<td>
<a *mifosxHasPermission="'READ_CURRENTACCOUNT'">{{
currentAccountData.onHoldFunds | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</a>
</td>
</tr>
}
@if (currentAccountData.withHoldTax) {
<tr>
<td>{{ 'labels.inputs.Withhold Tax Group' | translate }}</td>
<td>{{ currentAccountData.taxGroup.name }}</td>
</tr>
}
</tbody>
</table>
</div>
} @else {
<div class="flex-49">
<h4 class="table-headers">{{ 'labels.heading.Account Summary' | translate }}</h4>
<table>
<tbody>
<tr>
<td>{{ 'labels.inputs.External Id' | translate }}</td>
@if (currentAccountData.externalId) {
<td>
<mifosx-external-identifier <mifosx-external-identifier
externalId="{{ currentAccountData.externalId }}" externalId="{{ currentAccountData.externalId }}"
></mifosx-external-identifier> ></mifosx-external-identifier>
</td> } @else {
} {{ 'labels.inputs.Not Provided' | translate }}
@if (!currentAccountData.externalId) { }
<td>{{ 'labels.inputs.Not Provided' | translate }}</td> </span>
} </div>
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Activated On' | translate }}</span>
<td>{{ 'labels.inputs.Activated On' | translate }}</td> <span class="nx-row__value">
<td>
{{ {{
currentAccountData.timeline.activatedOnDate currentAccountData.timeline.activatedOnDate
? (currentAccountData.timeline.activatedOnDate | dateFormat) ? (currentAccountData.timeline.activatedOnDate | dateFormat)
: 'Not Activated' : 'Not Activated'
}} }}
</td> </span>
</tr> </div>
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Currency' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Field Officer' | translate }}</span>
<td>{{ currentAccountData.currency.name }} [{{ currentAccountData.currency.code }}]</td> <span class="nx-row__value">
</tr> {{ currentAccountData.fieldOfficerName ? currentAccountData.fieldOfficerName : 'Unassigned' }}
</tbody> </span>
</table> </div>
</div> <div class="nx-row">
} <span class="nx-row__label">{{ 'labels.inputs.Currency' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.currency.name }}
<span class="nx-mono">[{{ currentAccountData.currency.code }}]</span>
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Nominal Interest Rate' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
@if (currentAccountData.nominalAnnualInterestRate) {
{{ currentAccountData.nominalAnnualInterestRate | formatNumber }} %
} @else {
0 %
}
</span>
</div>
} @else {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Field Officer' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.fieldOfficerName ? currentAccountData.fieldOfficerName : 'Unassigned' }}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Balance' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ currentAccountData.summary.accountBalance | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
</div>
</section>
<!-- Performance History -->
@if (!currentAccountData.status.rejected && !currentAccountData.status.submittedAndPendingApproval) {
<section class="nx-card">
<header class="nx-card__head">
<fa-icon icon="chart-line" class="nx-card__ico"></fa-icon>
<h3 class="nx-card__title">{{ 'labels.heading.Performance History' | translate }}</h3>
</header>
<div class="nx-card__body">
@if (currentAccountData.summary.totalDeposits) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Total Deposits' | translate }}</span>
<span class="nx-row__value nx-row__value--amount nx-row__value--positive">
{{ currentAccountData.summary.totalDeposits | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
@if (currentAccountData.summary.totalInterestEarned >= 0) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Total Interest Earned' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.totalInterestEarned | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (!currentAccountData.summary.totalDeposits && !(currentAccountData.summary.totalInterestEarned >= 0)) {
<div class="nx-empty">
<fa-icon icon="inbox" class="nx-empty__ico"></fa-icon>
<span>No activity yet.</span>
</div>
}
</div>
</section>
}
</div>
<!-- ─── RIGHT COLUMN ─────────────────────────────────────────── -->
<div class="gt-col">
@if (isActive) {
<section class="nx-card">
<header class="nx-card__head">
<fa-icon icon="file-invoice" class="nx-card__ico"></fa-icon>
<h3 class="nx-card__title">{{ 'labels.heading.Account Summary' | translate }}</h3>
</header>
<div class="nx-card__body">
@if (currentAccountData.summary.totalWithdrawals) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Total Withdrawls' | translate }}</span>
<span class="nx-row__value nx-row__value--amount nx-row__value--negative">
{{
currentAccountData.summary.totalWithdrawals | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.summary.totalWithdrawalFees) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Withdrawals Fees' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.totalWithdrawalFees | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.summary.totalAnnualFees) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Annual Fees' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ currentAccountData.summary.totalAnnualFees | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
@if (currentAccountData.summary.totalInterestEarned >= 0) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Earned' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.totalInterestEarned | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.summary.totalInterestPosted) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Posted' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.totalInterestPosted | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.summary.interestNotPosted >= 0) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Earned Not Posted' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.interestNotPosted | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.summary.totalOverdraftInterestDerived) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest On Overdraft' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.totalOverdraftInterestDerived
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.summary.interestNotPosted < 0) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Overdraft Interest Not Posted' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
currentAccountData.summary.interestNotPosted | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.nominalAnnualInterestRate) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Nominal Interest Rate' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ currentAccountData.nominalAnnualInterestRate | formatNumber }} %
</span>
</div>
}
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Compounding Period' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs' }}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Posting Period' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.interestPostingPeriodType.value | translateKey: 'catalogs' }}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Calculated Using' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.interestCalculationType.value | translateKey: 'catalogs' }}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Days in Year' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs' }}
</span>
</div>
@if (currentAccountData.withdrawalFee) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Withdrawal Fee' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ currentAccountData.withdrawalFee.amount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
@if (currentAccountData.lastActiveTransactionDate) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Last Active Transaction Date' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.lastActiveTransactionDate | dateFormat }}</span>
</div>
}
@if (!(currentAccountData.subStatus.id === 0)) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Substatus' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.subStatus.value }}</span>
</div>
}
@if (currentAccountData.daysToInactive) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Days to Inactive' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.daysToInactive }}</span>
</div>
}
@if (currentAccountData.daysToDormancy) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Days to Dormancy' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.daysToDormancy }}</span>
</div>
}
@if (currentAccountData.daysToEscheat) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Days to Escheat' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.daysToEscheat }}</span>
</div>
}
@if (currentAccountData.annualFee) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Annual Fee' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ currentAccountData.annualFee.amount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
@if (currentAccountData.allowOverdraft) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Overdraft Limit' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ currentAccountData.overdraftLimit | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
@if (currentAccountData.allowOverdraft) {
<div class="nx-row">
<span class="nx-row__label">
{{ 'labels.inputs.Minimum Overdraft Required for Interest Calculation' | translate }}
</span>
<span class="nx-row__value">
{{
currentAccountData.minOverdraftForInterestCalculation
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
}
@if (currentAccountData.minBalanceForInterestCalculation) {
<div class="nx-row">
<span class="nx-row__label">
{{ 'labels.inputs.Min Balance Required for Interest Calculation' | translate }}
</span>
<span class="nx-row__value">
{{ currentAccountData.minBalanceForInterestCalculation | formatNumber }}
</span>
</div>
}
@if (currentAccountData.minRequiredBalance) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Minimum Required Balance' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.minRequiredBalance | formatNumber }}</span>
</div>
}
@if (currentAccountData.enforceMinRequiredBalance) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Enforce Minimum Required Balance' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.enforceMinRequiredBalance | yesNo }}</span>
</div>
}
@if (currentAccountData.summary.lastInterestCalculationDate) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Interest Recalculation Date' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.summary.lastInterestCalculationDate | dateFormat }}
</span>
</div>
}
@if (currentAccountData.onHoldFunds) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.On Hold Funds' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
<a *mifosxHasPermission="'READ_CURRENTACCOUNT'">
{{ currentAccountData.onHoldFunds | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</a>
</span>
</div>
}
@if (currentAccountData.withHoldTax) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Withhold Tax Group' | translate }}</span>
<span class="nx-row__value">{{ currentAccountData.taxGroup.name }}</span>
</div>
}
</div>
</section>
} @else {
<section class="nx-card">
<header class="nx-card__head">
<fa-icon icon="file-invoice" class="nx-card__ico"></fa-icon>
<h3 class="nx-card__title">{{ 'labels.heading.Account Summary' | translate }}</h3>
</header>
<div class="nx-card__body">
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.External Id' | translate }}</span>
<span class="nx-row__value">
@if (currentAccountData.externalId) {
<mifosx-external-identifier
externalId="{{ currentAccountData.externalId }}"
></mifosx-external-identifier>
} @else {
{{ 'labels.inputs.Not Provided' | translate }}
}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Activated On' | translate }}</span>
<span class="nx-row__value">
{{
currentAccountData.timeline.activatedOnDate
? (currentAccountData.timeline.activatedOnDate | dateFormat)
: 'Not Activated'
}}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Currency' | translate }}</span>
<span class="nx-row__value">
{{ currentAccountData.currency.name }}
<span class="nx-mono">[{{ currentAccountData.currency.code }}]</span>
</span>
</div>
</div>
</section>
}
</div>
</div> </div>
} }
@@ -6,9 +6,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
$navy: #0d1b2a;
$slate: #475569;
$muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
/* ─── Loader keyframes ──────────────────────────────────────────────── */
$bar: 160px; $bar: 160px;
$foo: $bar * 8; $foo: $bar * 8;
$color: #e2e4ec;
.loader { .loader {
margin-bottom: 39px; margin-bottom: 39px;
@@ -79,164 +85,136 @@ $color: #e2e4ec;
} }
} }
.general-tab-container { /* ─── Two-column grid ───────────────────────────────────────────────── */
padding: 16px 20px; .gt-grid {
width: 100%; display: grid;
box-sizing: border-box; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
position: relative; gap: 16px;
background-color: var(--background-color, #f8f9fa);
color: var(--text-color, #333);
transition:
background-color 0.3s ease,
color 0.3s ease;
.page-header { @media (width <= 1024px) {
margin-bottom: 24px; grid-template-columns: 1fr;
padding: 16px 0; }
position: relative; }
border-bottom: 1px solid var(--border-color, #e9ecef);
.header-title { .gt-col {
font-size: 1.75rem; display: flex;
font-weight: 600; flex-direction: column;
margin: 0 0 8px; gap: 16px;
line-height: 1.2; min-width: 0;
color: var(--primary-color, #007bff); }
position: relative;
}
.header-subtitle { /* ─── Nexora section card ───────────────────────────────────────────── */
font-size: 0.95rem; .nx-card {
margin: 0; background: #fff;
line-height: 1.4; border: 1px solid $border;
color: var(--text-secondary, #6c757d); border-radius: 14px;
position: relative; box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
} overflow: hidden;
&__head {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
} }
.content-wrapper { &__ico {
position: relative; width: 26px;
width: 100%; height: 26px;
} display: inline-flex;
align-items: center;
.account-info-card { justify-content: center;
background: var(--card-background, #fff);
border-radius: 8px; border-radius: 8px;
box-shadow: 0 2px 4px rgb(0 0 0 / 10%); background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
overflow: hidden; color: #fff;
position: relative; font-size: 12px;
width: 100%; }
max-width: 600px;
transition:
box-shadow 0.3s ease,
background-color 0.3s ease;
.card-header { &__title {
padding: 16px 20px; margin: 0;
background: var(--card-header-bg, #f8f9fa); font-size: 13.5px;
border-bottom: 1px solid var(--border-color, #e9ecef); font-weight: 700;
position: relative; color: $navy;
letter-spacing: 0.01em;
}
h3 { &__body {
margin: 0; padding: 4px 18px 10px;
font-size: 1.1rem; }
font-weight: 600; }
line-height: 1.3;
color: var(--text-color, #333); /* ─── Key/Value row ─────────────────────────────────────────────────── */
} .nx-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
min-height: 38px;
padding: 8px 0;
border-bottom: 1px dashed #eef2f7;
font-size: 13px;
&:last-child {
border-bottom: none;
}
&__label {
color: $slate;
font-weight: 500;
}
&__value {
color: $navy;
font-weight: 600;
text-align: right;
word-break: break-word;
&--amount {
font-variant-numeric: tabular-nums;
font-weight: 700;
} }
.card-content { &--positive {
padding: 20px; color: #047857;
position: relative; }
.info-row { &--negative {
display: flex; color: #b91c1c;
justify-content: space-between;
align-items: baseline;
padding: 10px 0;
border-bottom: 1px solid var(--border-light, #f1f3f4);
position: relative;
min-height: 24px;
&:last-child {
border-bottom: none;
}
.label {
font-weight: 500;
color: var(--text-secondary, #6c757d);
flex: 0 0 auto;
margin-right: 16px;
white-space: nowrap;
line-height: 1.4;
}
.value {
font-weight: 600;
color: var(--text-color, #333);
text-align: right;
flex: 1 1 auto;
line-height: 1.4;
&.currency {
color: var(--success-color, #28a745);
font-size: 1.05rem;
}
}
}
} }
} }
} }
// Dark mode styles .nx-muted {
[data-theme='dark'] .general-tab-container, color: $muted;
.dark-theme .general-tab-container { font-weight: 500;
--background-color: #1a1a1a; font-style: italic;
--text-color: #e9ecef;
--text-secondary: #adb5bd;
--primary-color: #4dabf7;
--card-background: #2d3748;
--card-header-bg: #374151;
--border-color: #4a5568;
--border-light: #2d3748;
--success-color: #68d391;
} }
// Responsive adjustments for mobile .nx-mono {
@media (width <= 768px) { font-family: 'JetBrains Mono', 'Courier New', monospace;
.general-tab-container { font-size: 12.5px;
padding: 12px 16px; color: $muted;
margin-left: 4px;
}
.page-header { /* ─── Empty state inside a card ─────────────────────────────────────── */
margin-bottom: 20px; .nx-empty {
padding: 12px 0; display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 24px 16px;
color: $muted;
.header-title { &__ico {
font-size: 1.5rem; font-size: 28px;
} color: #cbd5e1;
}
.header-subtitle { span {
font-size: 0.9rem; font-size: 13px;
} font-weight: 500;
}
.account-info-card {
.card-header {
padding: 14px 16px;
}
.card-content {
padding: 16px;
.info-row {
padding: 8px 0;
.label {
margin-right: 12px;
}
}
}
}
} }
} }
@@ -7,8 +7,8 @@
--> -->
<div class="passbook-container"> <div class="passbook-container">
<!-- Date Range Filter --> <!-- Filter Bar -->
<div class="passbook-filter-bar"> <div class="passbook-filter-bar no-print">
<form [formGroup]="dateRangeForm" class="passbook-filter-form"> <form [formGroup]="dateRangeForm" class="passbook-filter-form">
<mat-form-field appearance="outline" class="passbook-date-field" (click)="fromDatePicker.open()"> <mat-form-field appearance="outline" class="passbook-date-field" (click)="fromDatePicker.open()">
<mat-label>{{ 'labels.inputs.From Date' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.From Date' | translate }}</mat-label>
@@ -45,105 +45,152 @@
</form> </form>
</div> </div>
<!-- Passbook Preview (Printable Content) --> <!-- Bank Statement -->
<div class="passbook-preview" #passbookContent> <div class="statement-wrapper" #passbookContent>
<div class="passbook-header"> <!-- Bank Header -->
<h2>{{ 'labels.heading.Current Account Passbook' | translate }}</h2> <div class="bank-header">
<h3>{{ productName }}</h3> <div class="bank-logo-area">
</div> <div class="bank-logo-circle">
<mat-icon>account_balance</mat-icon>
<!-- Account Info --> </div>
<div class="passbook-info-grid"> <div class="bank-name-block">
<div class="passbook-info-item"> <div class="bank-title">LincPay Co-operative Bank Ltd.</div>
<div class="label">{{ 'labels.inputs.Account Number' | translate }}</div> <div class="bank-subtitle">Current Account Statement</div>
<div class="value">{{ accountNo }}</div> </div>
</div> </div>
<div class="passbook-info-item"> <div class="statement-label">
<div class="label">{{ 'labels.inputs.Account Holder' | translate }}</div> <div class="stmt-label-text">STATEMENT OF ACCOUNT</div>
<div class="value">{{ clientName }}</div> <div class="stmt-period">As on: {{ maxDate | dateFormat }}</div>
</div>
<div class="passbook-info-item">
<div class="label">{{ 'labels.inputs.Current Account Product' | translate }}</div>
<div class="value">{{ productName }}</div>
</div>
<div class="passbook-info-item">
<div class="label">{{ 'labels.inputs.Opening Date' | translate }}</div>
<div class="value">{{ activatedOnDate | dateFormat }}</div>
</div>
<div class="passbook-info-item">
<div class="label">{{ 'labels.inputs.Status' | translate }}</div>
<div class="value">{{ status }}</div>
</div>
<div class="passbook-info-item">
<div class="label">{{ 'labels.inputs.Interest Rate' | translate }}</div>
<div class="value">{{ interestRate }}%</div>
</div> </div>
</div> </div>
<!-- Balance Summary --> <!-- Account Details -->
<div class="passbook-balance-row"> <div class="account-details-band">
<div class="balance-item"> <div class="account-details-grid">
<span>{{ 'labels.inputs.Current Balance' | translate }}: </span> <div class="detail-block">
<b>{{ accountBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}</b> <div class="detail-label">Account Holder</div>
<div class="detail-value bold">{{ clientName | uppercase }}</div>
</div>
<div class="detail-block">
<div class="detail-label">Account Number</div>
<div class="detail-value mono bold">{{ accountNo }}</div>
</div>
<div class="detail-block">
<div class="detail-label">Product</div>
<div class="detail-value">{{ productName }}</div>
</div>
<div class="detail-block">
<div class="detail-label">Account Opening Date</div>
<div class="detail-value">{{ activatedOnDate | dateFormat }}</div>
</div>
<div class="detail-block">
<div class="detail-label">Status</div>
<div class="detail-value status-badge" [class.active]="status === 'Active'">{{ status }}</div>
</div>
<div class="detail-block">
<div class="detail-label">Interest Rate (p.a.)</div>
<div class="detail-value">{{ interestRate }}%</div>
</div>
</div> </div>
<div class="balance-item"> </div>
<span>{{ 'labels.inputs.Available Balance' | translate }}: </span>
<b>{{ availableBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}</b> <!-- Balance Summary Strip -->
<div class="balance-summary-strip">
<div class="balance-box">
<div class="balance-box-label">Current Balance</div>
<div class="balance-box-value">{{ accountBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}</div>
</div>
<div class="balance-divider"></div>
<div class="balance-box">
<div class="balance-box-label">Available Balance</div>
<div class="balance-box-value">
{{ availableBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}
</div>
</div>
<div class="balance-divider"></div>
<div class="balance-box">
<div class="balance-box-label">Total Transactions</div>
<div class="balance-box-value">{{ filteredTransactions.length }}</div>
</div> </div>
</div> </div>
<!-- Transactions Table --> <!-- Transactions Table -->
@if (filteredTransactions.length > 0) { @if (filteredTransactions.length > 0) {
<table> <table class="statement-table">
<thead> <thead>
<tr> <tr>
<th>#</th> <th class="col-sr">#</th>
<th>{{ 'labels.inputs.Date' | translate }}</th> <th class="col-date">Date</th>
<th>{{ 'labels.inputs.Description' | translate }}</th> <th class="col-desc">Description</th>
<th class="text-right">{{ 'labels.inputs.Debit' | translate }}</th> <th class="col-ref">Ref No.</th>
<th class="text-right">{{ 'labels.inputs.Credit' | translate }}</th> <th class="col-amount text-right">Debit (Dr)</th>
<th class="text-right">{{ 'labels.inputs.Balance' | translate }}</th> <th class="col-amount text-right">Credit (Cr)</th>
<th class="col-balance text-right">Balance (&#8377;)</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@for (txn of filteredTransactions; track txn.id; let i = $index) { @for (txn of filteredTransactions; track txn.id; let i = $index) {
<tr [class.reversed]="txn.reversed"> <tr
<td>{{ i + 1 }}</td> [class.reversed-row]="txn.reversed"
<td>{{ txn.date | dateFormat }}</td> [class.debit-row]="isDebit(txn.transactionType) && !txn.reversed"
<td>{{ txn.transactionType.value }}</td> [class.credit-row]="!isDebit(txn.transactionType) && !txn.reversed"
<td class="text-right"> >
<td class="col-sr text-center">{{ i + 1 }}</td>
<td class="col-date">{{ txn.date | dateFormat }}</td>
<td class="col-desc">
<span class="txn-desc">{{ txn.transactionType.value }}</span>
@if (txn.reversed) {
<span class="reversed-badge">REVERSED</span>
}
</td>
<td class="col-ref text-muted mono">{{ txn.id }}</td>
<td class="col-amount text-right debit-amount">
@if (isDebit(txn.transactionType)) { @if (isDebit(txn.transactionType)) {
{{ txn.amount | currency: currency?.code : 'symbol-narrow' : '1.2-2' }} {{ txn.amount | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}
} }
</td> </td>
<td class="text-right"> <td class="col-amount text-right credit-amount">
@if (!isDebit(txn.transactionType)) { @if (!isDebit(txn.transactionType)) {
{{ txn.amount | currency: currency?.code : 'symbol-narrow' : '1.2-2' }} {{ txn.amount | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}
} }
</td> </td>
<td class="text-right"> <td class="col-balance text-right balance-amount">
{{ txn.runningBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }} {{ txn.runningBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}
</td> </td>
</tr> </tr>
} }
</tbody> </tbody>
<tfoot>
<tr class="total-row">
<td colspan="4" class="text-right total-label">Closing Balance</td>
<td class="text-right total-label"></td>
<td class="text-right total-label"></td>
<td class="text-right closing-balance">
{{ accountBalance | currency: currency?.code : 'symbol-narrow' : '1.2-2' }}
</td>
</tr>
</tfoot>
</table> </table>
} @else { } @else {
<div class="passbook-no-data"> <div class="no-data-block">
<mat-icon>info_outline</mat-icon> <mat-icon>inbox</mat-icon>
<span>{{ <p>
isFiltered {{
? ('labels.text.No transactions found for the selected date range.' | translate) isFiltered
: 'No transactions found.' ? ('labels.text.No transactions found for the selected date range.' | translate)
}}</span> : 'No transactions found.'
}}
</p>
</div> </div>
} }
<!-- Footer --> <!-- Statement Footer -->
<div class="passbook-footer"> <div class="statement-footer">
{{ 'labels.text.Generated on' | translate }}: {{ maxDate | dateFormat }} <div class="footer-note">
&nbsp;|&nbsp; This is a computer-generated statement and does not require a signature. For queries, contact your branch or
{{ 'labels.text.Total Transactions' | translate }}: {{ filteredTransactions.length }} call customer care.
</div>
<div class="footer-meta">Generated on: {{ maxDate | dateFormat }} &nbsp;|&nbsp; Account No: {{ accountNo }}</div>
</div> </div>
</div> </div>
</div> </div>
@@ -6,13 +6,31 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
// ─── Variables ──────────────────────────────────────────────────────────────
$bank-primary: #1a3a6b; // deep navy (like SBI/PNB)
$bank-accent: #c8a951; // gold trim
$debit-color: #c0392b;
$credit-color: #1a7a3f;
$balance-color: #1a3a6b;
$border-color: #d0d7e3;
$row-alt: #f4f7fb;
$header-bg: #1a3a6b;
$header-text: #fff;
// ─── Container ──────────────────────────────────────────────────────────────
.passbook-container { .passbook-container {
padding: 16px; padding: 16px;
background: #eef1f7;
min-height: 100%;
} }
// Filter Bar // ─── Filter Bar ─────────────────────────────────────────────────────────────
.passbook-filter-bar { .passbook-filter-bar {
margin-bottom: 16px; margin-bottom: 16px;
background: #fff;
border-radius: 8px;
padding: 12px 16px;
border: 1px solid $border-color;
} }
.passbook-filter-form { .passbook-filter-form {
@@ -30,147 +48,388 @@
flex: 1; flex: 1;
} }
// Passbook Preview // ─── Statement Wrapper ───────────────────────────────────────────────────────
.passbook-preview { .statement-wrapper {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 24px;
background: #fff; background: #fff;
border: 1px solid $border-color;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px rgb(0 0 0 / 8%);
font-family: 'Segoe UI', Arial, sans-serif;
} }
.passbook-header { // ─── Bank Header ─────────────────────────────────────────────────────────────
text-align: center; .bank-header {
margin-bottom: 20px; background: $bank-primary;
border-bottom: 2px solid #1976d2; padding: 18px 24px;
padding-bottom: 12px; display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 4px solid $bank-accent;
}
h2 { .bank-logo-area {
color: #1976d2; display: flex;
font-size: 20px; align-items: center;
margin: 0 0 4px; gap: 14px;
font-weight: 600; }
}
h3 { .bank-logo-circle {
font-size: 14px; width: 52px;
font-weight: 400; height: 52px;
color: #666; border-radius: 50%;
margin: 0; background: $bank-accent;
display: flex;
align-items: center;
justify-content: center;
mat-icon {
color: $bank-primary;
font-size: 28px;
width: 28px;
height: 28px;
} }
} }
.passbook-info-grid { .bank-name-block {
display: grid; .bank-title {
grid-template-columns: repeat(3, 1fr); color: #fff;
gap: 12px 20px; font-size: 18px;
margin-bottom: 16px; font-weight: 700;
padding: 12px; letter-spacing: 0.3px;
background: #f5f5f5; }
border-radius: 6px;
}
.passbook-info-item { .bank-subtitle {
.label { color: $bank-accent;
font-size: 10px; font-size: 11px;
font-weight: 600; font-weight: 500;
color: #888; letter-spacing: 1.5px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.5px;
}
.value {
font-size: 13px;
color: #333;
margin-top: 2px; margin-top: 2px;
} }
} }
.passbook-balance-row { .statement-label {
display: flex; text-align: right;
justify-content: space-between;
margin-bottom: 16px;
padding: 10px 14px;
background: #e3f2fd;
border-radius: 6px;
font-size: 14px;
.balance-item { .stmt-label-text {
b { color: $bank-accent;
color: #1976d2; font-size: 13px;
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
}
.stmt-period {
color: rgb(255 255 255 / 75%);
font-size: 11px;
margin-top: 4px;
}
}
// ─── Account Details Band ────────────────────────────────────────────────────
.account-details-band {
background: #f0f3f9;
border-bottom: 1px solid $border-color;
padding: 14px 24px;
}
.account-details-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px 24px;
}
.detail-block {
.detail-label {
font-size: 9px;
font-weight: 700;
color: #7a8aaa;
text-transform: uppercase;
letter-spacing: 0.8px;
margin-bottom: 3px;
}
.detail-value {
font-size: 13px;
color: #222;
&.bold {
font-weight: 600;
}
&.mono {
font-family: 'Courier New', monospace;
letter-spacing: 1px;
}
&.status-badge {
display: inline-block;
padding: 1px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 600;
background: #eee;
color: #555;
&.active {
background: #d4edda;
color: #155724;
}
} }
} }
} }
// Transactions Table // ─── Balance Summary Strip ───────────────────────────────────────────────────
table { .balance-summary-strip {
display: flex;
align-items: stretch;
background: $bank-primary;
padding: 0;
}
.balance-box {
flex: 1;
padding: 12px 20px;
text-align: center;
.balance-box-label {
font-size: 10px;
font-weight: 600;
color: rgb(255 255 255 / 65%);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 4px;
}
.balance-box-value {
font-size: 16px;
font-weight: 700;
color: $bank-accent;
}
}
.balance-divider {
width: 1px;
background: rgb(255 255 255 / 15%);
margin: 8px 0;
}
// ─── Transactions Table ───────────────────────────────────────────────────────
.statement-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
font-size: 13px; font-size: 12.5px;
th { thead tr {
background: #1976d2; background: #e8edf5;
color: #fff; border-top: 1px solid $border-color;
padding: 8px 10px; border-bottom: 2px solid $bank-primary;
text-align: left;
font-weight: 600;
font-size: 12px;
} }
td { thead th {
padding: 6px 10px; padding: 9px 10px;
border-bottom: 1px solid #e0e0e0; font-size: 11px;
font-weight: 700;
color: $bank-primary;
text-transform: uppercase;
letter-spacing: 0.4px;
white-space: nowrap;
} }
tr:nth-child(even) { tbody tr {
background: #fafafa; border-bottom: 1px solid #e8ecf3;
transition: background 0.1s;
&:nth-child(even) {
background: $row-alt;
}
&:hover {
background: #dce6f5;
}
&.reversed-row {
opacity: 0.5;
text-decoration: line-through;
}
} }
tr:hover { tbody td {
background: #f0f0f0; padding: 7px 10px;
vertical-align: middle;
color: #333;
} }
.reversed { tfoot .total-row {
text-decoration: line-through; background: #e8edf5;
color: #999; border-top: 2px solid $bank-primary;
td {
padding: 9px 10px;
}
} }
} }
// ─── Column widths ────────────────────────────────────────────────────────────
.col-sr {
width: 38px;
}
.col-date {
width: 110px;
white-space: nowrap;
}
.col-desc {
min-width: 160px;
}
.col-ref {
width: 80px;
}
.col-amount {
width: 110px;
}
.col-balance {
width: 120px;
}
// ─── Amount colors ────────────────────────────────────────────────────────────
.debit-amount {
color: $debit-color;
font-weight: 500;
}
.credit-amount {
color: $credit-color;
font-weight: 500;
}
.balance-amount {
color: $balance-color;
font-weight: 600;
font-family: 'Courier New', monospace;
}
.total-label {
font-size: 12px;
font-weight: 700;
color: $bank-primary;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.closing-balance {
font-size: 14px;
font-weight: 700;
color: $bank-primary;
font-family: 'Courier New', monospace;
}
// ─── Badges & misc ────────────────────────────────────────────────────────────
.txn-desc {
font-weight: 500;
}
.reversed-badge {
display: inline-block;
margin-left: 8px;
font-size: 9px;
font-weight: 700;
color: #fff;
background: #e74c3c;
padding: 1px 5px;
border-radius: 3px;
letter-spacing: 0.5px;
}
.text-right { .text-right {
text-align: right; text-align: right;
} }
.passbook-no-data { .text-center {
text-align: center;
}
.text-muted {
color: #999;
}
.mono {
font-family: 'Courier New', monospace;
font-size: 11px;
}
// ─── No Data ──────────────────────────────────────────────────────────────────
.no-data-block {
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 8px; padding: 48px;
padding: 32px; color: #aaa;
color: #888;
font-size: 14px;
mat-icon { mat-icon {
color: #bbb; font-size: 48px;
width: 48px;
height: 48px;
margin-bottom: 12px;
}
p {
font-size: 14px;
margin: 0;
} }
} }
.passbook-footer { // ─── Statement Footer ─────────────────────────────────────────────────────────
margin-top: 16px; .statement-footer {
font-size: 11px; background: #f0f3f9;
color: #999; border-top: 1px solid $border-color;
padding: 12px 24px;
text-align: center; text-align: center;
border-top: 1px solid #e0e0e0;
padding-top: 10px; .footer-note {
font-size: 10px;
color: #888;
margin-bottom: 4px;
font-style: italic;
}
.footer-meta {
font-size: 10px;
color: #aaa;
letter-spacing: 0.3px;
}
} }
// Responsive // ─── Responsive ───────────────────────────────────────────────────────────────
@media (width <= 768px) { @media (width <= 768px) {
.passbook-info-grid { .account-details-grid {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }
.passbook-balance-row { .bank-header {
flex-direction: column; flex-direction: column;
gap: 8px; gap: 12px;
align-items: flex-start;
}
.statement-label {
text-align: left;
}
.balance-summary-strip {
flex-direction: column;
}
.balance-divider {
width: auto;
height: 1px;
margin: 0 20px;
} }
.passbook-filter-form { .passbook-filter-form {
@@ -188,19 +447,35 @@ table {
} }
@media (width <= 480px) { @media (width <= 480px) {
.passbook-info-grid { .account-details-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
// Print-specific styles // ─── Print ────────────────────────────────────────────────────────────────────
@media print { @media print {
.passbook-filter-bar { .no-print {
display: none !important; display: none !important;
} }
.passbook-preview { .passbook-container {
border: none; background: #fff;
padding: 0; padding: 0;
} }
.statement-wrapper {
border: none;
box-shadow: none;
border-radius: 0;
}
.bank-header {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.balance-summary-strip {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
} }
@@ -6,23 +6,22 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="container"> <div class="txn-tab">
<div class="mat-elevation-z1 m-b-25" [hidden]="!accountWithTransactions"> <div class="txn-tab__card" [hidden]="!accountWithTransactions">
<div class="layout-row align-end"> @if (checkStatus()) {
@if (checkStatus()) { <div class="txn-tab__toolbar">
<div class="action-button m-b-20 layout-row gap-20px"> <mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="txn-tab__check">
<mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="accruals"> {{ 'labels.inputs.Hide Reversed' | translate }}
{{ 'labels.inputs.Hide Reversed' | translate }}</mat-checkbox </mat-checkbox>
> <mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="txn-tab__check">
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="accruals"> {{ 'labels.inputs.Hide Accruals' | translate }}
{{ 'labels.inputs.Hide Accruals' | translate }}</mat-checkbox </mat-checkbox>
> <span class="txn-tab__spacer"></span>
<button mat-raised-button color="primary" [routerLink]="['export']"> <button mat-flat-button class="txn-tab__export" [routerLink]="['export']">
{{ 'labels.buttons.Export' | translate }} {{ 'labels.buttons.Export' | translate }}
</button> </button>
</div> </div>
} }
</div>
<table mat-table [dataSource]="dataSource" matSort> <table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="row"> <ng-container matColumnDef="row">
@@ -176,10 +175,11 @@
<mat-paginator [pageSize]="50" [pageSizeOptions]="[50, 100, 200]" showFirstLastButtons></mat-paginator> <mat-paginator [pageSize]="50" [pageSizeOptions]="[50, 100, 200]" showFirstLastButtons></mat-paginator>
</div> </div>
<div class="alert" [hidden]="accountWithTransactions"> <div class="txn-tab__empty" [hidden]="accountWithTransactions">
<div class="message"> <fa-icon icon="inbox" class="txn-tab__empty-ico"></fa-icon>
<i class="fa fa-exclamation-circle alert-check"></i> <div class="txn-tab__empty-title">
{{ 'labels.text.No transaction was found' | translate }} {{ 'labels.text.No transaction was found' | translate }}
</div> </div>
<div class="txn-tab__empty-sub">Posted transactions will appear here.</div>
</div> </div>
</div> </div>
@@ -6,37 +6,151 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
@use 'assets/styles/helper'; $navy: #0d1b2a;
$slate: #475569;
$muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
$blue: #1e40af;
.tab-container { .txn-tab {
padding: 1%; width: 100%;
margin: 1%; }
h3 { .txn-tab__card {
margin: 1% auto; background: #fff;
border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
overflow: hidden;
}
/* ─── Toolbar ─────────────────────────────────────────────────────── */
.txn-tab__toolbar {
display: flex;
align-items: center;
gap: 18px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
flex-wrap: wrap;
}
.txn-tab__check {
font-size: 13px;
color: $slate;
font-weight: 500;
}
.txn-tab__spacer {
flex: 1;
}
.txn-tab__export {
height: 36px !important;
border-radius: 8px !important;
font-weight: 600 !important;
font-size: 13px !important;
padding: 0 16px !important;
background: linear-gradient(135deg, #1e88e5 0%, $blue 100%) !important;
color: #fff !important;
}
/* ─── Table ───────────────────────────────────────────────────────── */
table {
width: 100%;
}
::ng-deep .txn-tab__card {
.mat-mdc-header-row {
background: $soft;
} }
.action-button { .mat-mdc-header-cell {
margin-left: auto; font-size: 11.5px;
font-weight: 800;
color: $slate;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 14px;
border-bottom: 1px solid $border;
} }
table { .mat-mdc-cell {
width: 100%; font-size: 13px;
color: $navy;
padding: 11px 14px;
border-bottom: 1px solid #f1f5f9;
}
.account-action-button { .mat-mdc-row:hover {
min-width: 26px; background: #f8fafc;
padding: 0 0 3px; cursor: pointer;
margin: 0 10%; }
line-height: 25px;
.accruals { /* Tabular numerics on the money columns (Debit / Credit / Balance) +
padding-top: 1%; right-align them. */
} .mat-column-debit,
} .mat-column-credit,
.mat-column-balance {
text-align: right;
font-variant-numeric: tabular-nums;
}
.mat-column-actions {
text-align: center;
width: 80px;
}
/* Compact paginator */
.mat-mdc-paginator {
border-top: 1px solid $border;
background: $soft;
min-height: 48px;
}
/* Row tint variants — strike-through reversed, dim accrual, blue transfer */
.strike td {
text-decoration: line-through;
color: $muted;
}
.accrual td {
color: $muted;
font-style: italic;
}
.transfer td {
color: #6d28d9;
} }
} }
.select-row:hover { /* ─── Empty state ─────────────────────────────────────────────────── */
cursor: pointer; .txn-tab__empty {
font-weight: 800; background: #fff;
border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
padding: 56px 24px;
text-align: center;
color: $muted;
}
.txn-tab__empty-ico {
font-size: 34px;
color: #cbd5e1;
margin-bottom: 8px;
}
.txn-tab__empty-title {
font-size: 14.5px;
font-weight: 700;
color: $slate;
margin-top: 6px;
}
.txn-tab__empty-sub {
font-size: 12.5px;
color: $muted;
margin-top: 2px;
} }
@@ -6,21 +6,18 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="tab-container mat-typography"> <div class="chg-tab">
<div class="layout-row align-start"> <div class="chg-tab__card">
<div class="m-b-10"> <div class="chg-tab__toolbar">
<h3>{{ 'labels.heading.All Charges' | translate }}</h3> <h3 class="chg-tab__title">{{ 'labels.heading.All Charges' | translate }}</h3>
</div> <span class="chg-tab__spacer"></span>
@if (this.chargesData) { @if (this.chargesData) {
<div class="action-button m-b-20"> <button mat-flat-button class="chg-tab__toggle" (click)="toggleCharges()">
<button mat-raised-button color="primary" (click)="toggleCharges()">
{{ showInactiveCharges ? 'View Active Charges' : 'View Inactive Charges' }} {{ showInactiveCharges ? 'View Active Charges' : 'View Inactive Charges' }}
</button> </button>
</div> }
} </div>
</div>
<div class="mat-elevation-z1 m-b-25">
<table mat-table #chargesTable [dataSource]="dataSource"> <table mat-table #chargesTable [dataSource]="dataSource">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th> <th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
@@ -6,26 +6,106 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
.tab-container { $navy: #0d1b2a;
padding: 1%; $slate: #475569;
margin: 1%; $muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
$blue: #1e40af;
h3 { .chg-tab {
margin: 1% auto; width: 100%;
}
.chg-tab__card {
background: #fff;
border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
overflow: hidden;
}
.chg-tab__toolbar {
display: flex;
align-items: center;
gap: 14px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
}
.chg-tab__title {
margin: 0;
font-size: 14px;
font-weight: 700;
color: $navy;
letter-spacing: 0.01em;
}
.chg-tab__spacer {
flex: 1;
}
.chg-tab__toggle {
height: 34px !important;
border-radius: 8px !important;
font-weight: 600 !important;
font-size: 13px !important;
padding: 0 14px !important;
background: linear-gradient(135deg, #1e88e5 0%, $blue 100%) !important;
color: #fff !important;
}
table {
width: 100%;
}
::ng-deep .chg-tab__card {
.mat-mdc-header-row {
background: $soft;
} }
.action-button { .mat-mdc-header-cell {
margin-left: auto; font-size: 11.5px;
font-weight: 800;
color: $slate;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 14px;
border-bottom: 1px solid $border;
} }
table { .mat-mdc-cell {
width: 100%; font-size: 13px;
color: $navy;
padding: 11px 14px;
border-bottom: 1px solid #f1f5f9;
}
.mat-mdc-row:hover {
background: #f8fafc;
cursor: pointer;
}
.mat-column-due,
.mat-column-paid,
.mat-column-waived,
.mat-column-outstanding {
text-align: right;
font-variant-numeric: tabular-nums;
}
.mat-column-actions {
text-align: center;
width: 140px;
.account-action-button { .account-action-button {
min-width: 26px; min-width: 30px !important;
padding: 0 6px; padding: 0 8px !important;
margin: 4px; margin: 0 3px !important;
line-height: 25px; height: 30px !important;
line-height: 30px !important;
border-radius: 7px !important;
} }
} }
} }
@@ -6,191 +6,191 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<mat-card class="account-card"> <div class="fd-view">
<mat-card-header class="header layout-column"> <!-- ─── Gradient hero header ─────────────────────────────────────── -->
<mat-card-title-group class="header-title-group"> <header class="fd-hero">
<div class="profile-image-container"> <div class="fd-hero__left">
<div> <div class="fd-hero__avatar">
<img <fa-icon icon="piggy-bank"></fa-icon>
mat-card-md-image </div>
class="profile-image"
matTooltip="{{ 'tooltips.Fixed Deposits Account' | translate }}" <div class="fd-hero__info">
[src]="'assets/images/fd_account_placeholder.png'" <div class="fd-hero__status-row">
/> <span
class="fd-status-pill"
[ngClass]="fixedDepositsAccountData.status.code | statusLookup"
[matTooltip]="fixedDepositsAccountData.status.value"
>
<span class="fd-status-pill__dot"></span>
{{ fixedDepositsAccountData.status.value }}
</span>
</div>
<h2 class="fd-hero__title">
<mifosx-long-text textValue="{{ fixedDepositsAccountData.depositProductName }}"></mifosx-long-text>
</h2>
<div class="fd-hero__meta">
<span class="fd-hero__meta-item">
<span class="fd-hero__meta-label">{{ 'labels.inputs.Account Number' | translate }}</span>
<mifosx-account-number
accountNo="{{ fixedDepositsAccountData.accountNo }}"
display="left"
></mifosx-account-number>
</span>
<span class="fd-hero__meta-item">
<span class="fd-hero__meta-label">
{{ 'labels.text.' + entityType | translate }} {{ 'labels.inputs.name' | translate }}
</span>
<span class="fd-hero__meta-value">
{{ fixedDepositsAccountData.clientName || fixedDepositsAccountData.groupName }}
@if (fixedDepositsAccountData.clientAccountNo) {
<mifosx-account-number
accountNo="{{ fixedDepositsAccountData.clientAccountNo }}"
></mifosx-account-number>
}
</span>
</span>
</div> </div>
</div> </div>
</div>
<div class="mat-typography account-card-title"> <!-- Balance KPI strip -->
<mat-card-title> @if (!fixedDepositsAccountData.status.rejected && !fixedDepositsAccountData.status.submittedAndPendingApproval) {
<div class="layout-row responsive-column"> <div class="fd-hero__kpis">
<div class="flex-60"> <div class="fd-kpi">
<h3> <span class="fd-kpi__label">{{ 'labels.inputs.Current Balance' | translate }}</span>
<i <span class="fd-kpi__value">
class="fa fa-stop" {{ fixedDepositsAccountData.summary.accountBalance | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
[ngClass]="fixedDepositsAccountData.status.code | statusLookup" </span>
[matTooltip]="fixedDepositsAccountData.status.value" </div>
></i> <div class="fd-kpi fd-kpi--deposit">
{{ 'labels.inputs.Fixed Deposit Product' | translate }} : <span class="fd-kpi__label">{{ 'labels.inputs.Deposit Amount' | translate }}</span>
{{ fixedDepositsAccountData.depositProductName }} <span class="fd-kpi__value">
<mifosx-account-number accountNo="{{ fixedDepositsAccountData.accountNo }}"></mifosx-account-number> {{ fixedDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</h3> </span>
<span class="account-overview"> </div>
<span class="m-r-10">{{ 'labels.text.' + entityType | translate }} :</span>
{{ fixedDepositsAccountData.clientName || fixedDepositsAccountData.groupName }}
@if (fixedDepositsAccountData.clientAccountNo) {
<span class="m-l-10">
<mifosx-account-number
accountNo="{{ fixedDepositsAccountData.clientAccountNo }}"
></mifosx-account-number>
</span>
}
</span>
</div>
@if (
!fixedDepositsAccountData.status.rejected && !fixedDepositsAccountData.status.submittedAndPendingApproval
) {
<div class="flex-30">
<h3 class="flex-100">{{ 'labels.heading.Account Overview' | translate }}</h3>
<table class="account-overview flex-100">
<tbody>
<tr>
<td class="flex-70">{{ 'labels.inputs.Current Balance' | translate }}</td>
<td class="r-amount flex-30">
{{
fixedDepositsAccountData.summary.accountBalance
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
<tr>
<td class="flex-70">{{ 'labels.inputs.Deposit Amount' | translate }}</td>
<td class="r-amount flex-30">
{{
fixedDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
</tbody>
</table>
</div>
}
<div class="flex-5">
<button
mat-icon-button
[matMenuTriggerFor]="accountMenu"
aria-label="Fixed Deposit account actions"
yPosition="below"
>
<mat-icon matListIcon class="actions-menu">
<fa-icon icon="bars" size="sm"></fa-icon>
</mat-icon>
</button>
</div>
</div>
</mat-card-title>
</div> </div>
}
<mat-menu #accountMenu="matMenu"> <!-- Action menu (kebab) -->
@for (button of buttonConfig.singleButtons; track button) { <div class="fd-hero__actions">
<button mat-menu-item (click)="doAction(button.name)"> <button mat-icon-button [matMenuTriggerFor]="accountMenu" aria-label="Account actions" yPosition="below">
<i ngClass="{{ button.icon }}"></i> {{ button.name | translateKey: 'menus' }} <fa-icon icon="ellipsis-v"></fa-icon>
</button> </button>
} </div>
@if (buttonConfig.options.length) { <mat-menu #accountMenu="matMenu">
<button mat-menu-item [matMenuTriggerFor]="More">{{ 'More' | translateKey: 'menus' }}</button> @for (button of buttonConfig.singleButtons; track button) {
<mat-menu #More="matMenu"> <button mat-menu-item (click)="doAction(button.name)">
@for (option of buttonConfig.options; track option) { <span>{{ button.name | translateKey: 'menus' }}</span>
<span> </button>
<button mat-menu-item (click)="doAction(option.name)">{{ option.name | translateKey: 'menus' }}</button>
</span>
}
</mat-menu>
}
</mat-menu>
</mat-card-title-group>
</mat-card-header>
<mat-card-content class="content">
<nav mat-tab-nav-bar class="navigation-tabs" [tabPanel]="tabPanel">
<a
mat-tab-link
[routerLink]="['./general']"
routerLinkActive
#general="routerLinkActive"
[active]="general.isActive"
>
{{ 'labels.inputs.General' | translate }}
</a>
<a
mat-tab-link
[routerLink]="['./interest-rate-chart']"
routerLinkActive
#IRC="routerLinkActive"
[active]="IRC.isActive"
>
{{ 'labels.inputs.Interest Rate Chart' | translate }}
</a>
@if (showTransactions) {
<span>
<a
mat-tab-link
[routerLink]="['./transactions']"
routerLinkActive
#transactions="routerLinkActive"
[active]="transactions.isActive"
>
{{ 'labels.inputs.Transactions' | translate }}
</a>
</span>
} }
<a @if (buttonConfig.options.length) {
mat-tab-link <button mat-menu-item [matMenuTriggerFor]="More">{{ 'More' | translateKey: 'menus' }}</button>
[routerLink]="['./charges']" <mat-menu #More="matMenu">
routerLinkActive @for (option of buttonConfig.options; track option) {
#charges="routerLinkActive" <span>
[active]="charges.isActive" <button mat-menu-item (click)="doAction(option.name)">{{ option.name | translateKey: 'menus' }}</button>
> </span>
{{ 'labels.inputs.Charges' | translate }} }
</a> </mat-menu>
@if (fixedDepositsAccountData.clientId) {
<a
mat-tab-link
[routerLink]="['./standing-instructions']"
routerLinkActive
#standingInstructions="routerLinkActive"
[active]="standingInstructions.isActive"
>
{{ 'labels.inputs.Standing Instructions' | translate }}
</a>
} }
<a </mat-menu>
mat-tab-link </header>
[routerLink]="['./nominees']"
routerLinkActive
#nominees="routerLinkActive"
[active]="nominees.isActive"
>
Nominees
</a>
@for (savingsDatatable of savingsDatatables; track savingsDatatable) {
<a
mat-tab-link
*mifosxHasPermission="'READ_' + savingsDatatable.registeredTableName"
[routerLink]="['./datatables', savingsDatatable.registeredTableName]"
routerLinkActive
#datatable="routerLinkActive"
[active]="datatable.isActive"
>
{{ savingsDatatable.registeredTableName }}
</a>
}
</nav>
<mat-tab-nav-panel #tabPanel> <!-- ─── Pill-style tab navigation ─────────────────────────────────── -->
<nav mat-tab-nav-bar class="fd-tabs" [tabPanel]="tabPanel">
<a
mat-tab-link
class="fd-tab"
[routerLink]="['./general']"
routerLinkActive
#general="routerLinkActive"
[active]="general.isActive"
>
<fa-icon icon="info-circle" class="fd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.General' | translate }}</span>
</a>
<a
mat-tab-link
class="fd-tab"
[routerLink]="['./interest-rate-chart']"
routerLinkActive
#IRC="routerLinkActive"
[active]="IRC.isActive"
>
<fa-icon icon="chart-line" class="fd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Interest Rate Chart' | translate }}</span>
</a>
@if (showTransactions) {
<a
mat-tab-link
class="fd-tab"
[routerLink]="['./transactions']"
routerLinkActive
#transactions="routerLinkActive"
[active]="transactions.isActive"
>
<fa-icon icon="exchange-alt" class="fd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Transactions' | translate }}</span>
</a>
}
<a
mat-tab-link
class="fd-tab"
[routerLink]="['./charges']"
routerLinkActive
#charges="routerLinkActive"
[active]="charges.isActive"
>
<fa-icon icon="receipt" class="fd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Charges' | translate }}</span>
</a>
@if (fixedDepositsAccountData.clientId) {
<a
mat-tab-link
class="fd-tab"
[routerLink]="['./standing-instructions']"
routerLinkActive
#standingInstructions="routerLinkActive"
[active]="standingInstructions.isActive"
>
<fa-icon icon="calendar-check" class="fd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Standing Instructions' | translate }}</span>
</a>
}
<a
mat-tab-link
class="fd-tab"
[routerLink]="['./nominees']"
routerLinkActive
#nominees="routerLinkActive"
[active]="nominees.isActive"
>
<fa-icon icon="user-shield" class="fd-tab__ic"></fa-icon>
<span>Nominees</span>
</a>
@for (savingsDatatable of savingsDatatables; track savingsDatatable) {
<a
mat-tab-link
class="fd-tab"
*mifosxHasPermission="'READ_' + savingsDatatable.registeredTableName"
[routerLink]="['./datatables', savingsDatatable.registeredTableName]"
routerLinkActive
#datatable="routerLinkActive"
[active]="datatable.isActive"
>
<fa-icon icon="table" class="fd-tab__ic"></fa-icon>
<span>{{ savingsDatatable.registeredTableName }}</span>
</a>
}
</nav>
<mat-tab-nav-panel #tabPanel>
<div class="fd-body">
<router-outlet></router-outlet> <router-outlet></router-outlet>
</mat-tab-nav-panel> </div>
</mat-card-content> </mat-tab-nav-panel>
</mat-card> </div>
@@ -5,3 +5,381 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
$navy: #0d1b2a;
$blue: #1e88e5;
$blue-d: #1e40af;
$border: #e2e8f0;
.fd-view {
max-width: 1440px;
margin: 0 auto;
padding: 12px 20px 22px;
}
/* ─── Gradient hero header ──────────────────────────────────────────── */
.fd-hero {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
align-items: stretch;
gap: 14px;
padding: 12px 18px;
border-radius: 12px;
color: #fff;
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 45%, #4338ca 100%);
box-shadow: 0 6px 18px -10px rgb(15 23 42 / 35%);
overflow: hidden;
&::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at top right, rgb(255 255 255 / 12%) 0%, transparent 55%);
pointer-events: none;
}
&__left {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
position: relative;
z-index: 1;
}
&__avatar {
width: 40px;
height: 40px;
border-radius: 10px;
background: linear-gradient(135deg, rgb(255 255 255 / 22%) 0%, rgb(255 255 255 / 10%) 100%);
border: 1px solid rgb(255 255 255 / 28%);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 16px;
flex-shrink: 0;
box-shadow: 0 3px 10px -3px rgb(0 0 0 / 25%);
}
&__info {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 0;
}
&__status-row {
display: flex;
align-items: center;
gap: 6px;
}
&__title {
margin: 0;
font-size: 15px;
font-weight: 800;
letter-spacing: 0.01em;
color: #fff;
line-height: 1.15;
::ng-deep mifosx-long-text {
color: #fff;
}
}
&__meta {
display: flex;
flex-wrap: wrap;
gap: 2px 18px;
margin-top: 1px;
}
&__meta-item {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: rgb(255 255 255 / 90%);
}
&__meta-label {
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: rgb(255 255 255 / 60%);
font-weight: 600;
}
&__meta-value {
font-weight: 600;
color: #fff;
}
&__kpis {
display: flex;
gap: 8px;
align-items: stretch;
position: relative;
z-index: 1;
}
&__actions {
display: flex;
align-items: center;
position: relative;
z-index: 1;
button {
width: 32px !important;
height: 32px !important;
min-width: 32px !important;
padding: 0 !important;
border-radius: 50% !important;
color: #fff !important;
background: rgb(255 255 255 / 10%) !important;
border: 1px solid rgb(255 255 255 / 22%) !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
line-height: 1;
transition:
background 0.15s ease,
border-color 0.15s ease,
transform 0.12s ease;
::ng-deep fa-icon {
font-size: 14px;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
}
::ng-deep .mat-mdc-button-persistent-ripple,
::ng-deep .mat-mdc-button-touch-target {
border-radius: 50% !important;
}
}
button:hover {
background: rgb(255 255 255 / 22%) !important;
border-color: rgb(255 255 255 / 38%) !important;
}
button:active {
transform: scale(0.94);
}
}
}
/* KPI tiles */
.fd-kpi {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 130px;
padding: 7px 14px;
border-radius: 9px;
background: rgb(255 255 255 / 14%);
border: 1px solid rgb(255 255 255 / 22%);
backdrop-filter: blur(8px);
&__label {
font-size: 9.5px;
text-transform: uppercase;
letter-spacing: 0.07em;
font-weight: 700;
color: rgb(255 255 255 / 75%);
}
&__value {
margin-top: 2px;
font-size: 15px;
font-weight: 800;
color: #fff;
font-variant-numeric: tabular-nums;
letter-spacing: -0.01em;
}
&--deposit {
background: rgb(245 158 11 / 22%);
border-color: rgb(245 158 11 / 35%);
}
}
/* Status pill */
.fd-status-pill {
display: inline-flex;
align-items: center;
gap: 5px;
height: 18px;
padding: 0 8px;
border-radius: 999px;
background: rgb(16 185 129 / 24%);
border: 1px solid rgb(16 185 129 / 40%);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #d1fae5;
&__dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 0 2px rgb(16 185 129 / 30%);
}
&.statussubmitted,
&.statuspending {
background: rgb(245 158 11 / 24%);
border-color: rgb(245 158 11 / 40%);
color: #fef3c7;
.fd-status-pill__dot {
background: #f59e0b;
}
}
&.statusclosed,
&.statusrejected,
&.statuswithdrawn,
&.statusprematureclosed {
background: rgb(239 68 68 / 24%);
border-color: rgb(239 68 68 / 40%);
color: #fee2e2;
.fd-status-pill__dot {
background: #ef4444;
}
}
}
/* ─── Pill-style tab navigation ─────────────────────────────────────── */
.fd-tabs {
margin-top: 18px;
background: #fff;
border: 1px solid $border;
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;
flex-wrap: wrap;
}
.mdc-tab-indicator__content--underline,
.mat-mdc-tab-header-pagination-controls-enabled .mdc-tab-indicator__content--underline {
display: none !important;
}
}
}
.fd-tab {
display: inline-flex !important;
align-items: center;
gap: 8px;
height: 38px !important;
min-width: 0 !important;
padding: 0 16px !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: 12px;
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,
.fd-tab__ic {
color: #fff !important;
opacity: 1 !important;
}
}
}
.fd-body {
margin-top: 16px;
}
/* ─── Responsive ────────────────────────────────────────────────────── */
@media (width <= 1100px) {
.fd-hero {
grid-template-columns: 1fr;
&__kpis {
width: 100%;
flex-wrap: wrap;
}
&__actions {
position: absolute;
top: 18px;
right: 18px;
}
}
.fd-kpi {
flex: 1 1 auto;
min-width: 0;
}
}
@media (width <= 700px) {
.fd-view {
padding: 12px;
}
.fd-hero {
padding: 18px;
&__title {
font-size: 18px;
}
&__avatar {
width: 52px;
height: 52px;
font-size: 22px;
border-radius: 12px;
}
}
.fd-tab {
padding: 0 12px !important;
font-size: 12px !important;
}
}
@@ -24,17 +24,10 @@ import { FixedDepositsButtonsConfiguration } from './fixed-deposits-buttons.conf
import { FixedDepositsService } from '../fixed-deposits.service'; import { FixedDepositsService } from '../fixed-deposits.service';
import { SavingsService } from 'app/savings/savings.service'; import { SavingsService } from 'app/savings/savings.service';
import { Currency } from 'app/shared/models/general.model'; import { Currency } from 'app/shared/models/general.model';
import {
MatCard,
MatCardHeader,
MatCardTitleGroup,
MatCardMdImage,
MatCardTitle,
MatCardContent
} from '@angular/material/card';
import { MatTooltip } from '@angular/material/tooltip'; import { MatTooltip } from '@angular/material/tooltip';
import { NgClass, CurrencyPipe } from '@angular/common'; import { NgClass, CurrencyPipe } from '@angular/common';
import { AccountNumberComponent } from '../../../shared/account-number/account-number.component'; import { AccountNumberComponent } from '../../../shared/account-number/account-number.component';
import { LongTextComponent } from '../../../shared/long-text/long-text.component';
import { MatIconButton } from '@angular/material/button'; import { MatIconButton } from '@angular/material/button';
import { MatMenuTrigger, MatMenu, MatMenuItem } from '@angular/material/menu'; import { MatMenuTrigger, MatMenu, MatMenuItem } from '@angular/material/menu';
import { MatIcon } from '@angular/material/icon'; import { MatIcon } from '@angular/material/icon';
@@ -52,12 +45,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
styleUrls: ['./fixed-deposit-account-view.component.scss'], styleUrls: ['./fixed-deposit-account-view.component.scss'],
imports: [ imports: [
...STANDALONE_SHARED_IMPORTS, ...STANDALONE_SHARED_IMPORTS,
MatCardHeader,
MatCardTitleGroup,
MatCardMdImage,
MatTooltip, MatTooltip,
MatCardTitle,
NgClass, NgClass,
LongTextComponent,
AccountNumberComponent, AccountNumberComponent,
MatIconButton, MatIconButton,
MatMenuTrigger, MatMenuTrigger,
@@ -6,196 +6,211 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="fixed-deposits-account-tables layout-row gap-2percent"> <div class="gt-grid">
<div class="flex-49 layout-column gap-4percent"> <!-- ─── Left Column ──────────────────────────────────────────────── -->
<div> <div class="gt-col">
<h4 class="table-headers">{{ 'labels.heading.Fixed Deposit Details' | translate }}</h4> <!-- Fixed Deposit Details -->
<table> <div class="nx-card">
<tbody> <div class="nx-card__head">
<tr> <span class="nx-card__ico"><fa-icon icon="file-alt"></fa-icon></span>
<td>{{ 'labels.inputs.External Id' | translate }}</td> <h3 class="nx-card__title">{{ 'labels.heading.Fixed Deposit Details' | translate }}</h3>
<td> </div>
@if (fixedDepositsAccountData.externalId) { <div class="nx-card__body">
<span> <div class="nx-row">
<mifosx-external-identifier <span class="nx-row__label">{{ 'labels.inputs.External Id' | translate }}</span>
externalId="{{ fixedDepositsAccountData.externalId }}" <span class="nx-row__value">
completed="true" @if (fixedDepositsAccountData.externalId) {
></mifosx-external-identifier> <mifosx-external-identifier
</span> externalId="{{ fixedDepositsAccountData.externalId }}"
} completed="true"
@if (!fixedDepositsAccountData.externalId) { ></mifosx-external-identifier>
<span> } @else {
{{ 'labels.inputs.Not Available' | translate }} <span class="nx-muted">{{ 'labels.inputs.Not Available' | translate }}</span>
</span> }
} </span>
</td> </div>
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Activated On' | translate }}</span>
<td>{{ 'labels.inputs.Activated On' | translate }}</td> <span class="nx-row__value">
<td> {{
{{ fixedDepositsAccountData.timeline.activatedOnDate
fixedDepositsAccountData.timeline.activatedOnDate ? (fixedDepositsAccountData.timeline.activatedOnDate | dateFormat)
? (fixedDepositsAccountData.timeline.activatedOnDate | dateFormat) : ('labels.text.Not Activated' | translate)
: ('labels.text.Not Activated' | translate) }}
}} </span>
</td> </div>
</tr> @if (fixedDepositsAccountData.timeline.closedOnDate) {
@if (fixedDepositsAccountData.timeline.closedOnDate) { <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Closed On' | translate }}</span>
<td>{{ 'labels.inputs.Closed On' | translate }}</td> <span class="nx-row__value">{{ fixedDepositsAccountData.timeline.closedOnDate | dateFormat }}</span>
<td>{{ fixedDepositsAccountData.timeline.closedOnDate | dateFormat }}</td> </div>
</tr> }
} <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Field Officer' | translate }}</span>
<td>{{ 'labels.inputs.Field Officer' | translate }}</td> <span class="nx-row__value">
<td> {{
{{ fixedDepositsAccountData.fieldOfficerName
fixedDepositsAccountData.fieldOfficerName ? fixedDepositsAccountData.fieldOfficerName
? fixedDepositsAccountData.fieldOfficerName : ('Unassigned' | translateKey: 'inputs')
: ('Unassigned' | translateKey: 'inputs') }}
}} </span>
</td> </div>
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Maturity Date' | translate }}</span>
<td>{{ 'labels.inputs.Maturity Date' | translate }}</td> <span class="nx-row__value">
<td> {{ fixedDepositsAccountData.maturityDate ? (fixedDepositsAccountData.maturityDate | dateFormat) : 'N/A' }}
{{ fixedDepositsAccountData.maturityDate ? (fixedDepositsAccountData.maturityDate | dateFormat) : 'N/A' }} </span>
</td> </div>
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Deposit Period' | translate }}</span>
<td>{{ 'labels.inputs.Deposit Period' | translate }}</td> <span class="nx-row__value">
<td> {{ fixedDepositsAccountData.depositPeriod }}&nbsp;{{
{{ fixedDepositsAccountData.depositPeriod }}&nbsp;{{ fixedDepositsAccountData.depositPeriodFrequency.value | translateKey: 'catalogs'
fixedDepositsAccountData.depositPeriodFrequency.value | translateKey: 'catalogs' }}
}} </span>
</td> </div>
</tr> @if (fixedDepositsAccountData.withHoldTax) {
@if (fixedDepositsAccountData.withHoldTax) { <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Tax Group' | translate }}</span>
<td>{{ 'labels.inputs.Tax Group' | translate }}</td> <span class="nx-row__value">{{ fixedDepositsAccountData.taxGroup.name }}</span>
<td>{{ fixedDepositsAccountData.taxGroup.name }}</td> </div>
</tr> }
} @if (fixedDepositsAccountData.onAccountClosure) {
@if (fixedDepositsAccountData.onAccountClosure) { <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Maturity Instructions' | translate }}</span>
<td>{{ 'labels.inputs.Maturity Instructions' | translate }}</td> <span class="nx-row__value">{{
<td>{{ fixedDepositsAccountData.onAccountClosure.value | translateKey: 'catalogs' }}</td> fixedDepositsAccountData.onAccountClosure.value | translateKey: 'catalogs'
</tr> }}</span>
} </div>
</tbody> }
</table> </div>
</div> </div>
<div> <!-- Interest Details -->
<h4 class="table-headers">{{ 'labels.heading.Interest Details' | translate }}</h4> <div class="nx-card">
<table> <div class="nx-card__head">
<tbody> <span class="nx-card__ico"><fa-icon icon="percentage"></fa-icon></span>
<tr> <h3 class="nx-card__title">{{ 'labels.heading.Interest Details' | translate }}</h3>
<td>{{ 'labels.inputs.Interest Rate' | translate }}</td> </div>
<td>{{ fixedDepositsAccountData.nominalAnnualInterestRate }} %</td> <div class="nx-card__body">
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Interest Rate' | translate }}</span>
<td>{{ 'labels.inputs.Interest Compounding Period' | translate }}</td> <span class="nx-row__value">{{ fixedDepositsAccountData.nominalAnnualInterestRate }} %</span>
<td>{{ fixedDepositsAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs' }}</td> </div>
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Interest Compounding Period' | translate }}</span>
<td>{{ 'labels.inputs.Interest Posting Period' | translate }}</td> <span class="nx-row__value">{{
<td>{{ fixedDepositsAccountData.interestPostingPeriodType.value | translateKey: 'catalogs' }}</td> fixedDepositsAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs'
</tr> }}</span>
<tr> </div>
<td>{{ 'labels.inputs.Interest Calculated Using' | translate }}</td> <div class="nx-row">
<td>{{ fixedDepositsAccountData.interestCalculationType.value | translateKey: 'catalogs' }}</td> <span class="nx-row__label">{{ 'labels.inputs.Interest Posting Period' | translate }}</span>
</tr> <span class="nx-row__value">{{
<tr> fixedDepositsAccountData.interestPostingPeriodType.value | translateKey: 'catalogs'
<td>{{ 'labels.inputs.No. of Days in Year' | translate }}</td> }}</span>
<td>{{ fixedDepositsAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs' }}</td> </div>
</tr> <div class="nx-row">
@if (fixedDepositsAccountData.preClosurePenalApplicable) { <span class="nx-row__label">{{ 'labels.inputs.Interest Calculated Using' | translate }}</span>
<tr> <span class="nx-row__value">{{
<td>{{ 'labels.inputs.Pre-cloure Penal' | translate }}</td> fixedDepositsAccountData.interestCalculationType.value | translateKey: 'catalogs'
<td> }}</span>
{{ fixedDepositsAccountData.preClosurePenalInterest }} % on </div>
{{ fixedDepositsAccountData.preClosurePenalInterestOnType.value | translateKey: 'catalogs' }} <div class="nx-row">
</td> <span class="nx-row__label">{{ 'labels.inputs.No. of Days in Year' | translate }}</span>
</tr> <span class="nx-row__value">{{
} fixedDepositsAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs'
</tbody> }}</span>
</table> </div>
@if (fixedDepositsAccountData.preClosurePenalApplicable) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Pre-cloure Penal' | translate }}</span>
<span class="nx-row__value">
{{ fixedDepositsAccountData.preClosurePenalInterest }} % on
{{ fixedDepositsAccountData.preClosurePenalInterestOnType.value | translateKey: 'catalogs' }}
</span>
</div>
}
</div>
</div> </div>
</div> </div>
<div class="flex-49"> <!-- ─── Right Column ─────────────────────────────────────────────── -->
<div class="gt-col">
@if (!fixedDepositsAccountData.status.rejected && !fixedDepositsAccountData.status.submittedAndPendingApproval) { @if (!fixedDepositsAccountData.status.rejected && !fixedDepositsAccountData.status.submittedAndPendingApproval) {
<div> <!-- Performance History -->
<h4 class="table-headers">{{ 'labels.heading.Performance History' | translate }}</h4> <div class="nx-card">
<table> <div class="nx-card__head">
<tbody> <span class="nx-card__ico"><fa-icon icon="chart-bar"></fa-icon></span>
<tr> <h3 class="nx-card__title">{{ 'labels.heading.Performance History' | translate }}</h3>
<td>{{ 'labels.inputs.Principal Amount' | translate }}</td> </div>
<td class="r-amount"> <div class="nx-card__body">
{{ fixedDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }} <div class="nx-row">
</td> <span class="nx-row__label">{{ 'labels.inputs.Principal Amount' | translate }}</span>
</tr> <span class="nx-row__value nx-row__value--amount">
<tr> {{ fixedDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
<td>{{ 'labels.inputs.Maturity Amount' | translate }}</td> </span>
<td class="r-amount"> </div>
{{ fixedDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }} <div class="nx-row">
</td> <span class="nx-row__label">{{ 'labels.inputs.Maturity Amount' | translate }}</span>
</tr> <span class="nx-row__value nx-row__value--amount nx-row__value--positive">
@if (fixedDepositsAccountData.summary.totalDeposits) { {{ fixedDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
<tr> </span>
<td>{{ 'labels.inputs.Total Deposits' | translate }}</td> </div>
<td class="r-amount"> @if (fixedDepositsAccountData.summary.totalDeposits) {
{{ <div class="nx-row">
fixedDepositsAccountData.summary.totalDeposits | currency: currency.code : 'symbol-narrow' : '1.2-2' <span class="nx-row__label">{{ 'labels.inputs.Total Deposits' | translate }}</span>
}} <span class="nx-row__value nx-row__value--amount">
</td> {{
</tr> fixedDepositsAccountData.summary.totalDeposits | currency: currency.code : 'symbol-narrow' : '1.2-2'
} }}
@if (fixedDepositsAccountData.summary.totalWithdrawals) { </span>
<tr> </div>
<td>{{ 'labels.inputs.Total Withdrawals' | translate }}</td> }
<td class="r-amount"> @if (fixedDepositsAccountData.summary.totalWithdrawals) {
{{ <div class="nx-row">
fixedDepositsAccountData.summary.totalWithdrawals <span class="nx-row__label">{{ 'labels.inputs.Total Withdrawals' | translate }}</span>
| currency: currency.code : 'symbol-narrow' : '1.2-2' <span class="nx-row__value nx-row__value--amount nx-row__value--negative">
}} {{
</td> fixedDepositsAccountData.summary.totalWithdrawals
</tr> | currency: currency.code : 'symbol-narrow' : '1.2-2'
} }}
@if (fixedDepositsAccountData.summary.totalInterestEarned >= 0) { </span>
<tr> </div>
<td>{{ 'labels.inputs.Total Interest Earned' | translate }}</td> }
<td class="r-amount"> @if (fixedDepositsAccountData.summary.totalInterestEarned >= 0) {
{{ <div class="nx-row">
fixedDepositsAccountData.summary.totalInterestEarned <span class="nx-row__label">{{ 'labels.inputs.Total Interest Earned' | translate }}</span>
| currency: currency.code : 'symbol-narrow' : '1.2-2' <span class="nx-row__value nx-row__value--amount nx-row__value--positive">
}} {{
</td> fixedDepositsAccountData.summary.totalInterestEarned
</tr> | currency: currency.code : 'symbol-narrow' : '1.2-2'
} }}
</tbody> </span>
</table> </div>
}
</div>
</div> </div>
} @else { } @else {
<div> <!-- Other Details (pending/rejected) -->
<h4 class="table-headers">{{ 'labels.heading.Other Details' | translate }}</h4> <div class="nx-card">
<table> <div class="nx-card__head">
<tbody> <span class="nx-card__ico"><fa-icon icon="info-circle"></fa-icon></span>
<tr> <h3 class="nx-card__title">{{ 'labels.heading.Other Details' | translate }}</h3>
<td>{{ 'labels.inputs.Principal Amount' | translate }}</td> </div>
<td class="r-amount"> <div class="nx-card__body">
{{ fixedDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }} <div class="nx-row">
</td> <span class="nx-row__label">{{ 'labels.inputs.Principal Amount' | translate }}</span>
</tr> <span class="nx-row__value nx-row__value--amount">
<tr> {{ fixedDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
<td>{{ 'labels.inputs.Maturity Amount' | translate }}</td> </span>
<td class="r-amount"> </div>
{{ fixedDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }} <div class="nx-row">
</td> <span class="nx-row__label">{{ 'labels.inputs.Maturity Amount' | translate }}</span>
</tr> <span class="nx-row__value nx-row__value--amount">
</tbody> {{ fixedDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</table> </span>
</div>
</div>
</div> </div>
} }
</div> </div>
@@ -6,6 +6,115 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
.fixed-deposits-account-tables { $navy: #0d1b2a;
padding: 1%; $slate: #475569;
$muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
/* ─── Two-column grid ───────────────────────────────────────────────── */
.gt-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 16px;
@media (width <= 1024px) {
grid-template-columns: 1fr;
}
}
.gt-col {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 0;
}
/* ─── Nexora section 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: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
}
&__ico {
width: 26px;
height: 26px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
color: #fff;
font-size: 12px;
}
&__title {
margin: 0;
font-size: 13.5px;
font-weight: 700;
color: $navy;
letter-spacing: 0.01em;
}
&__body {
padding: 4px 18px 10px;
}
}
/* ─── Key/Value row ─────────────────────────────────────────────────── */
.nx-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
min-height: 38px;
padding: 8px 0;
border-bottom: 1px dashed #eef2f7;
font-size: 13px;
&:last-child {
border-bottom: none;
}
&__label {
color: $slate;
font-weight: 500;
}
&__value {
color: $navy;
font-weight: 600;
text-align: right;
word-break: break-word;
&--amount {
font-variant-numeric: tabular-nums;
font-weight: 700;
}
&--positive {
color: #047857;
}
&--negative {
color: #b91c1c;
}
}
}
.nx-muted {
color: $muted;
font-weight: 500;
font-style: italic;
} }
@@ -12,6 +12,7 @@ import { Currency } from 'app/shared/models/general.model';
import { CurrencyPipe } from '@angular/common'; import { CurrencyPipe } from '@angular/common';
import { ExternalIdentifierComponent } from '../../../../shared/external-identifier/external-identifier.component'; import { ExternalIdentifierComponent } from '../../../../shared/external-identifier/external-identifier.component';
import { DateFormatPipe } from '../../../../pipes/date-format.pipe'; import { DateFormatPipe } from '../../../../pipes/date-format.pipe';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@Component({ @Component({
@@ -21,6 +22,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
imports: [ imports: [
...STANDALONE_SHARED_IMPORTS, ...STANDALONE_SHARED_IMPORTS,
ExternalIdentifierComponent, ExternalIdentifierComponent,
FaIconComponent,
CurrencyPipe, CurrencyPipe,
DateFormatPipe DateFormatPipe
] ]
@@ -6,23 +6,19 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="tab-container mat-typography"> <div class="txn-tab">
<div class="mat-elevation-z1 m-b-25"> <div class="txn-tab__card">
<div class="layout-row align-start"> @if (checkStatus()) {
<div class="m-b-20"> <div class="txn-tab__toolbar">
<h3>{{ 'labels.heading.All Transactions' | translate }}</h3> <mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="txn-tab__check">
{{ 'labels.inputs.Hide Reversed' | translate }}
</mat-checkbox>
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="txn-tab__check">
{{ 'labels.inputs.Hide Accruals' | translate }}
</mat-checkbox>
<span class="txn-tab__spacer"></span>
</div> </div>
@if (checkStatus()) { }
<div class="action-button m-b-20 layout-row gap-20px">
<mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="accruals">
{{ 'labels.inputs.Hide Reversed' | translate }}</mat-checkbox
>
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="accruals">
{{ 'labels.inputs.Hide Accruals' | translate }}</mat-checkbox
>
</div>
}
</div>
<table mat-table [dataSource]="dataSource"> <table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="row"> <ng-container matColumnDef="row">
@@ -105,7 +101,7 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th> <th mat-header-cell class="center" *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell class="center" *matCellDef="let transaction; let idx = index"> <td mat-cell class="center" *matCellDef="let transaction; let idx = index">
<button mat-icon-button [matMenuTriggerFor]="transactionMenu" aria-label="" class="action-button"> <button mat-icon-button [matMenuTriggerFor]="transactionMenu" aria-label="" class="action-button">
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
@@ -6,48 +6,95 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
@use 'assets/styles/helper'; $navy: #0d1b2a;
@use 'assets/styles/colours' as *; $slate: #475569;
$muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
$blue: #1e40af;
.tab-container { .txn-tab {
padding: 1%; width: 100%;
margin: 1%;
h3 {
margin: 1% auto;
}
.action-button {
margin-left: auto;
}
table {
width: 100%;
color: $black;
.account-action-button {
min-width: 26px;
padding: 0 0 3px;
margin: 0 2%;
line-height: 25px;
}
.strike {
text-decoration: line-through;
color: $status-active-overdue;
}
.linked {
color: $status-approved;
}
.accrual {
color: $msg-default;
}
}
} }
.select-row:hover { .txn-tab__card {
cursor: pointer; background: #fff;
font-weight: 800; border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
overflow: hidden;
}
.txn-tab__toolbar {
display: flex;
align-items: center;
gap: 18px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
flex-wrap: wrap;
}
.txn-tab__check {
font-size: 13px;
color: $slate;
font-weight: 500;
}
.txn-tab__spacer {
flex: 1;
}
table {
width: 100%;
}
::ng-deep .txn-tab__card {
.mat-mdc-header-row {
background: $soft;
}
.mat-mdc-header-cell {
font-size: 11.5px;
font-weight: 800;
color: $slate;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 14px;
border-bottom: 1px solid $border;
}
.mat-mdc-cell {
font-size: 13px;
color: $navy;
padding: 11px 14px;
border-bottom: 1px solid #f1f5f9;
}
.mat-mdc-row:hover {
background: #f8fafc;
cursor: pointer;
}
.mat-column-debit,
.mat-column-credit,
.mat-column-balance {
text-align: right;
font-variant-numeric: tabular-nums;
}
.mat-column-actions {
text-align: center;
width: 80px;
}
.strike td {
text-decoration: line-through;
color: $muted;
}
.accrual td {
color: $muted;
font-style: italic;
}
} }
@@ -6,14 +6,13 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="tab-container mat-typography"> <div class="chg-tab">
<div class="layout-row align-start"> <div class="chg-tab__card">
<div class="m-b-10"> <div class="chg-tab__toolbar">
<h3>{{ 'labels.heading.All Charges' | translate }}</h3> <h3 class="chg-tab__title">{{ 'labels.heading.All Charges' | translate }}</h3>
<span class="chg-tab__spacer"></span>
</div> </div>
</div>
<div class="mat-elevation-z1 m-b-25">
<table mat-table #chargesTable [dataSource]="dataSource"> <table mat-table #chargesTable [dataSource]="dataSource">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th> <th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
@@ -6,26 +6,96 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
.tab-container { $navy: #0d1b2a;
padding: 1%; $slate: #475569;
margin: 1%; $muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
$blue: #1e40af;
h3 { .chg-tab {
margin: 1% auto; width: 100%;
}
.chg-tab__card {
background: #fff;
border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
overflow: hidden;
}
.chg-tab__toolbar {
display: flex;
align-items: center;
gap: 14px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
}
.chg-tab__title {
margin: 0;
font-size: 14px;
font-weight: 700;
color: $navy;
letter-spacing: 0.01em;
}
.chg-tab__spacer {
flex: 1;
}
table {
width: 100%;
}
::ng-deep .chg-tab__card {
.mat-mdc-header-row {
background: $soft;
} }
.action-button { .mat-mdc-header-cell {
margin-left: auto; font-size: 11.5px;
font-weight: 800;
color: $slate;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 14px;
border-bottom: 1px solid $border;
} }
table { .mat-mdc-cell {
width: 100%; font-size: 13px;
color: $navy;
padding: 11px 14px;
border-bottom: 1px solid #f1f5f9;
}
.mat-mdc-row:hover {
background: #f8fafc;
cursor: pointer;
}
.mat-column-due,
.mat-column-paid,
.mat-column-waived,
.mat-column-outstanding {
text-align: right;
font-variant-numeric: tabular-nums;
}
.mat-column-actions {
text-align: center;
width: 140px;
.account-action-button { .account-action-button {
min-width: 26px; min-width: 30px !important;
padding: 0 6px; padding: 0 8px !important;
margin: 4px; margin: 0 3px !important;
line-height: 25px; height: 30px !important;
line-height: 30px !important;
border-radius: 7px !important;
} }
} }
} }
@@ -6,503 +6,442 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="recurring-deposits-account-tables layout-row gap-2percent"> <div class="gt-grid">
@if ( <!-- ─── Left Column ──────────────────────────────────────────────── -->
!recurringDepositsAccountData.status.rejected && !recurringDepositsAccountData.status.submittedAndPendingApproval <div class="gt-col">
) { @if (
<div class="flex-49"> !recurringDepositsAccountData.status.rejected && !recurringDepositsAccountData.status.submittedAndPendingApproval
<h4 class="table-headers">{{ 'labels.inputs.Account Details' | translate }}</h4> ) {
<table> <!-- ACTIVE: Account Details -->
<tbody> <div class="nx-card">
<tr> <div class="nx-card__head">
<td>{{ 'labels.inputs.External Id' | translate }}</td> <span class="nx-card__ico"><fa-icon icon="file-alt"></fa-icon></span>
<td> <h3 class="nx-card__title">{{ 'labels.inputs.Account Details' | translate }}</h3>
</div>
<div class="nx-card__body">
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.External Id' | translate }}</span>
<span class="nx-row__value">
@if (recurringDepositsAccountData.externalId) { @if (recurringDepositsAccountData.externalId) {
<span> <mifosx-external-identifier
<mifosx-external-identifier externalId="{{ recurringDepositsAccountData.externalId }}"
externalId="{{ recurringDepositsAccountData.externalId }}" completed="true"
completed="true" ></mifosx-external-identifier>
></mifosx-external-identifier> } @else {
</span> <span class="nx-muted">{{ 'labels.inputs.Not Available' | translate }}</span>
} }
@if (!recurringDepositsAccountData.externalId) { </span>
<span> </div>
{{ 'labels.inputs.Not Available' | translate }} <div class="nx-row">
</span> <span class="nx-row__label">{{ 'labels.inputs.Field Officer' | translate }}</span>
<span class="nx-row__value">
@if (recurringDepositsAccountData.fieldOfficerName) {
{{ recurringDepositsAccountData.fieldOfficerName }}
} @else {
<span class="nx-muted">{{ 'labels.inputs.Unassigned' | translate }}</span>
} }
</td> </span>
</tr> </div>
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Field Officer' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Activation date' | translate }}</span>
<td> <span class="nx-row__value">{{ recurringDepositsAccountData.timeline.activatedOnDate | dateFormat }}</span>
{{ recurringDepositsAccountData.fieldOfficerName }} </div>
@if (!recurringDepositsAccountData.fieldOfficerName) { <div class="nx-row">
<span>{{ 'labels.inputs.Unassigned' | translate }}</span> <span class="nx-row__label">{{ 'labels.inputs.Maturity Date' | translate }}</span>
} <span class="nx-row__value">{{ recurringDepositsAccountData.maturityDate | dateFormat }}</span>
</td> </div>
</tr>
<tr>
<td>{{ 'labels.inputs.Activation date' | translate }}</td>
<td>{{ recurringDepositsAccountData.timeline.activatedOnDate | dateFormat }}</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Maturity Date' | translate }}</td>
<td>
<span>{{ recurringDepositsAccountData.maturityDate | dateFormat }}</span>
</td>
</tr>
@if ( @if (
recurringDepositsAccountData.timeline.closedOnDate || recurringDepositsAccountData.summary.totalWitddrawals recurringDepositsAccountData.timeline.closedOnDate || recurringDepositsAccountData.summary.totalWitddrawals
) { ) {
<tr> <div class="nx-row">
@if (recurringDepositsAccountData.timeline.closedOnDate) { <span class="nx-row__label">{{ 'labels.inputs.Closed on Date' | translate }}</span>
<td> <span class="nx-row__value">{{ recurringDepositsAccountData.timeline.closedOnDate | dateFormat }}</span>
{{ 'labels.inputs.Closed on Date' | translate }} </div>
</td>
}
<td>
<span>{{ recurringDepositsAccountData.timeline.closedOnDate | dateFormat }}</span>
</td>
</tr>
} }
<tr></tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Deposit Frequency' | translate }}</span>
<td>{{ 'labels.inputs.Deposit Frequency' | translate }}</td> <span class="nx-row__value">
<td>
<span class="m-r-5">{{ recurringDepositsAccountData.recurringFrequency }}</span> <span class="m-r-5">{{ recurringDepositsAccountData.recurringFrequency }}</span>
{{ recurringDepositsAccountData.recurringFrequencyType.value | translateKey: 'catalogs' }} {{ recurringDepositsAccountData.recurringFrequencyType.value | translateKey: 'catalogs' }}
</td> </span>
</tr> </div>
@if (recurringDepositsAccountData.minBalanceForInterestCalculation) { @if (recurringDepositsAccountData.minBalanceForInterestCalculation) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Balance Required for Interest Calculation' | translate }}</td> <span class="nx-row__label">{{
<td> 'labels.inputs.Balance Required for Interest Calculation' | translate
<span>{{ recurringDepositsAccountData.minBalanceForInterestCalculation }}</span> }}</span>
</td> <span class="nx-row__value">{{ recurringDepositsAccountData.minBalanceForInterestCalculation }}</span>
</tr> </div>
} }
@if (recurringDepositsAccountData.witdHoldTax) { @if (recurringDepositsAccountData.witdHoldTax) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Witdhold Tax Group' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Witdhold Tax Group' | translate }}</span>
<td> <span class="nx-row__value">{{ recurringDepositsAccountData.taxGroup.name }}</span>
<span>{{ recurringDepositsAccountData.taxGroup.name }}</span> </div>
</td>
</tr>
} }
</tbody> </div>
</table> </div>
</div>
}
@if ( <!-- ACTIVE: Interest Details -->
!recurringDepositsAccountData.status.rejected && !recurringDepositsAccountData.status.submittedAndPendingApproval <div class="nx-card">
) { <div class="nx-card__head">
<div class="flex-49"> <span class="nx-card__ico"><fa-icon icon="percentage"></fa-icon></span>
<h4 class="table-headers">{{ 'labels.heading.Performance History' | translate }}</h4> <h3 class="nx-card__title">{{ 'labels.heading.Interest Details' | translate }}</h3>
<table> </div>
<tbody> <div class="nx-card__body">
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Principal Amount' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Interest Rate' | translate }}</span>
<td class="r-amount"> <span class="nx-row__value"
<span>{{ >{{ recurringDepositsAccountData.nominalAnnualInterestRate | formatNumber }} %</span
recurringDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' >
}}</span> </div>
</td> <div class="nx-row">
</tr> <span class="nx-row__label">{{ 'labels.inputs.Interest Compounding Period' | translate }}</span>
<tr> <span class="nx-row__value">{{
<td>{{ 'labels.inputs.Maturity Amount' | translate }}</td> recurringDepositsAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs'
<td class="r-amount"> }}</span>
<span>{{ </div>
recurringDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' <div class="nx-row">
}}</span> <span class="nx-row__label">{{ 'labels.inputs.Interest Posting Period' | translate }}</span>
</td> <span class="nx-row__value">{{
</tr> recurringDepositsAccountData.interestPostingPeriodType.value | translateKey: 'catalogs'
<tr> }}</span>
<td>{{ 'labels.inputs.Recurring Deposit Amount' | translate }}</td> </div>
<td class="r-amount"> <div class="nx-row">
<span>{{ <span class="nx-row__label">{{ 'labels.inputs.Interest calculated using' | translate }}</span>
recurringDepositsAccountData?.mandatoryRecommendedDepositAmount <span class="nx-row__value">{{
| currency: currency.code : 'symbol-narrow' : '1.2-2' recurringDepositsAccountData.interestCalculationType.value | translateKey: 'catalogs'
}}</span> }}</span>
</td> </div>
</tr> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Days in Year' | translate }}</span>
<td>{{ 'labels.inputs.Deposits till Date' | translate }}</td> <span class="nx-row__value">{{
<td class="r-amount"> recurringDepositsAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs'
@if (recurringDepositsAccountData.summary.totalDeposits) { }}</span>
<span>{{ </div>
recurringDepositsAccountData.summary.totalDeposits @if (recurringDepositsAccountData.preClosurePenalApplicable) {
| currency: currency.code : 'symbol-narrow' : '1.2-2' <div class="nx-row">
}}</span> <span class="nx-row__label">{{ 'labels.inputs.Pre-closure penal Interest (less)' | translate }}</span>
} <span class="nx-row__value">
@if (!recurringDepositsAccountData.summary.totalDeposits) { {{ recurringDepositsAccountData.preClosurePenalInterest }} % on
<span>{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span> {{ recurringDepositsAccountData.preClosurePenalInterestOnType.value | translateKey: 'catalogs' }}
} </span>
</td> </div>
</tr>
<tr>
<td>{{ 'labels.inputs.Withdrwals till Date' | translate }}</td>
<td class="r-amount">
@if (recurringDepositsAccountData.summary.totalWithdrawals) {
<span>{{
recurringDepositsAccountData.summary.totalWithdrawals
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</span>
}
@if (!recurringDepositsAccountData.summary.totalWithdrawals) {
<span>{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span>
}
</td>
</tr>
@if (recurringDepositsAccountData.summary.totalInterestEarned >= 0) {
<tr>
<td>{{ 'labels.inputs.Interest Earned' | translate }}</td>
<td class="r-amount">
<span>{{
recurringDepositsAccountData.summary.totalInterestEarned
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</span>
</td>
</tr>
} }
</tbody> </div>
</table> </div>
</div> } @else {
} <!-- PENDING/REJECTED: Account Details -->
<div class="nx-card">
@if ( <div class="nx-card__head">
recurringDepositsAccountData.status.rejected || recurringDepositsAccountData.status.submittedAndPendingApproval <span class="nx-card__ico"><fa-icon icon="file-alt"></fa-icon></span>
) { <h3 class="nx-card__title">{{ 'labels.inputs.Account Details' | translate }}</h3>
<div class="flex-49"> </div>
<table> <div class="nx-card__body">
<tbody> <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.External Id' | translate }}</span>
<td>{{ 'labels.inputs.External Id' | translate }}</td> <span class="nx-row__value">
<td>
@if (recurringDepositsAccountData.externalId) { @if (recurringDepositsAccountData.externalId) {
<span> <mifosx-external-identifier
<mifosx-external-identifier externalId="{{ recurringDepositsAccountData.externalId }}"
externalId="{{ recurringDepositsAccountData.externalId }}" completed="true"
completed="true" ></mifosx-external-identifier>
></mifosx-external-identifier> } @else {
</span> <span class="nx-muted">{{ 'labels.inputs.Not Available' | translate }}</span>
} }
@if (!recurringDepositsAccountData.externalId) { </span>
<span> </div>
{{ 'labels.inputs.Not Available' | translate }} <div class="nx-row">
</span> <span class="nx-row__label">{{ 'labels.inputs.Date of Deposit' | translate }}</span>
} <span class="nx-row__value">
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Date of Deposit' | translate }}</td>
<td>
@if (!recurringDepositsAccountData.expectedFirstDepositOnDate) { @if (!recurringDepositsAccountData.expectedFirstDepositOnDate) {
<span {{ recurringDepositsAccountData.timeline.activatedOnDate | dateFormat }}
>{{ recurringDepositsAccountData.timeline.activatedOnDate | dateFormat }} @if (!recurringDepositsAccountData.timeline.activatedOnDate) {
@if (!recurringDepositsAccountData.timeline.activatedOnDate) { <span class="nx-muted">{{ 'labels.inputs.Not Activated' | translate }}</span>
<span>{{ 'labels.inputs.Not Activated' | translate }}</span> }
} } @else {
</span> {{ recurringDepositsAccountData.expectedFirstDepositOnDate | dateFormat }}
} }
@if (recurringDepositsAccountData.expectedFirstDepositOnDate) { </span>
<span </div>
>{{ recurringDepositsAccountData.expectedFirstDepositOnDate | dateFormat }} <div class="nx-row">
@if (!recurringDepositsAccountData.expectedFirstDepositOnDate) { <span class="nx-row__label">{{ 'labels.inputs.Period' | translate }}</span>
<span>{{ 'labels.inputs.Not Activated' | translate }}</span> <span class="nx-row__value">
} {{ recurringDepositsAccountData.depositPeriod }}&nbsp;{{
</span> recurringDepositsAccountData.depositPeriodFrequency.value
} }}
</td> </span>
</tr> </div>
<tr>
<td>{{ 'labels.inputs.Period' | translate }}</td>
<td>
<span
>{{ recurringDepositsAccountData.depositPeriod }}&nbsp;{{
recurringDepositsAccountData.depositPeriodFrequency.value
}}</span
>
</td>
</tr>
@if (recurringDepositsAccountData.maturityDate) { @if (recurringDepositsAccountData.maturityDate) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Maturity Date' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Maturity Date' | translate }}</span>
<td> <span class="nx-row__value">{{ recurringDepositsAccountData.maturityDate | dateFormat }}</span>
<span>{{ recurringDepositsAccountData.maturityDate | dateFormat }}</span> </div>
</td>
</tr>
} }
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Total Deposits' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Total Deposits' | translate }}</span>
<td class="r-amount"> <span class="nx-row__value nx-row__value--amount">
@if (recurringDepositsAccountData.summary.totalDeposits) { @if (recurringDepositsAccountData.summary.totalDeposits) {
<span>{{ {{
recurringDepositsAccountData.summary.totalDeposits recurringDepositsAccountData.summary.totalDeposits
| currency: currency.code : 'symbol-narrow' : '1.2-2' | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</span> }}
} @else {
{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
} }
@if (!recurringDepositsAccountData.summary.totalDeposits) { </span>
<span>{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span> </div>
} <div class="nx-row">
</td> <span class="nx-row__label">{{ 'labels.inputs.Actual Available Balance' | translate }}</span>
</tr> <span class="nx-row__value nx-row__value--amount">
<tr>
<td>{{ 'labels.inputs.Actual Available Balance' | translate }}</td>
<td class="r-amount">
{{ {{
recurringDepositsAccountData.summary.accountBalance recurringDepositsAccountData.summary.accountBalance
| currency: currency.code : 'symbol-narrow' : '1.2-2' | currency: currency.code : 'symbol-narrow' : '1.2-2'
}} }}
</td> </span>
</tr> </div>
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Recurring Deposit Amount' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Recurring Deposit Amount' | translate }}</span>
<td class="r-amount"> <span class="nx-row__value nx-row__value--amount">
{{ {{
recurringDepositsAccountData.mandatoryRecommendedDepositAmount recurringDepositsAccountData.mandatoryRecommendedDepositAmount
| currency: currency.code : 'symbol-narrow' : '1.2-2' | currency: currency.code : 'symbol-narrow' : '1.2-2'
}} }}
</td> </span>
</tr> </div>
@if (recurringDepositsAccountData.summary.totalInterestEarned) { @if (recurringDepositsAccountData.summary.totalInterestEarned) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Interests Earned' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Interests Earned' | translate }}</span>
<td> <span class="nx-row__value nx-row__value--amount">
<span {{ recurringDepositsAccountData.currency.displaySymbol }}&nbsp;{{
>{{ recurringDepositsAccountData.currency.displaySymbol }}&nbsp;{{ recurringDepositsAccountData.summary.totalInterestEarned
recurringDepositsAccountData.summary.totalInterestEarned }}
}}</span </span>
> </div>
</td>
</tr>
} }
@if (recurringDepositsAccountData.summary.totalWithdrawals) { @if (recurringDepositsAccountData.summary.totalWithdrawals) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Total Withdrawls' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Total Withdrawls' | translate }}</span>
<td class="r-amount"> <span class="nx-row__value nx-row__value--amount">
<span>{{ {{
recurringDepositsAccountData.summary.totalWithdrawals recurringDepositsAccountData.summary.totalWithdrawals
| currency: currency.code : 'symbol-narrow' : '1.2-2' | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</span> }}
</td> </span>
</tr> </div>
} }
@if (recurringDepositsAccountData.minBalanceForInterestCalculation) { @if (recurringDepositsAccountData.minBalanceForInterestCalculation) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Balance Required for Interest Calculation' | translate }}</td> <span class="nx-row__label">{{
<td class="r-amount"> 'labels.inputs.Balance Required for Interest Calculation' | translate
<span>{{ recurringDepositsAccountData.minBalanceForInterestCalculation | number }}</span> }}</span>
</td> <span class="nx-row__value">{{
</tr> recurringDepositsAccountData.minBalanceForInterestCalculation | number
}}</span>
</div>
} }
</tbody> </div>
</table> </div>
</div>
}
@if ( <!-- PENDING/REJECTED: Interest Details -->
recurringDepositsAccountData.status.rejected || recurringDepositsAccountData.status.submittedAndPendingApproval <div class="nx-card">
) { <div class="nx-card__head">
<div class="flex-49"> <span class="nx-card__ico"><fa-icon icon="percentage"></fa-icon></span>
<table> <h3 class="nx-card__title">{{ 'labels.heading.Interest Details' | translate }}</h3>
<tbody> </div>
<tr> <div class="nx-card__body">
<td>{{ 'labels.inputs.Principal Amount' | translate }}</td> <div class="nx-row">
<td class="r-amount"> <span class="nx-row__label">{{ 'labels.inputs.Interest Compounding Period' | translate }}</span>
@if (recurringDepositsAccountData.depositAmount) { <span class="nx-row__value">{{
<span>{{ recurringDepositsAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs'
recurringDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span>
}}</span> </div>
} <div class="nx-row">
@if (!recurringDepositsAccountData.depositAmount) { <span class="nx-row__label">{{ 'labels.inputs.Interest Posting Period' | translate }}</span>
<span>{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span> <span class="nx-row__value">{{
} recurringDepositsAccountData.interestPostingPeriodType.value | translateKey: 'catalogs'
</td> }}</span>
</tr> </div>
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Rate of Interest' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Interest calculated using' | translate }}</span>
<td class="r-amount"> <span class="nx-row__value">{{
<span>{{ recurringDepositsAccountData.nominalAnnualInterestRate | formatNumber }} %</span> recurringDepositsAccountData.interestCalculationType.value | translateKey: 'catalogs'
</td> }}</span>
</tr> </div>
@if (recurringDepositsAccountData.maturityDate) { <div class="nx-row">
<tr> <span class="nx-row__label">{{ 'labels.inputs.Days in Year' | translate }}</span>
<td>{{ 'labels.inputs.Maturity Amount' | translate }}</td> <span class="nx-row__value">{{
<td class="r-amount"> recurringDepositsAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs'
<span>{{ }}</span>
recurringDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' </div>
}}</span> @if (recurringDepositsAccountData.preClosurePenalApplicable) {
</td> <div class="nx-row">
</tr> <span class="nx-row__label">{{ 'labels.inputs.Pre-closure penal Interest (less)' | translate }}</span>
<span class="nx-row__value">
{{ recurringDepositsAccountData.preClosurePenalInterest }} % on
{{ recurringDepositsAccountData.preClosurePenalInterestOnType.value | translateKey: 'catalogs' }}
</span>
</div>
} }
<tr> @if (recurringDepositsAccountData.witdHoldTax) {
<td>{{ 'labels.inputs.Total Withdrawls' | translate }}</td> <div class="nx-row">
<td class="r-amount"> <span class="nx-row__label">{{ 'labels.inputs.Witdhold Tax Group' | translate }}</span>
<span class="nx-row__value">{{ recurringDepositsAccountData.taxGroup.name }}</span>
</div>
}
</div>
</div>
}
</div>
<!-- ─── Right Column ─────────────────────────────────────────────── -->
<div class="gt-col">
@if (
!recurringDepositsAccountData.status.rejected && !recurringDepositsAccountData.status.submittedAndPendingApproval
) {
<!-- ACTIVE: Performance History -->
<div class="nx-card">
<div class="nx-card__head">
<span class="nx-card__ico"><fa-icon icon="chart-bar"></fa-icon></span>
<h3 class="nx-card__title">{{ 'labels.heading.Performance History' | translate }}</h3>
</div>
<div class="nx-card__body">
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Principal Amount' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ recurringDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Maturity Amount' | translate }}</span>
<span class="nx-row__value nx-row__value--amount nx-row__value--positive">
{{ recurringDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Recurring Deposit Amount' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{
recurringDepositsAccountData?.mandatoryRecommendedDepositAmount
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Deposits till Date' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
@if (recurringDepositsAccountData.summary.totalDeposits) {
{{
recurringDepositsAccountData.summary.totalDeposits
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
} @else {
{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Withdrwals till Date' | translate }}</span>
<span class="nx-row__value nx-row__value--amount nx-row__value--negative">
@if (recurringDepositsAccountData.summary.totalWithdrawals) { @if (recurringDepositsAccountData.summary.totalWithdrawals) {
<span>{{ {{
recurringDepositsAccountData.summary.totalWithdrawals recurringDepositsAccountData.summary.totalWithdrawals
| currency: currency.code : 'symbol-narrow' : '1.2-2' | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</span> }}
} @else {
{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
} }
@if (!recurringDepositsAccountData.summary.totalWithdrawals) { </span>
<span>{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span> </div>
} @if (recurringDepositsAccountData.summary.totalInterestEarned >= 0) {
</td> <div class="nx-row">
</tr> <span class="nx-row__label">{{ 'labels.inputs.Interest Earned' | translate }}</span>
@if (recurringDepositsAccountData.timeline.closedOnDate) { <span class="nx-row__value nx-row__value--amount nx-row__value--positive">
<tr> {{
<td>{{ 'labels.inputs.Closed on Date' | translate }}</td> recurringDepositsAccountData.summary.totalInterestEarned
<td> | currency: currency.code : 'symbol-narrow' : '1.2-2'
{{ recurringDepositsAccountData.timeline.closedOnDate | dateFormat }} }}
</td> </span>
</tr> </div>
} }
<tr> </div>
<td>{{ 'labels.inputs.Deposits Frequency' | translate }}</td> </div>
<td> } @else {
<!-- PENDING/REJECTED: Financial Summary -->
<div class="nx-card">
<div class="nx-card__head">
<span class="nx-card__ico"><fa-icon icon="info-circle"></fa-icon></span>
<h3 class="nx-card__title">{{ 'labels.heading.Other Details' | translate }}</h3>
</div>
<div class="nx-card__body">
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Principal Amount' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
@if (recurringDepositsAccountData.depositAmount) {
{{ recurringDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
} @else {
{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
}
</span>
</div>
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Rate of Interest' | translate }}</span>
<span class="nx-row__value"
>{{ recurringDepositsAccountData.nominalAnnualInterestRate | formatNumber }} %</span
>
</div>
@if (recurringDepositsAccountData.maturityDate) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Maturity Amount' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
{{ recurringDepositsAccountData.maturityAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
</span>
</div>
}
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Total Withdrawls' | translate }}</span>
<span class="nx-row__value nx-row__value--amount">
@if (recurringDepositsAccountData.summary.totalWithdrawals) {
{{
recurringDepositsAccountData.summary.totalWithdrawals
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
} @else {
{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
}
</span>
</div>
@if (recurringDepositsAccountData.timeline.closedOnDate) {
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Closed on Date' | translate }}</span>
<span class="nx-row__value">{{ recurringDepositsAccountData.timeline.closedOnDate | dateFormat }}</span>
</div>
}
<div class="nx-row">
<span class="nx-row__label">{{ 'labels.inputs.Deposits Frequency' | translate }}</span>
<span class="nx-row__value">
{{ recurringDepositsAccountData.recurringFrequency }}&nbsp;{{ {{ recurringDepositsAccountData.recurringFrequency }}&nbsp;{{
recurringDepositsAccountData.recurringFrequencyType.value | translateKey: 'catalogs' recurringDepositsAccountData.recurringFrequencyType.value | translateKey: 'catalogs'
}} }}
</td> </span>
</tr> </div>
@if (recurringDepositsAccountData.summary.totalInterestEarned) { @if (recurringDepositsAccountData.summary.totalInterestEarned) {
<tr> <div class="nx-row">
<td>{{ 'labels.inputs.Interests Posted' | translate }}</td> <span class="nx-row__label">{{ 'labels.inputs.Interests Posted' | translate }}</span>
<td class="r-amount"> <span class="nx-row__value nx-row__value--amount">
@if (recurringDepositsAccountData.summary.totalInterestPosted) { @if (recurringDepositsAccountData.summary.totalInterestPosted) {
<span>{{ {{
recurringDepositsAccountData.summary.totalInterestPosted recurringDepositsAccountData.summary.totalInterestPosted
| currency: currency.code : 'symbol-narrow' : '1.2-2' | currency: currency.code : 'symbol-narrow' : '1.2-2'
}}</span> }}
} @else {
{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
} }
@if (!recurringDepositsAccountData.summary.totalInterestPosted) { </span>
<span>{{ 0 | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span> </div>
}
</td>
</tr>
} }
</tbody> </div>
</table> </div>
</div> }
} </div>
</div>
<div class="recurring-deposits-account-tables layout-row gap-2percent">
@if (
!recurringDepositsAccountData.status.rejected && !recurringDepositsAccountData.status.submittedAndPendingApproval
) {
<div class="flex-49">
<h4 class="table-headers">{{ 'labels.heading.Interest Details' | translate }}</h4>
<table>
<tbody>
<tr>
<td>{{ 'labels.inputs.Interest Rate' | translate }}</td>
<td class="r-amount">{{ recurringDepositsAccountData.nominalAnnualInterestRate | formatNumber }} %</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest Compounding Period' | translate }}</td>
<td>
<span>{{
recurringDepositsAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs'
}}</span>
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest Posting Period' | translate }}</td>
<td>
<span>{{ recurringDepositsAccountData.interestPostingPeriodType.value | translateKey: 'catalogs' }}</span>
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest calculated using' | translate }}</td>
<td>
<span>{{ recurringDepositsAccountData.interestCalculationType.value | translateKey: 'catalogs' }}</span>
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Days in Year' | translate }}</td>
<td>
<span>{{
recurringDepositsAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs'
}}</span>
</td>
</tr>
@if (recurringDepositsAccountData.preClosurePenalApplicable) {
<tr>
<td>{{ 'labels.inputs.Pre-closure penal Interest (less)' | translate }}</td>
<td>
<span
>{{ recurringDepositsAccountData.preClosurePenalInterest }} % on
{{
recurringDepositsAccountData.preClosurePenalInterestOnType.value | translateKey: 'catalogs'
}}</span
>
</td>
</tr>
}
</tbody>
</table>
</div>
}
@if (
recurringDepositsAccountData.status.rejected || recurringDepositsAccountData.status.submittedAndPendingApproval
) {
<div class="flex-49">
<table>
<tbody>
<tr>
<td>{{ 'labels.inputs.Interest Compounding Period' | translate }}</td>
<td>
<span>{{
recurringDepositsAccountData.interestCompoundingPeriodType.value | translateKey: 'catalogs'
}}</span>
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest Posting Period' | translate }}</td>
<td>
<span>{{ recurringDepositsAccountData.interestPostingPeriodType.value | translateKey: 'catalogs' }}</span>
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Interest calculated using' | translate }}</td>
<td>
<span>{{ recurringDepositsAccountData.interestCalculationType.value | translateKey: 'catalogs' }}</span>
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Days in Year' | translate }}</td>
<td>
<span>{{
recurringDepositsAccountData.interestCalculationDaysInYearType.value | translateKey: 'catalogs'
}}</span>
</td>
</tr>
@if (recurringDepositsAccountData.preClosurePenalApplicable) {
<tr>
<td>{{ 'labels.inputs.Pre-closure penal Interest (less)' | translate }}</td>
<td>
<span
>{{ recurringDepositsAccountData.preClosurePenalInterest }} % on
{{
recurringDepositsAccountData.preClosurePenalInterestOnType.value | translateKey: 'catalogs'
}}</span
>
</td>
</tr>
}
@if (recurringDepositsAccountData.witdHoldTax) {
<tr>
<td>{{ 'labels.inputs.Witdhold Tax Group' | translate }}</td>
<td>
<span>{{ recurringDepositsAccountData.taxGroup.name }}</span>
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div> </div>
@@ -6,6 +6,115 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
.recurring-deposits-account-tables { $navy: #0d1b2a;
padding: 1%; $slate: #475569;
$muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
/* ─── Two-column grid ───────────────────────────────────────────────── */
.gt-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 16px;
@media (width <= 1024px) {
grid-template-columns: 1fr;
}
}
.gt-col {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 0;
}
/* ─── Nexora section 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: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
}
&__ico {
width: 26px;
height: 26px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 8px;
background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
color: #fff;
font-size: 12px;
}
&__title {
margin: 0;
font-size: 13.5px;
font-weight: 700;
color: $navy;
letter-spacing: 0.01em;
}
&__body {
padding: 4px 18px 10px;
}
}
/* ─── Key/Value row ─────────────────────────────────────────────────── */
.nx-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
min-height: 38px;
padding: 8px 0;
border-bottom: 1px dashed #eef2f7;
font-size: 13px;
&:last-child {
border-bottom: none;
}
&__label {
color: $slate;
font-weight: 500;
}
&__value {
color: $navy;
font-weight: 600;
text-align: right;
word-break: break-word;
&--amount {
font-variant-numeric: tabular-nums;
font-weight: 700;
}
&--positive {
color: #047857;
}
&--negative {
color: #b91c1c;
}
}
}
.nx-muted {
color: $muted;
font-weight: 500;
font-style: italic;
} }
@@ -13,6 +13,7 @@ import { DecimalPipe, CurrencyPipe } from '@angular/common';
import { ExternalIdentifierComponent } from '../../../../shared/external-identifier/external-identifier.component'; import { ExternalIdentifierComponent } from '../../../../shared/external-identifier/external-identifier.component';
import { DateFormatPipe } from '../../../../pipes/date-format.pipe'; import { DateFormatPipe } from '../../../../pipes/date-format.pipe';
import { FormatNumberPipe } from '../../../../pipes/format-number.pipe'; import { FormatNumberPipe } from '../../../../pipes/format-number.pipe';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@Component({ @Component({
@@ -22,6 +23,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
imports: [ imports: [
...STANDALONE_SHARED_IMPORTS, ...STANDALONE_SHARED_IMPORTS,
ExternalIdentifierComponent, ExternalIdentifierComponent,
FaIconComponent,
DecimalPipe, DecimalPipe,
CurrencyPipe, CurrencyPipe,
DateFormatPipe, DateFormatPipe,
@@ -6,196 +6,201 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<mat-card class="account-card"> <div class="rd-view">
<mat-card-header class="header layout-column"> <!-- ─── Gradient hero header ─────────────────────────────────────── -->
<mat-card-title-group class="header-title-group"> <header class="rd-hero">
<div class="profile-image-container"> <div class="rd-hero__left">
<div> <div class="rd-hero__avatar">
<img <fa-icon icon="calendar-alt"></fa-icon>
mat-card-md-image </div>
class="profile-image"
matTooltip="{{ 'tooltips.Recurring Deposits Account' | translate }}" <div class="rd-hero__info">
[src]="'assets/images/recurring-deposits_account_placeholder.png'" <div class="rd-hero__status-row">
/> <span
class="rd-status-pill"
[ngClass]="recurringDepositsAccountData.status.code | statusLookup"
[matTooltip]="recurringDepositsAccountData.status.value"
>
<span class="rd-status-pill__dot"></span>
{{ recurringDepositsAccountData.status.value }}
</span>
</div>
<h2 class="rd-hero__title">
<mifosx-long-text textValue="{{ recurringDepositsAccountData.depositProductName }}"></mifosx-long-text>
</h2>
<div class="rd-hero__meta">
<span class="rd-hero__meta-item">
<span class="rd-hero__meta-label">{{ 'labels.inputs.Account Number' | translate }}</span>
<mifosx-account-number
accountNo="{{ recurringDepositsAccountData.accountNo }}"
display="left"
></mifosx-account-number>
</span>
<span class="rd-hero__meta-item">
<span class="rd-hero__meta-label">
{{ 'labels.text.' + entityType | translate }} {{ 'labels.inputs.name' | translate }}
</span>
<span class="rd-hero__meta-value">
{{ recurringDepositsAccountData.clientName || recurringDepositsAccountData.groupName }}
@if (recurringDepositsAccountData.clientAccountNo) {
<mifosx-account-number
accountNo="{{ recurringDepositsAccountData.clientAccountNo }}"
></mifosx-account-number>
}
</span>
</span>
</div> </div>
</div> </div>
</div>
<div class="mat-typography account-card-title"> <!-- Balance KPI strip -->
<mat-card-title> @if (
<div class="layout-row responsive-column"> !recurringDepositsAccountData.status.rejected && !recurringDepositsAccountData.status.submittedAndPendingApproval
<div class="flex-60"> ) {
<h3> <div class="rd-hero__kpis">
<i <div class="rd-kpi">
class="fa fa-stop" <span class="rd-kpi__label">{{ 'labels.inputs.Current Balance' | translate }}</span>
[ngClass]="recurringDepositsAccountData.status.code | statusLookup" <span class="rd-kpi__value">
[matTooltip]="recurringDepositsAccountData.status.value" {{
></i> recurringDepositsAccountData.summary.accountBalance | currency: currency.code : 'symbol-narrow' : '1.2-2'
{{ 'labels.inputs.Recurring Deposit' | translate }} : }}
{{ recurringDepositsAccountData.depositProductName }} </span>
<mifosx-account-number accountNo="{{ recurringDepositsAccountData.accountNo }}"></mifosx-account-number> </div>
</h3> <div class="rd-kpi rd-kpi--deposit">
<span class="account-overview"> <span class="rd-kpi__label">{{ 'labels.inputs.Deposit Amount' | translate }}</span>
{{ 'labels.text.' + entityType | translate }} {{ 'labels.inputs.name' | translate }}: <span class="rd-kpi__value">
{{ recurringDepositsAccountData.clientName || recurringDepositsAccountData.groupName }} {{ recurringDepositsAccountData.depositAmount | currency: currency.code : 'symbol-narrow' : '1.2-2' }}
@if (recurringDepositsAccountData.clientAccountNo) { </span>
<span class="m-l-10"> </div>
<mifosx-account-number <div class="rd-kpi rd-kpi--period">
accountNo="{{ recurringDepositsAccountData.clientAccountNo }}" <span class="rd-kpi__label">{{ 'labels.inputs.Deposit Period' | translate }}</span>
></mifosx-account-number> <span class="rd-kpi__value">{{ recurringDepositsAccountData.depositPeriod | number }}</span>
</span> </div>
}
</span>
</div>
@if (
!recurringDepositsAccountData.status.rejected &&
!recurringDepositsAccountData.status.submittedAndPendingApproval
) {
<div class="flex-30">
<h3>{{ 'labels.heading.Account Overview' | translate }}</h3>
<table class="account-overview">
<tbody>
<tr>
<td>{{ 'labels.inputs.Current Balance' | translate }}</td>
<td class="r-amount">
{{
recurringDepositsAccountData.summary.accountBalance
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Deposit Amount' | translate }}</td>
<td class="r-amount">
{{
recurringDepositsAccountData.depositAmount
| currency: currency.code : 'symbol-narrow' : '1.2-2'
}}
</td>
</tr>
<tr>
<td>{{ 'labels.inputs.Deposit Period' | translate }}</td>
<td class="r-amount">{{ recurringDepositsAccountData.depositPeriod | number }}</td>
</tr>
</tbody>
</table>
</div>
}
<div class="flex-5">
<button
mat-icon-button
[matMenuTriggerFor]="accountMenu"
aria-label="Loan account actions"
yPosition="below"
>
<mat-icon matListIcon class="actions-menu">
<fa-icon icon="bars" size="sm"></fa-icon>
</mat-icon>
</button>
</div>
</div>
</mat-card-title>
</div> </div>
}
<mat-menu #accountMenu="matMenu"> <!-- Action menu (kebab) -->
@for (item of buttonConfig.singleButtons; track item) { <div class="rd-hero__actions">
<button mat-menu-item *mifosxHasPermission="item.taskPermissionName" (click)="doAction(item.name)"> <button mat-icon-button [matMenuTriggerFor]="accountMenu" aria-label="Account actions" yPosition="below">
<i ngClass="{{ item.icon }}"></i> {{ 'labels.menus.' + item.name | translate }} <fa-icon icon="ellipsis-v"></fa-icon>
</button> </button>
} </div>
@if (buttonConfig.options.length) { <mat-menu #accountMenu="matMenu">
<button mat-menu-item [matMenuTriggerFor]="More">{{ 'labels.menus.More' | translate }}</button> @for (item of buttonConfig.singleButtons; track item) {
<mat-menu #More="matMenu"> <button mat-menu-item *mifosxHasPermission="item.taskPermissionName" (click)="doAction(item.name)">
@for (option of buttonConfig.options; track option) { <span>{{ 'labels.menus.' + item.name | translate }}</span>
<span> </button>
<button mat-menu-item *mifosxHasPermission="option.taskPermissionName" (click)="doAction(option.name)"> }
{{ 'labels.menus.' + option.name | translate }} @if (buttonConfig.options.length) {
</button> <button mat-menu-item [matMenuTriggerFor]="More">{{ 'labels.menus.More' | translate }}</button>
</span> <mat-menu #More="matMenu">
} @for (option of buttonConfig.options; track option) {
</mat-menu> <span>
} <button mat-menu-item *mifosxHasPermission="option.taskPermissionName" (click)="doAction(option.name)">
</mat-menu> {{ 'labels.menus.' + option.name | translate }}
</mat-card-title-group> </button>
</mat-card-header> </span>
}
</mat-menu>
}
</mat-menu>
</header>
<mat-card-content class="content"> <!-- ─── Pill-style tab navigation ─────────────────────────────────── -->
<nav mat-tab-nav-bar class="navigation-tabs" [tabPanel]="tabPanel"> <nav mat-tab-nav-bar class="rd-tabs" [tabPanel]="tabPanel">
<a
mat-tab-link
class="rd-tab"
[routerLink]="['./general']"
routerLinkActive
#general="routerLinkActive"
[active]="general.isActive"
>
<fa-icon icon="info-circle" class="rd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.General' | translate }}</span>
</a>
<a
mat-tab-link
class="rd-tab"
[routerLink]="['./interest-rate-chart']"
routerLinkActive
#IRC="routerLinkActive"
[active]="IRC.isActive"
>
<fa-icon icon="chart-line" class="rd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Interest Rate Chart' | translate }}</span>
</a>
@if (showTransactions) {
<a <a
mat-tab-link mat-tab-link
[routerLink]="['./general']" class="rd-tab"
[routerLink]="['./transactions']"
routerLinkActive routerLinkActive
#general="routerLinkActive" #transactions="routerLinkActive"
[active]="general.isActive" [active]="transactions.isActive"
> >
{{ 'labels.inputs.General' | translate }} <fa-icon icon="exchange-alt" class="rd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Transactions' | translate }}</span>
</a> </a>
}
<a
mat-tab-link
class="rd-tab"
[routerLink]="['./charges']"
routerLinkActive
#charges="routerLinkActive"
[active]="charges.isActive"
>
<fa-icon icon="receipt" class="rd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Charges' | translate }}</span>
</a>
@if (recurringDepositsAccountData.clientId) {
<a <a
mat-tab-link mat-tab-link
[routerLink]="['./interest-rate-chart']" class="rd-tab"
[routerLink]="['./standing-instructions-tab']"
routerLinkActive routerLinkActive
#IRC="routerLinkActive" #standingInstructions="routerLinkActive"
[active]="IRC.isActive" [active]="standingInstructions.isActive"
> >
{{ 'labels.inputs.Interest Rate Chart' | translate }} <fa-icon icon="calendar-check" class="rd-tab__ic"></fa-icon>
<span>{{ 'labels.inputs.Standing Instructions' | translate }}</span>
</a> </a>
@if (showTransactions) { }
<a <a
mat-tab-link mat-tab-link
[routerLink]="['./transactions']" class="rd-tab"
routerLinkActive [routerLink]="['./nominees']"
#transactions="routerLinkActive" routerLinkActive
[active]="transactions.isActive" #nominees="routerLinkActive"
> [active]="nominees.isActive"
{{ 'labels.inputs.Transactions' | translate }} >
</a> <fa-icon icon="user-shield" class="rd-tab__ic"></fa-icon>
} <span>Nominees</span>
</a>
@for (savingsDatatable of savingsDatatables; track savingsDatatable) {
<a <a
mat-tab-link mat-tab-link
[routerLink]="['./charges']" class="rd-tab"
*mifosxHasPermission="'READ_' + savingsDatatable.registeredTableName"
[routerLink]="['./datatables', savingsDatatable.registeredTableName]"
routerLinkActive routerLinkActive
#charges="routerLinkActive" #datatable="routerLinkActive"
[active]="charges.isActive" [active]="datatable.isActive"
> >
{{ 'labels.inputs.Charges' | translate }} <fa-icon icon="table" class="rd-tab__ic"></fa-icon>
<span>{{ savingsDatatable.registeredTableName }}</span>
</a> </a>
@if (recurringDepositsAccountData.clientId) { }
<a </nav>
mat-tab-link
[routerLink]="['./standing-instructions-tab']" <mat-tab-nav-panel #tabPanel>
routerLinkActive <div class="rd-body">
#standingInstructions="routerLinkActive"
[active]="standingInstructions.isActive"
>
{{ 'labels.inputs.Standing Instructions' | translate }}
</a>
}
<a
mat-tab-link
[routerLink]="['./nominees']"
routerLinkActive
#nominees="routerLinkActive"
[active]="nominees.isActive"
>
Nominees
</a>
@for (savingsDatatable of savingsDatatables; track savingsDatatable) {
<a
mat-tab-link
*mifosxHasPermission="'READ_' + savingsDatatable.registeredTableName"
[routerLink]="['./datatables', savingsDatatable.registeredTableName]"
routerLinkActive
#datatable="routerLinkActive"
[active]="datatable.isActive"
>
{{ savingsDatatable.registeredTableName }}
</a>
}
</nav>
<mat-tab-nav-panel #tabPanel>
<router-outlet></router-outlet> <router-outlet></router-outlet>
</mat-tab-nav-panel> </div>
</mat-card-content> </mat-tab-nav-panel>
</mat-card> </div>
@@ -5,3 +5,386 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
$navy: #0d1b2a;
$blue: #1e88e5;
$blue-d: #1e40af;
$border: #e2e8f0;
.rd-view {
max-width: 1440px;
margin: 0 auto;
padding: 12px 20px 22px;
}
/* ─── Gradient hero header ──────────────────────────────────────────── */
.rd-hero {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
align-items: stretch;
gap: 14px;
padding: 12px 18px;
border-radius: 12px;
color: #fff;
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 45%, #4338ca 100%);
box-shadow: 0 6px 18px -10px rgb(15 23 42 / 35%);
overflow: hidden;
&::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at top right, rgb(255 255 255 / 12%) 0%, transparent 55%);
pointer-events: none;
}
&__left {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
position: relative;
z-index: 1;
}
&__avatar {
width: 40px;
height: 40px;
border-radius: 10px;
background: linear-gradient(135deg, rgb(255 255 255 / 22%) 0%, rgb(255 255 255 / 10%) 100%);
border: 1px solid rgb(255 255 255 / 28%);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 16px;
flex-shrink: 0;
box-shadow: 0 3px 10px -3px rgb(0 0 0 / 25%);
}
&__info {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 0;
}
&__status-row {
display: flex;
align-items: center;
gap: 6px;
}
&__title {
margin: 0;
font-size: 15px;
font-weight: 800;
letter-spacing: 0.01em;
color: #fff;
line-height: 1.15;
::ng-deep mifosx-long-text {
color: #fff;
}
}
&__meta {
display: flex;
flex-wrap: wrap;
gap: 2px 18px;
margin-top: 1px;
}
&__meta-item {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: rgb(255 255 255 / 90%);
}
&__meta-label {
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.07em;
color: rgb(255 255 255 / 60%);
font-weight: 600;
}
&__meta-value {
font-weight: 600;
color: #fff;
}
&__kpis {
display: flex;
gap: 8px;
align-items: stretch;
position: relative;
z-index: 1;
}
&__actions {
display: flex;
align-items: center;
position: relative;
z-index: 1;
button {
width: 32px !important;
height: 32px !important;
min-width: 32px !important;
padding: 0 !important;
border-radius: 50% !important;
color: #fff !important;
background: rgb(255 255 255 / 10%) !important;
border: 1px solid rgb(255 255 255 / 22%) !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
line-height: 1;
transition:
background 0.15s ease,
border-color 0.15s ease,
transform 0.12s ease;
::ng-deep fa-icon {
font-size: 14px;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
}
::ng-deep .mat-mdc-button-persistent-ripple,
::ng-deep .mat-mdc-button-touch-target {
border-radius: 50% !important;
}
}
button:hover {
background: rgb(255 255 255 / 22%) !important;
border-color: rgb(255 255 255 / 38%) !important;
}
button:active {
transform: scale(0.94);
}
}
}
/* KPI tiles */
.rd-kpi {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 110px;
padding: 7px 14px;
border-radius: 9px;
background: rgb(255 255 255 / 14%);
border: 1px solid rgb(255 255 255 / 22%);
backdrop-filter: blur(8px);
&__label {
font-size: 9.5px;
text-transform: uppercase;
letter-spacing: 0.07em;
font-weight: 700;
color: rgb(255 255 255 / 75%);
}
&__value {
margin-top: 2px;
font-size: 15px;
font-weight: 800;
color: #fff;
font-variant-numeric: tabular-nums;
letter-spacing: -0.01em;
}
&--deposit {
background: rgb(245 158 11 / 22%);
border-color: rgb(245 158 11 / 35%);
}
&--period {
background: rgb(139 92 246 / 22%);
border-color: rgb(139 92 246 / 35%);
}
}
/* Status pill */
.rd-status-pill {
display: inline-flex;
align-items: center;
gap: 5px;
height: 18px;
padding: 0 8px;
border-radius: 999px;
background: rgb(16 185 129 / 24%);
border: 1px solid rgb(16 185 129 / 40%);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #d1fae5;
&__dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 0 2px rgb(16 185 129 / 30%);
}
&.statussubmitted,
&.statuspending {
background: rgb(245 158 11 / 24%);
border-color: rgb(245 158 11 / 40%);
color: #fef3c7;
.rd-status-pill__dot {
background: #f59e0b;
}
}
&.statusclosed,
&.statusrejected,
&.statuswithdrawn,
&.statusprematureclosed {
background: rgb(239 68 68 / 24%);
border-color: rgb(239 68 68 / 40%);
color: #fee2e2;
.rd-status-pill__dot {
background: #ef4444;
}
}
}
/* ─── Pill-style tab navigation ─────────────────────────────────────── */
.rd-tabs {
margin-top: 18px;
background: #fff;
border: 1px solid $border;
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;
flex-wrap: wrap;
}
.mdc-tab-indicator__content--underline,
.mat-mdc-tab-header-pagination-controls-enabled .mdc-tab-indicator__content--underline {
display: none !important;
}
}
}
.rd-tab {
display: inline-flex !important;
align-items: center;
gap: 8px;
height: 38px !important;
min-width: 0 !important;
padding: 0 16px !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: 12px;
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,
.rd-tab__ic {
color: #fff !important;
opacity: 1 !important;
}
}
}
.rd-body {
margin-top: 16px;
}
/* ─── Responsive ────────────────────────────────────────────────────── */
@media (width <= 1100px) {
.rd-hero {
grid-template-columns: 1fr;
&__kpis {
width: 100%;
flex-wrap: wrap;
}
&__actions {
position: absolute;
top: 18px;
right: 18px;
}
}
.rd-kpi {
flex: 1 1 auto;
min-width: 0;
}
}
@media (width <= 700px) {
.rd-view {
padding: 12px;
}
.rd-hero {
padding: 18px;
&__title {
font-size: 18px;
}
&__avatar {
width: 52px;
height: 52px;
font-size: 22px;
border-radius: 12px;
}
}
.rd-tab {
padding: 0 12px !important;
font-size: 12px !important;
}
}
@@ -23,17 +23,10 @@ import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.co
import { RecurringDepositConfirmationDialogComponent } from './custom-dialogs/recurring-deposit-confirmation-dialog/recurring-deposit-confirmation-dialog.component'; import { RecurringDepositConfirmationDialogComponent } from './custom-dialogs/recurring-deposit-confirmation-dialog/recurring-deposit-confirmation-dialog.component';
import { Currency } from 'app/shared/models/general.model'; import { Currency } from 'app/shared/models/general.model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import {
MatCard,
MatCardHeader,
MatCardTitleGroup,
MatCardMdImage,
MatCardTitle,
MatCardContent
} from '@angular/material/card';
import { MatTooltip } from '@angular/material/tooltip'; import { MatTooltip } from '@angular/material/tooltip';
import { NgClass, DecimalPipe, CurrencyPipe } from '@angular/common'; import { NgClass, DecimalPipe, CurrencyPipe } from '@angular/common';
import { AccountNumberComponent } from '../../../shared/account-number/account-number.component'; import { AccountNumberComponent } from '../../../shared/account-number/account-number.component';
import { LongTextComponent } from '../../../shared/long-text/long-text.component';
import { MatIconButton } from '@angular/material/button'; import { MatIconButton } from '@angular/material/button';
import { MatMenuTrigger, MatMenu, MatMenuItem } from '@angular/material/menu'; import { MatMenuTrigger, MatMenu, MatMenuItem } from '@angular/material/menu';
import { MatIcon } from '@angular/material/icon'; import { MatIcon } from '@angular/material/icon';
@@ -51,12 +44,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
styleUrls: ['./recurring-deposits-account-view.component.scss'], styleUrls: ['./recurring-deposits-account-view.component.scss'],
imports: [ imports: [
...STANDALONE_SHARED_IMPORTS, ...STANDALONE_SHARED_IMPORTS,
MatCardHeader,
MatCardTitleGroup,
MatCardMdImage,
MatTooltip, MatTooltip,
MatCardTitle,
NgClass, NgClass,
LongTextComponent,
AccountNumberComponent, AccountNumberComponent,
MatIconButton, MatIconButton,
MatMenuTrigger, MatMenuTrigger,
@@ -6,23 +6,19 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="tab-container mat-typography"> <div class="txn-tab">
<div class="mat-elevation-z1 m-b-25"> <div class="txn-tab__card">
<div class="layout-row align-start"> @if (checkStatus()) {
<div class="m-b-20"> <div class="txn-tab__toolbar">
<h3>{{ 'labels.heading.All Transactions' | translate }}</h3> <mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="txn-tab__check">
{{ 'labels.inputs.Hide Reversed' | translate }}
</mat-checkbox>
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="txn-tab__check">
{{ 'labels.inputs.Hide Accruals' | translate }}
</mat-checkbox>
<span class="txn-tab__spacer"></span>
</div> </div>
@if (checkStatus()) { }
<div class="action-button m-b-20 layout-row gap-20px">
<mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="accruals">
{{ 'labels.inputs.Hide Reversed' | translate }}</mat-checkbox
>
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="accruals">
{{ 'labels.inputs.Hide Accruals' | translate }}</mat-checkbox
>
</div>
}
</div>
<table mat-table [dataSource]="dataSource"> <table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="row"> <ng-container matColumnDef="row">
@@ -6,37 +6,95 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
@use 'assets/styles/helper'; $navy: #0d1b2a;
$slate: #475569;
$muted: #64748b;
$border: #e2e8f0;
$soft: #f8fafc;
$blue: #1e40af;
.tab-container { .txn-tab {
padding: 1%; width: 100%;
margin: 1%;
h3 {
margin: 1% auto;
}
.action-button {
margin-left: auto;
}
table {
width: 100%;
.account-action-button {
min-width: 26px;
padding: 0 0 3px;
margin: 0 10%;
line-height: 25px;
.accruals {
padding-top: 1%;
}
}
}
} }
.select-row:hover { .txn-tab__card {
cursor: pointer; background: #fff;
font-weight: 800; border: 1px solid $border;
border-radius: 14px;
box-shadow: 0 1px 3px rgb(15 23 42 / 4%);
overflow: hidden;
}
.txn-tab__toolbar {
display: flex;
align-items: center;
gap: 18px;
padding: 12px 18px;
background: $soft;
border-bottom: 1px solid $border;
flex-wrap: wrap;
}
.txn-tab__check {
font-size: 13px;
color: $slate;
font-weight: 500;
}
.txn-tab__spacer {
flex: 1;
}
table {
width: 100%;
}
::ng-deep .txn-tab__card {
.mat-mdc-header-row {
background: $soft;
}
.mat-mdc-header-cell {
font-size: 11.5px;
font-weight: 800;
color: $slate;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 12px 14px;
border-bottom: 1px solid $border;
}
.mat-mdc-cell {
font-size: 13px;
color: $navy;
padding: 11px 14px;
border-bottom: 1px solid #f1f5f9;
}
.mat-mdc-row:hover {
background: #f8fafc;
cursor: pointer;
}
.mat-column-debit,
.mat-column-credit,
.mat-column-balance {
text-align: right;
font-variant-numeric: tabular-nums;
}
.mat-column-actions {
text-align: center;
width: 80px;
}
.strike td {
text-decoration: line-through;
color: $muted;
}
.accrual td {
color: $muted;
font-style: italic;
}
} }