feat: complete UI redesign — client creation tabs, footer, home page, CIF & occupation fields
- Client creation: replaced vertical stepper with 3-tab layout (General, KYC & Nominee, Preview) - All form fields redesigned with appearance="outline" and section grouping - Preview tab with profile card, info tables, KYC details, family members - Footer redesigned: security bar, LincShield certifications, regulatory & legal, quick navigation, support & contact, LincPay branding - Home page redesigned: welcome banner, quick action cards, info row - Client view header redesigned: ID chips row (Account No, CIF Number, External Id), 4-column details grid - Added CIF Number column to clients list table - Added CIF Number display to client view sidebar and personal data tab - Added occupationCategoryId and occupationId dropdowns to client creation form - Added occupation fields to client view sidebar, personal data tab, and preview - Added 51+ missing translation keys to en-US.json - Toolbar: added Last login chip - Registered faUserPlus icon Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
b3a4cce0cf
commit
7b1f2e8ad7
+1
-1
@@ -31,7 +31,7 @@
|
|||||||
"@angular/localize/init"
|
"@angular/localize/init"
|
||||||
],
|
],
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/favicon.ico",
|
"src/assets/images/cbsnexora-favicon.svg",
|
||||||
"src/robots.txt",
|
"src/robots.txt",
|
||||||
"src/manifest.json",
|
"src/manifest.json",
|
||||||
"src/assets",
|
"src/assets",
|
||||||
|
|||||||
+107
-79
@@ -7,87 +7,115 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="mat-typography">
|
<div class="mat-typography">
|
||||||
<h3>{{ 'labels.heading.Address' | translate }}</h3>
|
<div class="section-block">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4 class="section-title">
|
||||||
|
<fa-icon icon="location-arrow" class="section-icon"></fa-icon>
|
||||||
|
{{ 'labels.heading.Address' | translate }}
|
||||||
|
</h4>
|
||||||
|
<button mat-stroked-button color="primary" (click)="addAddress()" class="add-btn">
|
||||||
|
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Add' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="layout-row align-end m-b-20">
|
@if (clientAddressData.length === 0) {
|
||||||
<button mat-raised-button color="primary" (click)="addAddress()">
|
<div class="empty-state">
|
||||||
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Add' | translate }}
|
<fa-icon icon="location-arrow" class="empty-icon"></fa-icon>
|
||||||
</button>
|
<span>No address added yet. Click Add to add an address.</span>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@if (clientAddressData.length > 0) {
|
@if (clientAddressData.length > 0) {
|
||||||
<mat-accordion>
|
<mat-accordion>
|
||||||
@for (address of clientAddressData; track address; let i = $index) {
|
@for (address of clientAddressData; track address; let i = $index) {
|
||||||
<mat-expansion-panel class="address">
|
<mat-expansion-panel class="address-panel">
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title>
|
<mat-panel-title>
|
||||||
{{ getSelectedValue('addressTypeIdOptions', address.addressTypeId)?.name }}
|
<fa-icon icon="location-arrow" class="panel-icon"></fa-icon>
|
||||||
</mat-panel-title>
|
{{ getSelectedValue('addressTypeIdOptions', address.addressTypeId)?.name }}
|
||||||
<mat-panel-description>
|
</mat-panel-title>
|
||||||
{{ address.relationship }}
|
<mat-panel-description>
|
||||||
</mat-panel-description>
|
{{ address.relationship }}
|
||||||
</mat-expansion-panel-header>
|
</mat-panel-description>
|
||||||
<mat-divider></mat-divider>
|
</mat-expansion-panel-header>
|
||||||
<div class="address-actions layout-row align-end align-items-center">
|
|
||||||
<button mat-button color="primary" (click)="editAddress(address, i)">
|
|
||||||
<fa-icon icon="edit"></fa-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-button color="warn" (click)="deleteAddress(address, i)">
|
|
||||||
<fa-icon icon="trash"></fa-icon>
|
|
||||||
</button>
|
|
||||||
<mat-slide-toggle [checked]="address.isActive" (change)="toggleAddress(address)"></mat-slide-toggle>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
@if (isFieldEnabled('street')) {
|
|
||||||
<span>{{ 'labels.inputs.Street' | translate }} : {{ address.street }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('addressLine1')) {
|
|
||||||
<span>{{ 'labels.inputs.Address Line' | translate }} 1 : {{ address.addressLine1 }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('addressLine2')) {
|
|
||||||
<span>{{ 'labels.inputs.Address Line' | translate }} 2 : {{ address.addressLine2 }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('addressLine3')) {
|
|
||||||
<span>{{ 'labels.inputs.Address Line' | translate }} 3 : {{ address.addressLine3 }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('townVillage')) {
|
|
||||||
<span>{{ 'labels.inputs.Town / Village' | translate }} : {{ address.townVillage }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('city')) {
|
|
||||||
<span>{{ 'labels.inputs.City' | translate }} : {{ address.city }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('stateProvinceId')) {
|
|
||||||
<span
|
|
||||||
>{{ 'labels.inputs.State / Province' | translate }} :
|
|
||||||
{{ getSelectedValue('stateProvinceIdOptions', address.stateProvinceId)?.name }}<br
|
|
||||||
/></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('countryId')) {
|
|
||||||
<span
|
|
||||||
>{{ 'labels.inputs.Country' | translate }} :
|
|
||||||
{{ getSelectedValue('countryIdOptions', address.countryId)?.name }}<br
|
|
||||||
/></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('postalCode')) {
|
|
||||||
<span>{{ 'labels.inputs.Postal Code' | translate }} : {{ address.postalCode }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('isActive')) {
|
|
||||||
<span>{{ 'labels.inputs.Active Status' | translate }} : {{ address.isActive }}<br /></span>
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</mat-expansion-panel>
|
|
||||||
}
|
|
||||||
</mat-accordion>
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="layout-row align-center gap-2percent margin-t responsive-column">
|
<mat-divider></mat-divider>
|
||||||
<button mat-raised-button matStepperPrevious>
|
|
||||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
<div class="address-actions">
|
||||||
{{ 'labels.buttons.Previous' | translate }}
|
<button mat-button color="primary" (click)="editAddress(address, i)">
|
||||||
</button>
|
<fa-icon icon="edit"></fa-icon>
|
||||||
<button mat-raised-button matStepperNext>
|
</button>
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
<button mat-button color="warn" (click)="deleteAddress(address, i)">
|
||||||
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
|
<fa-icon icon="trash"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
|
<mat-slide-toggle [checked]="address.isActive" (change)="toggleAddress(address)"></mat-slide-toggle>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="address-details">
|
||||||
|
@if (isFieldEnabled('street')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Street' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ address.street }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('addressLine1')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Address Line' | translate }} 1</span>
|
||||||
|
<span class="detail-value">{{ address.addressLine1 }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('addressLine2')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Address Line' | translate }} 2</span>
|
||||||
|
<span class="detail-value">{{ address.addressLine2 }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('addressLine3')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Address Line' | translate }} 3</span>
|
||||||
|
<span class="detail-value">{{ address.addressLine3 }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('townVillage')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Town / Village' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ address.townVillage }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('city')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.City' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ address.city }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('stateProvinceId')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.State / Province' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ getSelectedValue('stateProvinceIdOptions', address.stateProvinceId)?.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('countryId')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Country' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ getSelectedValue('countryIdOptions', address.countryId)?.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('postalCode')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Postal Code' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ address.postalCode }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (isFieldEnabled('isActive')) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Active Status' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ address.isActive ? 'Active' : 'Inactive' }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
}
|
||||||
|
</mat-accordion>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+92
-15
@@ -6,25 +6,102 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.address {
|
.section-block {
|
||||||
.address-actions {
|
margin-bottom: 8px;
|
||||||
margin-top: 1%;
|
}
|
||||||
|
|
||||||
button {
|
.section-header {
|
||||||
margin-right: 1%;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
.section-title {
|
||||||
margin: 1% auto;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
p {
|
.section-icon {
|
||||||
line-height: 30px;
|
color: var(--md-sys-color-primary, #1074b9);
|
||||||
margin-left: 2%;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.margin-t {
|
.add-btn {
|
||||||
margin-top: 2em;
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 24px 16px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-size: 14px;
|
||||||
|
background: rgba(0, 0, 0, 0.02);
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px dashed rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-panel {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.panel-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
margin: 8px 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-details {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px 24px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.section-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-details {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
} from '@angular/material/expansion';
|
} from '@angular/material/expansion';
|
||||||
import { MatDivider } from '@angular/material/divider';
|
import { MatDivider } from '@angular/material/divider';
|
||||||
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||||
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
|
|
||||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,9 +48,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
MatExpansionPanelTitle,
|
MatExpansionPanelTitle,
|
||||||
MatExpansionPanelDescription,
|
MatExpansionPanelDescription,
|
||||||
MatDivider,
|
MatDivider,
|
||||||
MatSlideToggle,
|
MatSlideToggle
|
||||||
MatStepperPrevious,
|
|
||||||
MatStepperNext
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ClientAddressStepComponent {
|
export class ClientAddressStepComponent {
|
||||||
|
|||||||
-11
@@ -53,15 +53,4 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layout-row align-center gap-2percent margin-t responsive-column">
|
|
||||||
<button mat-raised-button matStepperPrevious disabled>
|
|
||||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
|
||||||
{{ 'labels.buttons.Previous' | translate }}
|
|
||||||
</button>
|
|
||||||
<button mat-raised-button matStepperNext>
|
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
|
||||||
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+2
-4
@@ -17,7 +17,7 @@ import {
|
|||||||
import { Datatables } from 'app/core/utils/datatables';
|
import { Datatables } from 'app/core/utils/datatables';
|
||||||
import { SettingsService } from 'app/settings/settings.service';
|
import { SettingsService } from 'app/settings/settings.service';
|
||||||
import { MatCheckbox } from '@angular/material/checkbox';
|
import { MatCheckbox } from '@angular/material/checkbox';
|
||||||
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
|
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||||
|
|
||||||
@@ -28,9 +28,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
imports: [
|
imports: [
|
||||||
...STANDALONE_SHARED_IMPORTS,
|
...STANDALONE_SHARED_IMPORTS,
|
||||||
MatCheckbox,
|
MatCheckbox,
|
||||||
MatStepperPrevious,
|
FaIconComponent
|
||||||
FaIconComponent,
|
|
||||||
MatStepperNext
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ClientDatatableStepComponent implements OnInit {
|
export class ClientDatatableStepComponent implements OnInit {
|
||||||
|
|||||||
+84
-55
@@ -7,63 +7,92 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="mat-typography">
|
<div class="mat-typography">
|
||||||
<h3>{{ 'labels.heading.Family Members' | translate }}</h3>
|
<div class="section-block">
|
||||||
|
<div class="section-header">
|
||||||
|
<h4 class="section-title">
|
||||||
|
<fa-icon icon="users" class="section-icon"></fa-icon>
|
||||||
|
{{ 'labels.heading.Family Members' | translate }}
|
||||||
|
</h4>
|
||||||
|
<button mat-stroked-button color="primary" (click)="addFamilyMember()" class="add-btn">
|
||||||
|
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Add' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="layout-row align-end m-b-20">
|
@if (clientFamilyMembers.length === 0) {
|
||||||
<button mat-raised-button color="primary" (click)="addFamilyMember()">
|
<div class="empty-state">
|
||||||
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Add' | translate }}
|
<fa-icon icon="users" class="empty-icon"></fa-icon>
|
||||||
</button>
|
<span>No family members / nominees added yet.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-accordion>
|
|
||||||
@for (member of clientFamilyMembers; track member; let i = $index) {
|
|
||||||
<mat-expansion-panel class="family-member">
|
|
||||||
<mat-expansion-panel-header>
|
|
||||||
<mat-panel-title>
|
|
||||||
{{ member.firstName }}
|
|
||||||
</mat-panel-title>
|
|
||||||
<mat-panel-description>
|
|
||||||
{{ member.relationshipId | find: clientTemplate.familyMemberOptions.relationshipIdOptions : 'id' : 'name' }}
|
|
||||||
</mat-panel-description>
|
|
||||||
</mat-expansion-panel-header>
|
|
||||||
<mat-divider></mat-divider>
|
|
||||||
<div class="family-member-actions layout-row align-end">
|
|
||||||
<button mat-button color="primary">
|
|
||||||
<fa-icon icon="edit" (click)="editFamilyMember(member, i)"></fa-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-button color="warn" (click)="deleteFamilyMember(member.firstName, i)">
|
|
||||||
<fa-icon icon="trash"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
{{ 'labels.inputs.Nomination Type' | translate }} : {{ member.nominationType }}<br />
|
|
||||||
{{ 'labels.inputs.Nominee Name' | translate }} : {{ member.firstName }}<br />
|
|
||||||
{{ 'labels.inputs.Relationship' | translate }} :
|
|
||||||
{{ member.relationshipId | find: clientTemplate.familyMemberOptions.relationshipIdOptions : 'id' : 'name'
|
|
||||||
}}<br />
|
|
||||||
{{ 'labels.inputs.Date Of Birth' | translate }} : {{ member.dateOfBirth | dateFormat }}<br />
|
|
||||||
{{ 'labels.inputs.Percentage Share' | translate }} : {{ member.percentageShare }}%<br />
|
|
||||||
{{ 'labels.inputs.Nominee is Minor' | translate }} : {{ member.isDependent ? 'Yes' : 'No' }}<br />
|
|
||||||
@if (member.isDependent) {
|
|
||||||
{{ 'labels.inputs.Guardian Name' | translate }} : {{ member.guardianName }}<br />
|
|
||||||
{{ 'labels.inputs.Relationship with Minor' | translate }} : {{ member.guardianRelationship }}<br />
|
|
||||||
}
|
|
||||||
@if (member.remarks) {
|
|
||||||
{{ 'labels.inputs.Remarks' | translate }} : {{ member.remarks }}<br />
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</mat-expansion-panel>
|
|
||||||
}
|
}
|
||||||
</mat-accordion>
|
|
||||||
|
|
||||||
<div class="layout-row align-center gap-2percent margin-t responsive-column">
|
<mat-accordion>
|
||||||
<button mat-raised-button matStepperPrevious>
|
@for (member of clientFamilyMembers; track member; let i = $index) {
|
||||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
<mat-expansion-panel class="member-panel">
|
||||||
{{ 'labels.buttons.Previous' | translate }}
|
<mat-expansion-panel-header>
|
||||||
</button>
|
<mat-panel-title>
|
||||||
<button mat-raised-button matStepperNext>
|
<fa-icon icon="user" class="panel-icon"></fa-icon>
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
{{ member.firstName }}
|
||||||
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
|
</mat-panel-title>
|
||||||
</button>
|
<mat-panel-description>
|
||||||
|
{{ member.relationshipId | find: clientTemplate.familyMemberOptions.relationshipIdOptions : 'id' : 'name' }}
|
||||||
|
</mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
|
<div class="member-actions">
|
||||||
|
<button mat-button color="primary" (click)="editFamilyMember(member, i)">
|
||||||
|
<fa-icon icon="edit"></fa-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-button color="warn" (click)="deleteFamilyMember(member.firstName, i)">
|
||||||
|
<fa-icon icon="trash"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="member-details">
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Nomination Type' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.nominationType }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Nominee Name' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.firstName }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Relationship' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.relationshipId | find: clientTemplate.familyMemberOptions.relationshipIdOptions : 'id' : 'name' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Date Of Birth' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.dateOfBirth | dateFormat }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Percentage Share' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.percentageShare }}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Nominee is Minor' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.isDependent ? 'Yes' : 'No' }}</span>
|
||||||
|
</div>
|
||||||
|
@if (member.isDependent) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Guardian Name' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.guardianName }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Relationship with Minor' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.guardianRelationship }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (member.remarks) {
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">{{ 'labels.inputs.Remarks' | translate }}</span>
|
||||||
|
<span class="detail-value">{{ member.remarks }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
}
|
||||||
|
</mat-accordion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+91
-15
@@ -6,25 +6,101 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.family-member {
|
.section-block {
|
||||||
.family-member-actions {
|
margin-bottom: 8px;
|
||||||
margin-top: 1%;
|
}
|
||||||
|
|
||||||
button {
|
.section-header {
|
||||||
margin-right: 1%;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
.section-title {
|
||||||
margin: 1% auto;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
p {
|
.section-icon {
|
||||||
line-height: 30px;
|
color: var(--md-sys-color-primary, #1074b9);
|
||||||
margin-left: 2%;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.margin-t {
|
.add-btn {
|
||||||
margin-top: 2em;
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 24px 16px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-size: 14px;
|
||||||
|
background: rgba(0, 0, 0, 0.02);
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px dashed rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-panel {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.panel-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 4px;
|
||||||
|
margin: 8px 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-details {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px 24px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.section-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-details {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -23,7 +23,7 @@ import {
|
|||||||
MatExpansionPanelDescription
|
MatExpansionPanelDescription
|
||||||
} from '@angular/material/expansion';
|
} from '@angular/material/expansion';
|
||||||
import { MatDivider } from '@angular/material/divider';
|
import { MatDivider } from '@angular/material/divider';
|
||||||
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
|
|
||||||
import { FindPipe } from '../../../pipes/find.pipe';
|
import { FindPipe } from '../../../pipes/find.pipe';
|
||||||
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
|
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
|
||||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||||
@@ -44,8 +44,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
MatExpansionPanelTitle,
|
MatExpansionPanelTitle,
|
||||||
MatExpansionPanelDescription,
|
MatExpansionPanelDescription,
|
||||||
MatDivider,
|
MatDivider,
|
||||||
MatStepperPrevious,
|
|
||||||
MatStepperNext,
|
|
||||||
FindPipe,
|
FindPipe,
|
||||||
DateFormatPipe
|
DateFormatPipe
|
||||||
]
|
]
|
||||||
|
|||||||
+287
-302
@@ -7,230 +7,228 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<form [formGroup]="createClientForm">
|
<form [formGroup]="createClientForm">
|
||||||
<div class="layout-row-wrap gap-2px responsive-column">
|
<!-- Section: Basic Information -->
|
||||||
<mat-form-field class="flex-fill flex-23">
|
<div class="section-block">
|
||||||
<mat-label>{{ 'labels.inputs.Office' | translate }}</mat-label>
|
<h4 class="section-title">
|
||||||
<mat-select required formControlName="officeId">
|
<fa-icon icon="briefcase" class="section-icon"></fa-icon>
|
||||||
@for (office of officeOptions; track office) {
|
{{ 'labels.inputs.Basic Information' | translate }}
|
||||||
<mat-option [value]="office.id">
|
</h4>
|
||||||
{{ office.name }}
|
<div class="form-grid">
|
||||||
</mat-option>
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
}
|
<mat-label>{{ 'labels.inputs.Office' | translate }}</mat-label>
|
||||||
</mat-select>
|
<mat-select required formControlName="officeId">
|
||||||
@if (createClientForm.controls.officeId.hasError('required')) {
|
@for (office of officeOptions; track office) {
|
||||||
<mat-error>
|
<mat-option [value]="office.id">{{ office.name }}</mat-option>
|
||||||
{{ 'labels.inputs.Office' | translate }} {{ 'labels.commons.is' | translate }}
|
}
|
||||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
</mat-select>
|
||||||
</mat-error>
|
@if (createClientForm.controls.officeId.hasError('required')) {
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="flex-fill flex-23">
|
|
||||||
<mat-label>{{ 'labels.inputs.Legal Form' | translate }}</mat-label>
|
|
||||||
<mat-select required formControlName="legalFormId">
|
|
||||||
@for (legalForm of legalFormOptions; track legalForm) {
|
|
||||||
<mat-option [value]="legalForm.id">
|
|
||||||
{{ legalForm.value | translateKey: 'inputs' }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="flex-fill flex-23">
|
|
||||||
<mat-label>{{ 'labels.inputs.External Id' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="externalId" />
|
|
||||||
@if (!externalNationalIdService.isLoading && externalNationalIdService.statusMessageKey) {
|
|
||||||
<mat-hint>
|
|
||||||
<span
|
|
||||||
class="external-id-status"
|
|
||||||
[ngClass]="{
|
|
||||||
success: externalNationalIdService.statusMessageKey === 'External ID verified successfully',
|
|
||||||
error: externalNationalIdService.statusMessageKey !== 'External ID verified successfully'
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ 'labels.inputs.' + externalNationalIdService.statusMessageKey | translate }}
|
|
||||||
</span>
|
|
||||||
</mat-hint>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
@if (createClientForm.get('fullname')) {
|
|
||||||
<mat-form-field class="flex-48">
|
|
||||||
<mat-label>
|
|
||||||
{{ 'labels.inputs.' + getDateLabel(createClientForm.value.legalFormId, ['Name', 'Entity Name']) | translate }}
|
|
||||||
</mat-label>
|
|
||||||
<input matInput required formControlName="fullname" />
|
|
||||||
@if (createClientForm.controls.fullname.hasError('required')) {
|
|
||||||
<mat-error>
|
<mat-error>
|
||||||
{{ 'labels.inputs.Client name' | translate }} {{ 'labels.commons.is' | translate }}
|
{{ 'labels.inputs.Office' | translate }} {{ 'labels.commons.is' | translate }}
|
||||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||||
</mat-error>
|
</mat-error>
|
||||||
}
|
}
|
||||||
@if (createClientForm.controls.fullname.hasError('pattern')) {
|
</mat-form-field>
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Client name' | translate }} <strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
{{ 'labels.commons.begin with a special character or number' | translate }}
|
<mat-label>{{ 'labels.inputs.Legal Form' | translate }}</mat-label>
|
||||||
</mat-error>
|
<mat-select required formControlName="legalFormId">
|
||||||
|
@for (legalForm of legalFormOptions; track legalForm) {
|
||||||
|
<mat-option [value]="legalForm.id">{{ legalForm.value | translateKey: 'inputs' }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.External Id' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="externalId" />
|
||||||
|
@if (!externalNationalIdService.isLoading && externalNationalIdService.statusMessageKey) {
|
||||||
|
<mat-hint>
|
||||||
|
<span class="external-id-status"
|
||||||
|
[ngClass]="{
|
||||||
|
success: externalNationalIdService.statusMessageKey === 'External ID verified successfully',
|
||||||
|
error: externalNationalIdService.statusMessageKey !== 'External ID verified successfully'
|
||||||
|
}">
|
||||||
|
{{ 'labels.inputs.' + externalNationalIdService.statusMessageKey | translate }}
|
||||||
|
</span>
|
||||||
|
</mat-hint>
|
||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
}
|
|
||||||
|
|
||||||
@if (createClientForm.get('firstname') || createClientForm.get('middlename') || createClientForm.get('lastname')) {
|
</div>
|
||||||
<div class="name-fields-row">
|
</div>
|
||||||
@if (createClientForm.get('firstname')) {
|
|
||||||
<mat-form-field class="name-field first-name">
|
|
||||||
<mat-label>{{ 'labels.inputs.First Name' | translate }}</mat-label>
|
|
||||||
<input matInput required formControlName="firstname" />
|
|
||||||
@if (createClientForm.controls.firstname.hasError('required')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Client first name' | translate }} {{ 'labels.commons.is' | translate }}
|
|
||||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
|
||||||
</mat-error>
|
|
||||||
}
|
|
||||||
@if (createClientForm.controls.firstname.hasError('pattern')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Client first name' | translate }}
|
|
||||||
<strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
|
||||||
{{ 'labels.commons.begin with a special character or number' | translate }}
|
|
||||||
</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
}
|
|
||||||
@if (createClientForm.get('middlename')) {
|
|
||||||
<mat-form-field class="name-field middle-name">
|
|
||||||
<mat-label>{{ 'labels.inputs.Middle Name' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="middlename" />
|
|
||||||
@if (createClientForm.controls.middlename.hasError('pattern')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Client middle name' | translate }}
|
|
||||||
<strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
|
||||||
{{ 'labels.commons.begin with a special character or number' | translate }}
|
|
||||||
</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
}
|
|
||||||
@if (createClientForm.get('lastname')) {
|
|
||||||
<mat-form-field class="name-field last-name">
|
|
||||||
<mat-label>{{ 'labels.inputs.Last Name' | translate }}</mat-label>
|
|
||||||
<input matInput required formControlName="lastname" />
|
|
||||||
@if (createClientForm.controls.lastname.hasError('required')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Client last name' | translate }} {{ 'labels.commons.is' | translate }}
|
|
||||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
|
||||||
</mat-error>
|
|
||||||
}
|
|
||||||
@if (createClientForm.controls.lastname.hasError('pattern')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Client last name' | translate }}
|
|
||||||
<strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
|
||||||
{{ 'labels.commons.begin with a special character or number' | translate }}
|
|
||||||
</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<mat-divider></mat-divider>
|
<!-- Section: Client Name -->
|
||||||
|
<div class="section-block">
|
||||||
|
<h4 class="section-title">
|
||||||
|
<fa-icon icon="user" class="section-icon"></fa-icon>
|
||||||
|
{{ 'labels.inputs.Client Details' | translate }}
|
||||||
|
</h4>
|
||||||
|
<div class="form-grid">
|
||||||
|
@if (createClientForm.get('fullname')) {
|
||||||
|
<mat-form-field appearance="outline" class="form-field full-width">
|
||||||
|
<mat-label>
|
||||||
|
{{ 'labels.inputs.' + getDateLabel(createClientForm.value.legalFormId, ['Name', 'Entity Name']) | translate }}
|
||||||
|
</mat-label>
|
||||||
|
<input matInput required formControlName="fullname" />
|
||||||
|
@if (createClientForm.controls.fullname.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Client name' | translate }} {{ 'labels.commons.is' | translate }}
|
||||||
|
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
@if (createClientForm.controls.fullname.hasError('pattern')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Client name' | translate }} <strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
||||||
|
{{ 'labels.commons.begin with a special character or number' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
|
||||||
<mat-form-field class="flex-48" (click)="dateOfBirthDatePicker.open()">
|
@if (createClientForm.get('firstname') || createClientForm.get('middlename') || createClientForm.get('lastname')) {
|
||||||
<mat-label>
|
<div class="name-fields-row">
|
||||||
{{
|
@if (createClientForm.get('firstname')) {
|
||||||
'labels.inputs.' + getDateLabel(createClientForm.value.legalFormId, ['Date of Birth', 'Incorporation Date'])
|
<mat-form-field appearance="outline" class="name-field first-name">
|
||||||
| translate
|
<mat-label>{{ 'labels.inputs.First Name' | translate }}</mat-label>
|
||||||
}}
|
<input matInput required formControlName="firstname" />
|
||||||
</mat-label>
|
@if (createClientForm.controls.firstname.hasError('required')) {
|
||||||
<input matInput [max]="maxDate" [matDatepicker]="dateOfBirthDatePicker" formControlName="dateOfBirth" />
|
<mat-error>
|
||||||
<mat-datepicker-toggle matSuffix [for]="dateOfBirthDatePicker"></mat-datepicker-toggle>
|
{{ 'labels.inputs.Client first name' | translate }} {{ 'labels.commons.is' | translate }}
|
||||||
<mat-datepicker #dateOfBirthDatePicker></mat-datepicker>
|
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||||
</mat-form-field>
|
</mat-error>
|
||||||
|
}
|
||||||
|
@if (createClientForm.controls.firstname.hasError('pattern')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Client first name' | translate }}
|
||||||
|
<strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
||||||
|
{{ 'labels.commons.begin with a special character or number' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
@if (createClientForm.get('middlename')) {
|
||||||
|
<mat-form-field appearance="outline" class="name-field middle-name">
|
||||||
|
<mat-label>{{ 'labels.inputs.Middle Name' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="middlename" />
|
||||||
|
@if (createClientForm.controls.middlename.hasError('pattern')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Client middle name' | translate }}
|
||||||
|
<strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
||||||
|
{{ 'labels.commons.begin with a special character or number' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
@if (createClientForm.get('lastname')) {
|
||||||
|
<mat-form-field appearance="outline" class="name-field last-name">
|
||||||
|
<mat-label>{{ 'labels.inputs.Last Name' | translate }}</mat-label>
|
||||||
|
<input matInput required formControlName="lastname" />
|
||||||
|
@if (createClientForm.controls.lastname.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Client last name' | translate }} {{ 'labels.commons.is' | translate }}
|
||||||
|
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
@if (createClientForm.controls.lastname.hasError('pattern')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Client last name' | translate }}
|
||||||
|
<strong>{{ 'labels.inputs.cannot' | translate }}</strong>
|
||||||
|
{{ 'labels.commons.begin with a special character or number' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field" (click)="dateOfBirthDatePicker.open()">
|
||||||
|
<mat-label>
|
||||||
|
{{ 'labels.inputs.' + getDateLabel(createClientForm.value.legalFormId, ['Date of Birth', 'Incorporation Date']) | translate }}
|
||||||
|
</mat-label>
|
||||||
|
<input matInput [max]="maxDate" [matDatepicker]="dateOfBirthDatePicker" formControlName="dateOfBirth" />
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="dateOfBirthDatePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #dateOfBirthDatePicker></mat-datepicker>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
@if (createClientForm.value.legalFormId === LegalFormId.PERSON) {
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.Gender' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="genderId">
|
||||||
|
@for (gender of genderOptions; track gender) {
|
||||||
|
<mat-option [value]="gender.id">{{ gender.name }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.Staff' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="staffId">
|
||||||
|
@for (staff of staffOptions; track staff) {
|
||||||
|
<mat-option [value]="staff.id">{{ staff.displayName }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
@if (createClientForm.value.legalFormId === LegalFormId.PERSON) {
|
||||||
|
<div class="form-field checkbox-field">
|
||||||
|
<mat-checkbox labelPosition="after" formControlName="isStaff">
|
||||||
|
{{ 'labels.inputs.Is staff' | translate }}?
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Entity Non-Person Details -->
|
||||||
@if (createClientForm.get('clientNonPersonDetails')) {
|
@if (createClientForm.get('clientNonPersonDetails')) {
|
||||||
<div class="flex-100 layout-row-wrap responsive-column gap-4percent" formGroupName="clientNonPersonDetails">
|
<div class="form-grid" formGroupName="clientNonPersonDetails">
|
||||||
<mat-form-field class="flex-48">
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
<mat-label>{{ 'labels.inputs.Constitution' | translate }}</mat-label>
|
<mat-label>{{ 'labels.inputs.Constitution' | translate }}</mat-label>
|
||||||
<mat-select formControlName="constitutionId" required>
|
<mat-select formControlName="constitutionId" required>
|
||||||
@for (constitution of constitutionOptions; track constitution) {
|
@for (constitution of constitutionOptions; track constitution) {
|
||||||
<mat-option [value]="constitution.id">
|
<mat-option [value]="constitution.id">{{ constitution.name }}</mat-option>
|
||||||
{{ constitution.name }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-48">
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
<mat-label>{{ 'labels.inputs.Main Business Line' | translate }}</mat-label>
|
<mat-label>{{ 'labels.inputs.Main Business Line' | translate }}</mat-label>
|
||||||
<mat-select formControlName="mainBusinessLineId">
|
<mat-select formControlName="mainBusinessLineId">
|
||||||
@for (business of businessLineOptions; track business) {
|
@for (business of businessLineOptions; track business) {
|
||||||
<mat-option [value]="business.id">
|
<mat-option [value]="business.id">{{ business.name }}</mat-option>
|
||||||
{{ business.name }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-48" (click)="incorpValidityTillDateDatePicker.open()">
|
<mat-form-field appearance="outline" class="form-field" (click)="incorpValidityTillDateDatePicker.open()">
|
||||||
<mat-label>{{ 'labels.inputs.Incorporation Validity Till Date' | translate }}</mat-label>
|
<mat-label>{{ 'labels.inputs.Incorporation Validity Till Date' | translate }}</mat-label>
|
||||||
<input
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="incorpValidityTillDateDatePicker" formControlName="incorpValidityTillDate" />
|
||||||
matInput
|
|
||||||
[min]="minDate"
|
|
||||||
[max]="maxDate"
|
|
||||||
[matDatepicker]="incorpValidityTillDateDatePicker"
|
|
||||||
formControlName="incorpValidityTillDate"
|
|
||||||
/>
|
|
||||||
<mat-datepicker-toggle matSuffix [for]="incorpValidityTillDateDatePicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="incorpValidityTillDateDatePicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #incorpValidityTillDateDatePicker></mat-datepicker>
|
<mat-datepicker #incorpValidityTillDateDatePicker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-48">
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
<mat-label>{{ 'labels.inputs.Incorporation Number' | translate }}</mat-label>
|
<mat-label>{{ 'labels.inputs.Incorporation Number' | translate }}</mat-label>
|
||||||
<input matInput formControlName="incorpNumber" />
|
<input matInput formControlName="incorpNumber" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-98">
|
<mat-form-field appearance="outline" class="form-field full-width">
|
||||||
<mat-label>{{ 'labels.inputs.Remarks' | translate }}</mat-label>
|
<mat-label>{{ 'labels.inputs.Remarks' | translate }}</mat-label>
|
||||||
<textarea matInput formControlName="remarks" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
|
<textarea matInput formControlName="remarks" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
@if (createClientForm.value.legalFormId === LegalFormId.PERSON) {
|
<!-- Section: Verification -->
|
||||||
<mat-form-field class="flex-48">
|
<div class="section-block">
|
||||||
<mat-label>{{ 'labels.inputs.Gender' | translate }}</mat-label>
|
<h4 class="section-title">
|
||||||
<mat-select formControlName="genderId">
|
<fa-icon icon="shield-alt" class="section-icon"></fa-icon>
|
||||||
@for (gender of genderOptions; track gender) {
|
{{ 'labels.inputs.Verification' | translate }}
|
||||||
<mat-option [value]="gender.id">
|
</h4>
|
||||||
{{ gender.name }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
}
|
|
||||||
|
|
||||||
<mat-form-field class="flex-48">
|
<div class="sanctions-verify-section">
|
||||||
<mat-label>{{ 'labels.inputs.Staff' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="staffId">
|
|
||||||
@for (staff of staffOptions; track staff) {
|
|
||||||
<mat-option [value]="staff.id">
|
|
||||||
{{ staff.displayName }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
@if (createClientForm.value.legalFormId === LegalFormId.PERSON) {
|
|
||||||
<mat-checkbox class="flex-48 margin-v" labelPosition="before" formControlName="isStaff">
|
|
||||||
{{ 'labels.inputs.Is staff' | translate }}?
|
|
||||||
</mat-checkbox>
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="sanctions-verify-section flex-98">
|
|
||||||
@if (!sanctionsVerified && !sanctionsBlocked) {
|
@if (!sanctionsVerified && !sanctionsBlocked) {
|
||||||
<button
|
<button mat-stroked-button color="primary" type="button" class="verify-client-btn"
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
type="button"
|
|
||||||
class="verify-client-btn"
|
|
||||||
[disabled]="!createClientForm.get('firstname')?.value && !createClientForm.get('fullname')?.value"
|
[disabled]="!createClientForm.get('firstname')?.value && !createClientForm.get('fullname')?.value"
|
||||||
(click)="verifySanctions()"
|
(click)="verifySanctions()">
|
||||||
>
|
<fa-icon icon="shield-alt" class="m-r-10"></fa-icon>
|
||||||
<fa-icon icon="shield-alt" class="mr-05"></fa-icon>
|
|
||||||
Verify Client
|
Verify Client
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@@ -253,145 +251,132 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-divider class="flex-98"></mat-divider>
|
<div class="dip-info">
|
||||||
|
<mat-icon class="dip-info-icon"
|
||||||
<div class="dip-info flex-98">
|
|
||||||
<mat-icon
|
|
||||||
class="dip-info-icon"
|
|
||||||
matTooltip="Digital Intelligence Platform (DIP) refers to the fraud-monitoring and intelligence ecosystem created by the Department of Telecommunications (DoT)"
|
matTooltip="Digital Intelligence Platform (DIP) refers to the fraud-monitoring and intelligence ecosystem created by the Department of Telecommunications (DoT)"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above">info</mat-icon>
|
||||||
>info</mat-icon
|
|
||||||
>
|
|
||||||
<span class="dip-info-text">DIP Verification</span>
|
<span class="dip-info-text">DIP Verification</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mobile-verify-row flex-48">
|
<div class="mobile-verify-row">
|
||||||
<mat-form-field class="mobile-field">
|
<mat-form-field appearance="outline" class="mobile-field">
|
||||||
<mat-label>{{ 'labels.inputs.Mobile No' | translate }}</mat-label>
|
<mat-label>{{ 'labels.inputs.Mobile No' | translate }}</mat-label>
|
||||||
<input matInput type="text" formControlName="mobileNo" />
|
<input matInput type="text" formControlName="mobileNo" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
@if (!mobileVerified) {
|
@if (!mobileVerified) {
|
||||||
<button
|
<button mat-stroked-button color="primary" type="button" class="verify-btn"
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
type="button"
|
|
||||||
class="verify-btn"
|
|
||||||
[disabled]="!createClientForm.get('mobileNo').value"
|
[disabled]="!createClientForm.get('mobileNo').value"
|
||||||
(click)="verifyWithDIP()"
|
(click)="verifyWithDIP()">
|
||||||
>
|
|
||||||
Verify with DIP
|
Verify with DIP
|
||||||
</button>
|
</button>
|
||||||
} @else {
|
} @else {
|
||||||
<span class="text-success verified-label">✔ Verified</span>
|
<span class="text-success verified-label">✔ Verified</span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<mat-form-field class="flex-48">
|
<!-- Section: Contact & Classification -->
|
||||||
<mat-label>{{ 'labels.inputs.Email Address' | translate }}</mat-label>
|
<div class="section-block">
|
||||||
<input matInput formControlName="emailAddress" />
|
<h4 class="section-title">
|
||||||
@if (createClientForm.controls.emailAddress.errors?.email) {
|
<fa-icon icon="envelope" class="section-icon"></fa-icon>
|
||||||
<mat-error>
|
{{ 'labels.inputs.Contact & Classification' | translate }}
|
||||||
{{ 'error.Email not valid' | translate }}
|
</h4>
|
||||||
</mat-error>
|
<div class="form-grid">
|
||||||
}
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
</mat-form-field>
|
<mat-label>{{ 'labels.inputs.Email Address' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="emailAddress" />
|
||||||
<mat-form-field class="flex-48">
|
@if (createClientForm.controls.emailAddress.errors?.email) {
|
||||||
<mat-label>{{ 'labels.inputs.Client Type' | translate }}</mat-label>
|
<mat-error>{{ 'error.Email not valid' | translate }}</mat-error>
|
||||||
<mat-select formControlName="clientTypeId">
|
|
||||||
@for (clientType of clientTypeOptions; track clientType) {
|
|
||||||
<mat-option [value]="clientType.id">
|
|
||||||
{{ clientType.name }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="flex-48">
|
|
||||||
<mat-label>{{ 'labels.inputs.Client Classification' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="clientClassificationId">
|
|
||||||
@for (clientClassification of clientClassificationTypeOptions; track clientClassification) {
|
|
||||||
<mat-option [value]="clientClassification.id">
|
|
||||||
{{ clientClassification.name }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="flex-48" (click)="submittedOnDatePicker.open()">
|
|
||||||
<mat-label>{{ 'labels.inputs.Submitted On' | translate }}</mat-label>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
[min]="minDate"
|
|
||||||
[max]="maxDate"
|
|
||||||
[matDatepicker]="submittedOnDatePicker"
|
|
||||||
formControlName="submittedOnDate"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<mat-datepicker-toggle matSuffix [for]="submittedOnDatePicker"></mat-datepicker-toggle>
|
|
||||||
<mat-datepicker #submittedOnDatePicker></mat-datepicker>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<mat-checkbox labelPosition="before" formControlName="active" class="margin-v flex-48">
|
|
||||||
{{ 'labels.inputs.Active' | translate }}?
|
|
||||||
</mat-checkbox>
|
|
||||||
|
|
||||||
@if (createClientForm.contains('activationDate')) {
|
|
||||||
<mat-form-field class="flex-48" (click)="activatedOnDatePicker.open()">
|
|
||||||
<mat-label>{{ 'labels.inputs.Activation Date' | translate }}</mat-label>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
[min]="createClientForm.value.submittedOnDate"
|
|
||||||
[max]="maxDate"
|
|
||||||
[matDatepicker]="activatedOnDatePicker"
|
|
||||||
required
|
|
||||||
formControlName="activationDate"
|
|
||||||
/>
|
|
||||||
<mat-datepicker-toggle matSuffix [for]="activatedOnDatePicker"></mat-datepicker-toggle>
|
|
||||||
<mat-datepicker #activatedOnDatePicker></mat-datepicker>
|
|
||||||
@if (createClientForm.controls.activationDate.hasError('required')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Activation Date' | translate }} {{ 'labels.commons.is' | translate }}
|
|
||||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
|
||||||
</mat-error>
|
|
||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
}
|
|
||||||
|
|
||||||
<mat-checkbox labelPosition="before" formControlName="addSavings" class="margin-v flex-48">
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
{{ 'labels.inputs.Open Savings Account' | translate }}?
|
<mat-label>{{ 'labels.inputs.Client Type' | translate }}</mat-label>
|
||||||
</mat-checkbox>
|
<mat-select formControlName="clientTypeId">
|
||||||
|
@for (clientType of clientTypeOptions; track clientType) {
|
||||||
@if (createClientForm.contains('savingsProductId')) {
|
<mat-option [value]="clientType.id">{{ clientType.name }}</mat-option>
|
||||||
<mat-form-field class="flex-48">
|
|
||||||
<mat-label>{{ 'labels.inputs.Savings Product' | translate }}</mat-label>
|
|
||||||
<mat-select required formControlName="savingsProductId">
|
|
||||||
@for (product of savingProductOptions; track product) {
|
|
||||||
<mat-option [value]="product.id">
|
|
||||||
{{ product.name }}
|
|
||||||
</mat-option>
|
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
@if (createClientForm.controls.savingsProductId.hasError('required')) {
|
|
||||||
<mat-error>
|
|
||||||
{{ 'labels.inputs.Savings Product' | translate }} {{ 'labels.commons.is' | translate }}
|
|
||||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
|
||||||
</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="layout-row align-center gap-2percent margin-t responsive-column">
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
<button mat-raised-button matStepperPrevious disabled>
|
<mat-label>{{ 'labels.inputs.Client Classification' | translate }}</mat-label>
|
||||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
<mat-select formControlName="clientClassificationId">
|
||||||
{{ 'labels.buttons.Previous' | translate }}
|
@for (clientClassification of clientClassificationTypeOptions; track clientClassification) {
|
||||||
</button>
|
<mat-option [value]="clientClassification.id">{{ clientClassification.name }}</mat-option>
|
||||||
<button mat-raised-button matStepperNext [disabled]="sanctionsBlocked">
|
}
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
</mat-select>
|
||||||
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
|
</mat-form-field>
|
||||||
</button>
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.Occupation Category' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="occupationCategoryId">
|
||||||
|
@for (cat of occupationCategoryOptions; track cat) {
|
||||||
|
<mat-option [value]="cat.id">{{ cat.name }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.Occupation' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="occupationId">
|
||||||
|
@for (occ of occupationOptions; track occ) {
|
||||||
|
<mat-option [value]="occ.id">{{ occ.name }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field" (click)="submittedOnDatePicker.open()">
|
||||||
|
<mat-label>{{ 'labels.inputs.Submitted On' | translate }}</mat-label>
|
||||||
|
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="submittedOnDatePicker" formControlName="submittedOnDate" required />
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="submittedOnDatePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #submittedOnDatePicker></mat-datepicker>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<div class="form-field checkbox-field">
|
||||||
|
<mat-checkbox labelPosition="after" formControlName="active">
|
||||||
|
{{ 'labels.inputs.Active' | translate }}?
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (createClientForm.contains('activationDate')) {
|
||||||
|
<mat-form-field appearance="outline" class="form-field" (click)="activatedOnDatePicker.open()">
|
||||||
|
<mat-label>{{ 'labels.inputs.Activation Date' | translate }}</mat-label>
|
||||||
|
<input matInput [min]="createClientForm.value.submittedOnDate" [max]="maxDate"
|
||||||
|
[matDatepicker]="activatedOnDatePicker" required formControlName="activationDate" />
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="activatedOnDatePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #activatedOnDatePicker></mat-datepicker>
|
||||||
|
@if (createClientForm.controls.activationDate.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Activation Date' | translate }} {{ 'labels.commons.is' | translate }}
|
||||||
|
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="form-field checkbox-field">
|
||||||
|
<mat-checkbox labelPosition="after" formControlName="addSavings">
|
||||||
|
{{ 'labels.inputs.Open Savings Account' | translate }}?
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (createClientForm.contains('savingsProductId')) {
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.Savings Product' | translate }}</mat-label>
|
||||||
|
<mat-select required formControlName="savingsProductId">
|
||||||
|
@for (product of savingProductOptions; track product) {
|
||||||
|
<mat-option [value]="product.id">{{ product.name }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
@if (createClientForm.controls.savingsProductId.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
{{ 'labels.inputs.Savings Product' | translate }} {{ 'labels.commons.is' | translate }}
|
||||||
|
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+112
-163
@@ -7,191 +7,80 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
form {
|
form {
|
||||||
padding: 16px 0;
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.layout-row-wrap {
|
.section-block {
|
||||||
gap: 8px !important;
|
margin-bottom: 24px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-form-field {
|
.section-title {
|
||||||
margin-bottom: 8px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
|
||||||
|
.section-icon {
|
||||||
|
color: var(--md-sys-color-primary, #1074b9);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-divider {
|
.form-grid {
|
||||||
margin: 16px 0;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 4px 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.margin-v {
|
.form-field {
|
||||||
margin: 2em 0 0;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.margin-t {
|
.full-width {
|
||||||
margin-top: 2em;
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-field {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name-fields-row {
|
.name-fields-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 12px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 8px;
|
grid-column: 1 / -1;
|
||||||
|
|
||||||
.name-field {
|
.name-field {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 200px;
|
min-width: 180px;
|
||||||
|
|
||||||
&.first-name,
|
&.first-name,
|
||||||
&.last-name {
|
&.last-name {
|
||||||
flex: 1.2;
|
flex: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.middle-name {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (width <= 768px) {
|
|
||||||
.name-fields-row {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
.name-field {
|
|
||||||
width: 100%;
|
|
||||||
min-width: unset;
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.name-fields-row + mat-form-field,
|
|
||||||
.name-fields-row + mat-divider,
|
|
||||||
.name-fields-row + div {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-row.align-center {
|
|
||||||
padding-top: 16px;
|
|
||||||
margin-top: 12px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin: 0 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-100 {
|
|
||||||
margin: 16px 0;
|
|
||||||
padding: 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-checkbox {
|
|
||||||
margin: 8px 0;
|
|
||||||
|
|
||||||
&.margin-v {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (width <= 768px) {
|
|
||||||
form {
|
|
||||||
padding: 12px 0;
|
|
||||||
|
|
||||||
.layout-row-wrap {
|
|
||||||
gap: 6px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-form-field {
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-divider {
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-row.align-center {
|
|
||||||
padding-top: 12px;
|
|
||||||
margin-top: 8px;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
margin: 2px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dip-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
|
|
||||||
.dip-info-icon {
|
|
||||||
font-size: 18px;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
color: #1976d2;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dip-info-text {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-verify-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
.mobile-field {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verify-btn {
|
|
||||||
height: 40px;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-size: 13px;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verified-label {
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-success {
|
|
||||||
color: #388e3c;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Verification Section */
|
||||||
.sanctions-verify-section {
|
.sanctions-verify-section {
|
||||||
margin: 12px 0;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
.verify-client-btn {
|
.verify-client-btn {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sanctions-progress {
|
|
||||||
mat-progress-bar {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sanctions-msg {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #555;
|
|
||||||
line-height: 1.5;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sanctions-result {
|
.sanctions-result {
|
||||||
@@ -216,7 +105,6 @@ mat-checkbox {
|
|||||||
border-left: 4px solid #d32f2f;
|
border-left: 4px solid #d32f2f;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
margin: 12px 0;
|
|
||||||
|
|
||||||
.text-danger {
|
.text-danger {
|
||||||
color: #d32f2f;
|
color: #d32f2f;
|
||||||
@@ -230,14 +118,60 @@ mat-checkbox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dip-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.dip-info-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
color: #1976d2;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dip-info-text {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-verify-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.mobile-field {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-btn {
|
||||||
|
height: 40px;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verified-label {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-success {
|
||||||
|
color: #388e3c;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.external-id-status {
|
.external-id-status {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
&.loading {
|
|
||||||
color: #1976d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.success {
|
&.success {
|
||||||
color: #388e3c;
|
color: #388e3c;
|
||||||
}
|
}
|
||||||
@@ -247,12 +181,27 @@ mat-checkbox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (width <= 480px) {
|
@media (max-width: 768px) {
|
||||||
form {
|
.form-grid {
|
||||||
padding: 8px 0;
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.layout-row-wrap {
|
.name-fields-row {
|
||||||
gap: 4px !important;
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.name-field {
|
||||||
|
min-width: unset;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-verify-row {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
.mobile-field {
|
||||||
|
max-width: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { SettingsService } from 'app/settings/settings.service';
|
|||||||
import { MatDivider } from '@angular/material/divider';
|
import { MatDivider } from '@angular/material/divider';
|
||||||
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
|
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
|
||||||
import { MatCheckbox } from '@angular/material/checkbox';
|
import { MatCheckbox } from '@angular/material/checkbox';
|
||||||
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
|
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
import { MatIcon } from '@angular/material/icon';
|
import { MatIcon } from '@angular/material/icon';
|
||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
@@ -49,9 +49,7 @@ import { DipVerifyDialogComponent } from './dip-verify-dialog.component';
|
|||||||
MatDivider,
|
MatDivider,
|
||||||
CdkTextareaAutosize,
|
CdkTextareaAutosize,
|
||||||
MatCheckbox,
|
MatCheckbox,
|
||||||
MatStepperPrevious,
|
|
||||||
FaIconComponent,
|
FaIconComponent,
|
||||||
MatStepperNext,
|
|
||||||
MatIcon,
|
MatIcon,
|
||||||
MatTooltip
|
MatTooltip
|
||||||
]
|
]
|
||||||
@@ -100,6 +98,10 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy {
|
|||||||
genderOptions: any;
|
genderOptions: any;
|
||||||
/** Saving Product Options */
|
/** Saving Product Options */
|
||||||
savingProductOptions: any;
|
savingProductOptions: any;
|
||||||
|
/** Occupation Category Options */
|
||||||
|
occupationCategoryOptions: any;
|
||||||
|
/** Occupation Options */
|
||||||
|
occupationOptions: any;
|
||||||
/** Mobile number DIP verification status */
|
/** Mobile number DIP verification status */
|
||||||
mobileVerified = false;
|
mobileVerified = false;
|
||||||
/** Sanctions verification state */
|
/** Sanctions verification state */
|
||||||
@@ -152,6 +154,8 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy {
|
|||||||
dateOfBirth: [''],
|
dateOfBirth: [''],
|
||||||
clientTypeId: [''],
|
clientTypeId: [''],
|
||||||
clientClassificationId: [''],
|
clientClassificationId: [''],
|
||||||
|
occupationCategoryId: [''],
|
||||||
|
occupationId: [''],
|
||||||
submittedOnDate: [
|
submittedOnDate: [
|
||||||
this.settingsService.businessDate,
|
this.settingsService.businessDate,
|
||||||
Validators.required
|
Validators.required
|
||||||
@@ -172,6 +176,8 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy {
|
|||||||
this.constitutionOptions = this.clientTemplate.clientNonPersonConstitutionOptions;
|
this.constitutionOptions = this.clientTemplate.clientNonPersonConstitutionOptions;
|
||||||
this.genderOptions = this.clientTemplate.genderOptions;
|
this.genderOptions = this.clientTemplate.genderOptions;
|
||||||
this.savingProductOptions = this.clientTemplate.savingProductOptions;
|
this.savingProductOptions = this.clientTemplate.savingProductOptions;
|
||||||
|
this.occupationCategoryOptions = this.clientTemplate.occupationCategoryOptions || [];
|
||||||
|
this.occupationOptions = this.clientTemplate.occupationOptions || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,111 +7,59 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="mat-typography" [formGroup]="kycForm">
|
<div class="mat-typography" [formGroup]="kycForm">
|
||||||
<div class="kyc-header">
|
<div class="section-block">
|
||||||
<h3>{{ 'labels.inputs.KYC Verification' | translate }}</h3>
|
<h4 class="section-title">
|
||||||
<span class="kyc-badge">KYC</span>
|
<fa-icon icon="fingerprint" class="section-icon"></fa-icon>
|
||||||
</div>
|
{{ 'labels.inputs.KYC Verification' | translate }}
|
||||||
|
<span class="kyc-badge">KYC</span>
|
||||||
|
</h4>
|
||||||
|
|
||||||
<p class="kyc-subtitle">
|
<div class="kyc-info-hint">
|
||||||
{{ 'labels.inputs.KYC' | translate }} — RBI Master Direction compliant. Fields are optional but recommended for
|
<mat-icon class="kyc-info-hint-icon">info</mat-icon>
|
||||||
compliance.
|
<span>Verification (PAN, Aadhaar, GSTIN) will be available from the KYC tab after the client is created.</span>
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="kyc-info-hint">
|
|
||||||
<mat-icon class="kyc-info-hint-icon">info</mat-icon>
|
|
||||||
<span>Verification (PAN, Aadhaar, GSTIN) will be available from the KYC tab after the client is created.</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-divider class="m-b-20 m-t-10"></mat-divider>
|
|
||||||
|
|
||||||
<!-- PAN Section -->
|
|
||||||
<div class="kyc-field-row">
|
|
||||||
<div class="kyc-field-label-row">
|
|
||||||
<span class="kyc-field-title">{{ 'labels.inputs.PAN Number' | translate }}</span>
|
|
||||||
<span class="kyc-tag">KYC</span>
|
|
||||||
</div>
|
</div>
|
||||||
<mat-form-field appearance="outline" class="full-width">
|
|
||||||
<mat-label>{{ 'labels.inputs.PAN Number' | translate }}</mat-label>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
formControlName="panNumber"
|
|
||||||
placeholder="{{ 'labels.inputs.Enter 10-character PAN' | translate }}"
|
|
||||||
maxlength="10"
|
|
||||||
style="text-transform: uppercase"
|
|
||||||
(input)="kycForm.get('panNumber')?.setValue($any($event.target).value.toUpperCase(), { emitEvent: false })"
|
|
||||||
/>
|
|
||||||
@if (kycForm.get('panNumber')?.hasError('pattern') && kycForm.get('panNumber')?.touched) {
|
|
||||||
<mat-error>{{ 'labels.inputs.Enter 10-character PAN' | translate }}</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-divider class="m-b-20 m-t-10"></mat-divider>
|
<div class="form-grid">
|
||||||
|
<!-- PAN -->
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.PAN Number' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="panNumber"
|
||||||
|
placeholder="{{ 'labels.inputs.Enter 10-character PAN' | translate }}"
|
||||||
|
maxlength="10" style="text-transform: uppercase"
|
||||||
|
(input)="kycForm.get('panNumber')?.setValue($any($event.target).value.toUpperCase(), { emitEvent: false })" />
|
||||||
|
@if (kycForm.get('panNumber')?.hasError('pattern') && kycForm.get('panNumber')?.touched) {
|
||||||
|
<mat-error>{{ 'labels.inputs.Enter 10-character PAN' | translate }}</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<!-- Aadhaar Section -->
|
<!-- Aadhaar -->
|
||||||
<div class="kyc-field-row">
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
<div class="kyc-field-label-row">
|
<mat-label>{{ 'labels.inputs.Aadhaar Number' | translate }}</mat-label>
|
||||||
<span class="kyc-field-title">{{ 'labels.inputs.Aadhaar Number' | translate }}</span>
|
<input matInput formControlName="aadhaarNumber"
|
||||||
<span class="kyc-tag">KYC</span>
|
placeholder="{{ 'labels.inputs.Enter 12-digit Aadhaar' | translate }}"
|
||||||
|
maxlength="12" type="password" />
|
||||||
|
@if (kycForm.get('aadhaarNumber')?.hasError('pattern') && kycForm.get('aadhaarNumber')?.touched) {
|
||||||
|
<mat-error>{{ 'labels.inputs.Enter 12-digit Aadhaar' | translate }}</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<!-- GSTIN -->
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>{{ 'labels.inputs.GSTIN Number' | translate }}</mat-label>
|
||||||
|
<input matInput formControlName="gstinNumber"
|
||||||
|
placeholder="{{ 'labels.inputs.Enter 15-character GSTIN' | translate }}"
|
||||||
|
maxlength="15" style="text-transform: uppercase"
|
||||||
|
(input)="kycForm.get('gstinNumber')?.setValue($any($event.target).value.toUpperCase(), { emitEvent: false })" />
|
||||||
|
@if (kycForm.get('gstinNumber')?.hasError('pattern') && kycForm.get('gstinNumber')?.touched) {
|
||||||
|
<mat-error>{{ 'labels.inputs.Enter 15-character GSTIN' | translate }}</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<!-- Remarks -->
|
||||||
|
<mat-form-field appearance="outline" class="form-field full-width">
|
||||||
|
<mat-label>{{ 'labels.inputs.Remarks' | translate }}</mat-label>
|
||||||
|
<textarea matInput formControlName="remarks" rows="3"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<mat-form-field appearance="outline" class="full-width">
|
|
||||||
<mat-label>{{ 'labels.inputs.Aadhaar Number' | translate }}</mat-label>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
formControlName="aadhaarNumber"
|
|
||||||
placeholder="{{ 'labels.inputs.Enter 12-digit Aadhaar' | translate }}"
|
|
||||||
maxlength="12"
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
@if (kycForm.get('aadhaarNumber')?.hasError('pattern') && kycForm.get('aadhaarNumber')?.touched) {
|
|
||||||
<mat-error>{{ 'labels.inputs.Enter 12-digit Aadhaar' | translate }}</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-divider class="m-b-20 m-t-10"></mat-divider>
|
|
||||||
|
|
||||||
<!-- GSTIN Section -->
|
|
||||||
<div class="kyc-field-row">
|
|
||||||
<div class="kyc-field-label-row">
|
|
||||||
<span class="kyc-field-title">{{ 'labels.inputs.GSTIN Number' | translate }}</span>
|
|
||||||
<span class="kyc-tag">KYC</span>
|
|
||||||
</div>
|
|
||||||
<mat-form-field appearance="outline" class="full-width">
|
|
||||||
<mat-label>{{ 'labels.inputs.GSTIN Number' | translate }}</mat-label>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
formControlName="gstinNumber"
|
|
||||||
placeholder="{{ 'labels.inputs.Enter 15-character GSTIN' | translate }}"
|
|
||||||
maxlength="15"
|
|
||||||
style="text-transform: uppercase"
|
|
||||||
(input)="kycForm.get('gstinNumber')?.setValue($any($event.target).value.toUpperCase(), { emitEvent: false })"
|
|
||||||
/>
|
|
||||||
@if (kycForm.get('gstinNumber')?.hasError('pattern') && kycForm.get('gstinNumber')?.touched) {
|
|
||||||
<mat-error>{{ 'labels.inputs.Enter 15-character GSTIN' | translate }}</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-divider class="m-b-20 m-t-10"></mat-divider>
|
|
||||||
|
|
||||||
<!-- Additional Fields -->
|
|
||||||
<div class="kyc-additional">
|
|
||||||
<mat-form-field appearance="outline" class="full-width">
|
|
||||||
<mat-label>{{ 'labels.inputs.Remarks' | translate }}</mat-label>
|
|
||||||
<textarea matInput formControlName="remarks" rows="3"></textarea>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Navigation -->
|
|
||||||
<div class="layout-row align-center gap-2percent margin-t responsive-column">
|
|
||||||
<button mat-raised-button matStepperPrevious type="button">
|
|
||||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
|
||||||
{{ 'labels.buttons.Previous' | translate }}
|
|
||||||
</button>
|
|
||||||
<button mat-raised-button matStepperNext type="button">
|
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
|
||||||
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,21 +6,29 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.kyc-header {
|
.section-block {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
margin-bottom: 4px;
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
|
||||||
h3 {
|
.section-icon {
|
||||||
margin: 0;
|
color: var(--md-sys-color-primary, #1074b9);
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.kyc-badge {
|
.kyc-badge {
|
||||||
background-color: #1976d2;
|
background-color: #1976d2;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 11px;
|
font-size: 10px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@@ -28,24 +36,6 @@
|
|||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kyc-tag {
|
|
||||||
background-color: #e3f2fd;
|
|
||||||
color: #1565c0;
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 2px 7px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid #90caf9;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-subtitle {
|
|
||||||
color: #666;
|
|
||||||
font-size: 13px;
|
|
||||||
margin: 0 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-info-hint {
|
.kyc-info-hint {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -56,7 +46,7 @@
|
|||||||
background-color: #e3f2fd;
|
background-color: #e3f2fd;
|
||||||
border: 1px solid #90caf9;
|
border: 1px solid #90caf9;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kyc-info-hint-icon {
|
.kyc-info-hint-icon {
|
||||||
@@ -66,187 +56,22 @@
|
|||||||
color: #1565c0;
|
color: #1565c0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kyc-field-row {
|
.form-grid {
|
||||||
margin-bottom: 8px;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 4px 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kyc-field-label-row {
|
.form-field {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-field-title {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-input-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-input {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verify-btn {
|
|
||||||
margin-top: 4px;
|
|
||||||
min-width: 100px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-status-row {
|
|
||||||
margin-top: 4px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-chip {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 4px 10px;
|
|
||||||
border-radius: 16px;
|
|
||||||
|
|
||||||
&.verified {
|
|
||||||
background-color: #e8f5e9;
|
|
||||||
color: #2e7d32;
|
|
||||||
border: 1px solid #a5d6a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.pending {
|
|
||||||
background-color: #fff8e1;
|
|
||||||
color: #f57f17;
|
|
||||||
border: 1px solid #ffe082;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.failed {
|
|
||||||
background-color: #ffebee;
|
|
||||||
color: #c62828;
|
|
||||||
border: 1px solid #ef9a9a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-chip-icon {
|
|
||||||
font-size: 16px;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-icon {
|
|
||||||
font-size: 20px;
|
|
||||||
|
|
||||||
&.verified {
|
|
||||||
color: #2e7d32;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.failed {
|
|
||||||
color: #c62828;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-additional {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-width {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-b-20 {
|
.full-width {
|
||||||
margin-bottom: 20px;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-t-10 {
|
@media (max-width: 768px) {
|
||||||
margin-top: 10px;
|
.form-grid {
|
||||||
}
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
/* OTP Section */
|
|
||||||
.otp-section {
|
|
||||||
margin-top: 8px;
|
|
||||||
padding: 12px 16px;
|
|
||||||
background-color: #f3f8ff;
|
|
||||||
border: 1px solid #bbdefb;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.otp-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #1565c0;
|
|
||||||
margin: 0 0 10px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.otp-info-icon {
|
|
||||||
font-size: 18px;
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
color: #1565c0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.otp-input {
|
|
||||||
max-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resend-btn {
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Warning & Error messages */
|
|
||||||
.kyc-warning {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #f57f17;
|
|
||||||
margin-top: 4px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
background-color: #fffde7;
|
|
||||||
border: 1px solid #fff59d;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-warning-icon {
|
|
||||||
font-size: 16px;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
color: #f57f17;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-error-msg {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #c62828;
|
|
||||||
margin-top: 4px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
background-color: #ffebee;
|
|
||||||
border: 1px solid #ef9a9a;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kyc-error-icon {
|
|
||||||
font-size: 16px;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
color: #c62828;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verification-detail {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #333;
|
|
||||||
margin-left: 8px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Component, inject } from '@angular/core';
|
|||||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||||
|
|
||||||
/** Custom Imports */
|
/** Custom Imports */
|
||||||
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
|
|
||||||
import { MatDivider } from '@angular/material/divider';
|
import { MatDivider } from '@angular/material/divider';
|
||||||
import { MatIcon } from '@angular/material/icon';
|
import { MatIcon } from '@angular/material/icon';
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
@@ -29,8 +29,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
styleUrls: ['./client-kyc-step.component.scss'],
|
styleUrls: ['./client-kyc-step.component.scss'],
|
||||||
imports: [
|
imports: [
|
||||||
...STANDALONE_SHARED_IMPORTS,
|
...STANDALONE_SHARED_IMPORTS,
|
||||||
MatStepperPrevious,
|
|
||||||
MatStepperNext,
|
|
||||||
MatDivider,
|
MatDivider,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
FaIconComponent
|
FaIconComponent
|
||||||
|
|||||||
+234
-270
@@ -6,280 +6,244 @@
|
|||||||
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 p-b-20">
|
<div class="preview-container">
|
||||||
<h3>{{ 'labels.heading.General' | translate }}</h3>
|
<!-- Client Profile Card -->
|
||||||
|
<div class="profile-card">
|
||||||
<mat-divider [inset]="true"></mat-divider>
|
<div class="profile-avatar">
|
||||||
|
<fa-icon [icon]="client?.legalFormId === LegalFormId.PERSON ? 'user' : 'building'" class="avatar-icon"></fa-icon>
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.name' | translate }}</span>
|
|
||||||
@if (client.legalFormId === LegalFormId.ENTITY) {
|
|
||||||
<span class="flex-60">{{ client.fullname }}</span>
|
|
||||||
}
|
|
||||||
@if (client.legalFormId === LegalFormId.PERSON) {
|
|
||||||
<span class="flex-60"
|
|
||||||
>{{ client.firstname }}
|
|
||||||
{{ client.middlename ? client.middlename + ' ' + client.lastname : client.lastname }}</span
|
|
||||||
>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Office' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.officeId | find: clientTemplate.officeOptions : 'id' : 'name' }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Legal Form' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.legalFormId | find: clientTemplate.clientLegalFormOptions : 'id' : 'value' }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (client.staffId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Staff' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.staffId | find: clientTemplate.staffOptions : 'id' : 'displayName' }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
<div class="profile-info">
|
||||||
|
<h3 class="profile-name">
|
||||||
@if (client.dateOfBirth) {
|
@if (client?.legalFormId === LegalFormId.ENTITY) {
|
||||||
<div class="flex-fill">
|
{{ client.fullname }}
|
||||||
<span class="flex-40">{{
|
|
||||||
client.legalFormId === LegalFormId.PERSON ? 'Date of Birth' : 'Incorporation Date'
|
|
||||||
}}</span>
|
|
||||||
<span class="flex-60">{{ client.dateOfBirth | dateFormat }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.externalId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.External Id' | translate }}</span>
|
|
||||||
<span class="flex-60">
|
|
||||||
<mifosx-external-identifier externalId="{{ client.externalId }}"></mifosx-external-identifier>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.mobileNo) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Mobile No' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.mobileNo }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.emailAddress) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Email Address' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.emailAddress }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.clientTypeId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Client Type' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.clientTypeId | find: clientTemplate.clientTypeOptions : 'id' : 'name' }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.clientClassificationId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Client Classification' | translate }}</span>
|
|
||||||
<span class="flex-60">{{
|
|
||||||
client.clientClassificationId | find: clientTemplate.clientClassificationOptions : 'id' : 'name'
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.savingsProductId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Savings Product' | translate }}</span>
|
|
||||||
<span class="flex-60">{{
|
|
||||||
client.savingsProductId | find: clientTemplate.savingProductOptions : 'id' : 'name'
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.submittedOnDate) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Submitted On Date' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.submittedOnDate | dateFormat }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Active' | translate }}?</span>
|
|
||||||
<span class="flex-60">{{ client.active | yesNo }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (client.activationDate) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Activation Date' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.activationDate | dateFormat }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.legalFormId === LegalFormId.PERSON) {
|
|
||||||
@if (client.genderId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Gender' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.genderId | find: clientTemplate.genderOptions : 'id' : 'name' }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Is staff' | translate }}?</span>
|
|
||||||
<span class="flex-60">{{ client.isStaff | yesNo }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.legalFormId === LegalFormId.ENTITY) {
|
|
||||||
@if (client.clientNonPersonDetails.incorpValidityTillDate) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Incorporation Validity Till Date' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.clientNonPersonDetails.incorpValidityTillDate | dateFormat }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Incorportation Number' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.clientNonPersonDetails.incorpNumber || 'Not Provided' }}</span>
|
|
||||||
</div>
|
|
||||||
@if (client.clientNonPersonDetails.mainBusinessLineId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Main Business Line' | translate }}</span>
|
|
||||||
<span class="flex-60">{{
|
|
||||||
client.clientNonPersonDetails.mainBusinessLineId
|
|
||||||
| find: clientTemplate.clientNonPersonMainBusinessLineOptions : 'id' : 'name'
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@if (client.clientNonPersonDetails.constitutionId) {
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Constitution' | translate }}</span>
|
|
||||||
<span class="flex-60">{{
|
|
||||||
client.clientNonPersonDetails.constitutionId
|
|
||||||
| find: clientTemplate.clientNonPersonConstitutionOptions : 'id' : 'name'
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="flex-fill">
|
|
||||||
<span class="flex-40">{{ 'labels.inputs.Remarks' | translate }}</span>
|
|
||||||
<span class="flex-60">{{ client.clientNonPersonDetails.remarks || 'N/A' }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (client.familyMembers.length) {
|
|
||||||
<div class="layout-row-wrap responsive-column flex-fill m-b-20">
|
|
||||||
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Family Members' | translate }}</h3>
|
|
||||||
<mat-divider class="flex-fill"></mat-divider>
|
|
||||||
<mat-accordion class="flex-fill m-t-5">
|
|
||||||
@for (member of client.familyMembers; track member) {
|
|
||||||
<mat-expansion-panel class="family-member">
|
|
||||||
<mat-expansion-panel-header>
|
|
||||||
<mat-panel-title>
|
|
||||||
{{ member.firstName }}
|
|
||||||
{{ member.middleName ? member.middleName + ' ' + member.lastName : member.lastName }}
|
|
||||||
</mat-panel-title>
|
|
||||||
<mat-panel-description>
|
|
||||||
{{ member.relationship }}
|
|
||||||
</mat-panel-description>
|
|
||||||
</mat-expansion-panel-header>
|
|
||||||
<mat-divider></mat-divider>
|
|
||||||
<p>
|
|
||||||
{{ 'labels.inputs.First Name' | translate }} : {{ member.firstName }}<br />
|
|
||||||
{{ 'labels.inputs.Middle Name' | translate }} : {{ member.middleName }}<br />
|
|
||||||
{{ 'labels.inputs.Last Name' | translate }} : {{ member.lastName }}<br />
|
|
||||||
{{ 'labels.inputs.Qualification' | translate }} : {{ member.qualification }}<br />
|
|
||||||
{{ 'labels.inputs.Relationship' | translate }} :
|
|
||||||
{{ member.relationshipId | find: clientTemplate.familyMemberOptions.relationshipIdOptions : 'id' : 'name'
|
|
||||||
}}<br />
|
|
||||||
{{ 'labels.inputs.Age' | translate }} : {{ member.age }}<br />
|
|
||||||
{{ 'labels.inputs.Is Dependent' | translate }} : {{ member.isDependent ? 'Yes' : 'No' }}<br />
|
|
||||||
{{ 'labels.inputs.Marital Status' | translate }} :
|
|
||||||
{{
|
|
||||||
member.maritalStatusId
|
|
||||||
| find: clientTemplate.familyMemberOptions.maritalStatusIdOptions : 'id' : 'name'
|
|
||||||
}}<br />
|
|
||||||
{{ 'labels.inputs.Gender' | translate }} :
|
|
||||||
{{ member.genderId | find: clientTemplate.familyMemberOptions.genderIdOptions : 'id' : 'name' }}<br />
|
|
||||||
{{ 'labels.inputs.Profession' | translate }} :
|
|
||||||
{{ member.professionId | find: clientTemplate.familyMemberOptions.professionIdOptions : 'id' : 'name'
|
|
||||||
}}<br />
|
|
||||||
{{ 'labels.inputs.Date Of Birth' | translate }} : {{ member.dateOfBirth | dateFormat }}<br />
|
|
||||||
</p>
|
|
||||||
</mat-expansion-panel>
|
|
||||||
}
|
}
|
||||||
</mat-accordion>
|
@if (client?.legalFormId === LegalFormId.PERSON) {
|
||||||
</div>
|
{{ client.firstname }} {{ client.middlename ? client.middlename + ' ' : '' }}{{ client.lastname }}
|
||||||
}
|
|
||||||
|
|
||||||
@if (clientTemplate.isAddressEnabled && client.address && client.address.length) {
|
|
||||||
<div class="flex-fill layout-row-wrap responsive-column">
|
|
||||||
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Address' | translate }}</h3>
|
|
||||||
<mat-divider class="flex-fill"></mat-divider>
|
|
||||||
<mat-accordion class="flex-fill m-t-5">
|
|
||||||
@for (address of client.address; track address) {
|
|
||||||
<mat-expansion-panel class="address">
|
|
||||||
<mat-expansion-panel-header>
|
|
||||||
<mat-panel-title>
|
|
||||||
{{ getSelectedValue('addressTypeIdOptions', address.addressTypeId)?.name }}
|
|
||||||
</mat-panel-title>
|
|
||||||
<mat-panel-description>
|
|
||||||
{{ address.relationship }}
|
|
||||||
</mat-panel-description>
|
|
||||||
</mat-expansion-panel-header>
|
|
||||||
<mat-divider></mat-divider>
|
|
||||||
<p>
|
|
||||||
@if (isFieldEnabled('street')) {
|
|
||||||
<span>{{ 'labels.inputs.Street' | translate }} : {{ address.street }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('addressLine1')) {
|
|
||||||
<span>{{ 'labels.inputs.Address Line' | translate }} 1 : {{ address.addressLine1 }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('addressLine2')) {
|
|
||||||
<span>{{ 'labels.inputs.Address Line' | translate }} 2 : {{ address.addressLine2 }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('addressLine3')) {
|
|
||||||
<span>{{ 'labels.inputs.Address Line' | translate }} 3 : {{ address.addressLine3 }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('townVillage')) {
|
|
||||||
<span>{{ 'labels.inputs.Town / Village' | translate }} : {{ address.townVillage }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('city')) {
|
|
||||||
<span>{{ 'labels.inputs.City' | translate }} : {{ address.city }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('stateProvinceId')) {
|
|
||||||
<span
|
|
||||||
>{{ 'labels.inputs.State / Province' | translate }} :
|
|
||||||
{{ getSelectedValue('stateProvinceIdOptions', address.stateProvinceId)?.name }}<br
|
|
||||||
/></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('countryId')) {
|
|
||||||
<span
|
|
||||||
>{{ 'labels.inputs.Country' | translate }} :
|
|
||||||
{{ getSelectedValue('countryIdOptions', address.countryId)?.name }}<br
|
|
||||||
/></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('postalCode')) {
|
|
||||||
<span>{{ 'labels.inputs.Postal Code' | translate }} : {{ address.postalCode }}<br /></span>
|
|
||||||
}
|
|
||||||
@if (isFieldEnabled('isActive')) {
|
|
||||||
<span>{{ 'labels.inputs.Active Status' | translate }} : {{ address.isActive }}<br /></span>
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</mat-expansion-panel>
|
|
||||||
}
|
}
|
||||||
</mat-accordion>
|
</h3>
|
||||||
|
<div class="profile-meta">
|
||||||
|
@if (client?.officeId) {
|
||||||
|
<span class="meta-chip">
|
||||||
|
<fa-icon icon="briefcase" class="chip-icon"></fa-icon>
|
||||||
|
{{ client.officeId | find: clientTemplate.officeOptions : 'id' : 'name' }}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
@if (client?.legalFormId) {
|
||||||
|
<span class="meta-chip">
|
||||||
|
{{ client.legalFormId | find: clientTemplate.clientLegalFormOptions : 'id' : 'value' }}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
@if (client?.active) {
|
||||||
|
<span class="meta-chip status-active">Active</span>
|
||||||
|
} @else {
|
||||||
|
<span class="meta-chip status-inactive">Inactive</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- General Information Card -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<fa-icon icon="user" class="card-icon"></fa-icon>
|
||||||
|
<span>{{ 'labels.heading.General' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="info-table">
|
||||||
|
<tbody>
|
||||||
|
@if (client?.dateOfBirth) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ client.legalFormId === LegalFormId.PERSON ? 'Date of Birth' : 'Incorporation Date' }}</td>
|
||||||
|
<td class="info-value">{{ client.dateOfBirth | dateFormat }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.externalId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.External Id' | translate }}</td>
|
||||||
|
<td class="info-value">
|
||||||
|
<mifosx-external-identifier externalId="{{ client.externalId }}"></mifosx-external-identifier>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.staffId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Staff' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.staffId | find: clientTemplate.staffOptions : 'id' : 'displayName' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.legalFormId === LegalFormId.PERSON && client?.genderId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Gender' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.genderId | find: clientTemplate.genderOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.mobileNo) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Mobile No' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.mobileNo }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.emailAddress) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Email Address' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.emailAddress }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.clientTypeId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Client Type' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.clientTypeId | find: clientTemplate.clientTypeOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.clientClassificationId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Client Classification' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.clientClassificationId | find: clientTemplate.clientClassificationOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.occupationCategoryId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Occupation Category' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.occupationCategoryId | find: clientTemplate.occupationCategoryOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.occupationId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Occupation' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.occupationId | find: clientTemplate.occupationOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.submittedOnDate) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Submitted On Date' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.submittedOnDate | dateFormat }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Active' | translate }}?</td>
|
||||||
|
<td class="info-value">
|
||||||
|
<span [class]="client?.active ? 'badge-yes' : 'badge-no'">{{ client?.active | yesNo }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@if (client?.activationDate) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Activation Date' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.activationDate | dateFormat }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.savingsProductId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Savings Product' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.savingsProductId | find: clientTemplate.savingProductOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.legalFormId === LegalFormId.PERSON) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Is staff' | translate }}?</td>
|
||||||
|
<td class="info-value">{{ client.isStaff | yesNo }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (client?.legalFormId === LegalFormId.ENTITY && client?.clientNonPersonDetails) {
|
||||||
|
@if (client.clientNonPersonDetails.constitutionId) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Constitution' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.clientNonPersonDetails.constitutionId | find: clientTemplate.clientNonPersonConstitutionOptions : 'id' : 'name' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Incorporation Number' | translate }}</td>
|
||||||
|
<td class="info-value">{{ client.clientNonPersonDetails.incorpNumber || 'N/A' }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- KYC Details Card -->
|
||||||
|
@if (kycData?.panNumber || kycData?.aadhaarNumberMasked || kycData?.gstinNumber) {
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<fa-icon icon="fingerprint" class="card-icon"></fa-icon>
|
||||||
|
<span>{{ 'labels.inputs.KYC' | translate }}</span>
|
||||||
|
<span class="kyc-badge">KYC</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="info-table">
|
||||||
|
<tbody>
|
||||||
|
@if (kycData.panNumber) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.PAN Number' | translate }}</td>
|
||||||
|
<td class="info-value mono">{{ kycData.panNumber }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (kycData.aadhaarNumberMasked) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Aadhaar Number' | translate }}</td>
|
||||||
|
<td class="info-value mono">{{ kycData.aadhaarNumberMasked }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (kycData.gstinNumber) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.GSTIN Number' | translate }}</td>
|
||||||
|
<td class="info-value mono">{{ kycData.gstinNumber }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@if (kycData.remarks) {
|
||||||
|
<tr>
|
||||||
|
<td class="info-label">{{ 'labels.inputs.Remarks' | translate }}</td>
|
||||||
|
<td class="info-value">{{ kycData.remarks }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="layout-row responsive-column align-center gap-2px margin-t">
|
<!-- Family Members / Nominee Card -->
|
||||||
<button mat-raised-button matStepperPrevious>
|
@if (client?.familyMembers?.length) {
|
||||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
<div class="info-card">
|
||||||
{{ 'labels.buttons.Previous' | translate }}
|
<div class="card-header">
|
||||||
</button>
|
<fa-icon icon="users" class="card-icon"></fa-icon>
|
||||||
<button mat-raised-button [routerLink]="['../']">
|
<span>{{ 'labels.heading.Family Members' | translate }} / {{ 'labels.inputs.Nominee' | translate }}</span>
|
||||||
{{ 'labels.buttons.Cancel' | translate }}
|
<span class="count-badge">{{ client.familyMembers.length }}</span>
|
||||||
</button>
|
</div>
|
||||||
<button mat-raised-button color="primary" (click)="submitEvent.emit()">
|
<div class="card-body no-padding">
|
||||||
{{ 'labels.buttons.Submit' | translate }}
|
<table class="data-table">
|
||||||
</button>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'labels.inputs.name' | translate }}</th>
|
||||||
|
<th>{{ 'labels.inputs.Relationship' | translate }}</th>
|
||||||
|
<th>{{ 'labels.inputs.Date Of Birth' | translate }}</th>
|
||||||
|
<th>{{ 'labels.inputs.Is Dependent' | translate }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (member of client.familyMembers; track member) {
|
||||||
|
<tr>
|
||||||
|
<td>{{ member.firstName }} {{ member.lastName }}</td>
|
||||||
|
<td>{{ member.relationshipId | find: clientTemplate.familyMemberOptions.relationshipIdOptions : 'id' : 'name' }}</td>
|
||||||
|
<td>{{ member.dateOfBirth | dateFormat }}</td>
|
||||||
|
<td>
|
||||||
|
<span [class]="member.isDependent ? 'badge-yes' : 'badge-no'">{{ member.isDependent ? 'Yes' : 'No' }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Submit Section -->
|
||||||
|
<div class="submit-section">
|
||||||
|
<button mat-raised-button [routerLink]="['../']" class="cancel-btn">
|
||||||
|
{{ 'labels.buttons.Cancel' | translate }}
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button color="primary" class="submit-btn" (click)="submitEvent.emit()">
|
||||||
|
<fa-icon icon="check" class="m-r-10"></fa-icon>
|
||||||
|
{{ 'labels.buttons.Submit' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+279
-30
@@ -6,43 +6,292 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
h2,
|
.preview-container {
|
||||||
h3,
|
display: flex;
|
||||||
h4 {
|
flex-direction: column;
|
||||||
margin: 0;
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Profile Card ── */
|
||||||
|
.profile-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%);
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-avatar {
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--md-sys-color-primary, #1074b9);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.avatar-icon {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-name {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
padding: 3px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
color: #555;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
span {
|
.chip-icon {
|
||||||
margin: 0.5em 0;
|
font-size: 10px;
|
||||||
}
|
color: #888;
|
||||||
|
|
||||||
mat-divider {
|
|
||||||
margin: 0 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.margin-t {
|
|
||||||
margin-top: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.family-member {
|
|
||||||
h3 {
|
|
||||||
margin: 1% auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
&.status-active {
|
||||||
line-height: 30px;
|
background: #e8f5e9;
|
||||||
margin-left: 2%;
|
color: #2e7d32;
|
||||||
|
border-color: #a5d6a7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.status-inactive {
|
||||||
|
background: #fff3e0;
|
||||||
|
color: #e65100;
|
||||||
|
border-color: #ffcc80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.address {
|
/* ── Info Cards ── */
|
||||||
h3 {
|
.info-card {
|
||||||
margin: 1% auto;
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
}
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
.card-header {
|
||||||
line-height: 30px;
|
display: flex;
|
||||||
margin-left: 2%;
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
background: #fafafa;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
color: var(--md-sys-color-primary, #1074b9);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 16px 20px;
|
||||||
|
|
||||||
|
&.no-padding {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.count-badge {
|
||||||
|
margin-left: auto;
|
||||||
|
background: var(--md-sys-color-primary, #1074b9);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Info Table (Key-Value pairs) ── */
|
||||||
|
.info-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 10px 0;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
width: 40%;
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: 500;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Data Table (Family, etc.) ── */
|
||||||
|
.data-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background: #fafafa;
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 10px 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(0, 0, 0, 0.55);
|
||||||
|
text-align: left;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
tr {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 10px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Badges ── */
|
||||||
|
.badge-yes {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #e8f5e9;
|
||||||
|
color: #2e7d32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-no {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── KYC ── */
|
||||||
|
.kyc-badge {
|
||||||
|
margin-left: auto;
|
||||||
|
background: #1976d2;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mono {
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Submit Section ── */
|
||||||
|
.submit-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 20px 0 4px;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
min-width: 160px;
|
||||||
|
height: 44px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Responsive ── */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.profile-card {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-meta {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-table {
|
||||||
|
.info-label {
|
||||||
|
width: 45%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
thead th,
|
||||||
|
tbody td {
|
||||||
|
padding: 8px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
MatExpansionPanelTitle,
|
MatExpansionPanelTitle,
|
||||||
MatExpansionPanelDescription
|
MatExpansionPanelDescription
|
||||||
} from '@angular/material/expansion';
|
} from '@angular/material/expansion';
|
||||||
import { MatStepperPrevious } from '@angular/material/stepper';
|
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
import { FindPipe } from '../../../pipes/find.pipe';
|
import { FindPipe } from '../../../pipes/find.pipe';
|
||||||
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
|
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
|
||||||
@@ -41,7 +40,6 @@ import { LegalFormId } from 'app/clients/models/legal-form.enum';
|
|||||||
MatExpansionPanelHeader,
|
MatExpansionPanelHeader,
|
||||||
MatExpansionPanelTitle,
|
MatExpansionPanelTitle,
|
||||||
MatExpansionPanelDescription,
|
MatExpansionPanelDescription,
|
||||||
MatStepperPrevious,
|
|
||||||
FaIconComponent,
|
FaIconComponent,
|
||||||
FindPipe,
|
FindPipe,
|
||||||
DateFormatPipe,
|
DateFormatPipe,
|
||||||
@@ -55,6 +53,8 @@ export class ClientPreviewStepComponent {
|
|||||||
@Input() clientTemplate: any;
|
@Input() clientTemplate: any;
|
||||||
/** Client Object */
|
/** Client Object */
|
||||||
@Input() client: any;
|
@Input() client: any;
|
||||||
|
/** KYC Data */
|
||||||
|
@Input() kycData: any;
|
||||||
|
|
||||||
/** Form submission event */
|
/** Form submission event */
|
||||||
@Output() submitEvent = new EventEmitter();
|
@Output() submitEvent = new EventEmitter();
|
||||||
|
|||||||
@@ -51,150 +51,116 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mat-typography account-card-title">
|
<div class="mat-typography account-card-title">
|
||||||
<mat-card-title class="make-flex content">
|
<!-- Top Row: Name + Status + Actions -->
|
||||||
<h3 class="flex-95">
|
<mat-card-title class="cv-title-row">
|
||||||
<i
|
<div class="cv-name-block">
|
||||||
class="fa fa-stop"
|
<i class="fa fa-stop" [ngClass]="clientViewData.status.code | statusLookup"
|
||||||
[ngClass]="clientViewData.status.code | statusLookup"
|
matTooltip="{{ 'labels.status.' + clientViewData.status.value | translate }}"></i>
|
||||||
matTooltip="{{ 'labels.status.' + clientViewData.status.value | translate }}"
|
|
||||||
></i>
|
|
||||||
<b>{{ 'labels.inputs.Client Name' | translate }} :</b>
|
|
||||||
<mifosx-entity-name
|
<mifosx-entity-name
|
||||||
[entityName]="
|
[entityName]="complianceHideClientData ? maskName(clientViewData.displayName) : clientViewData.displayName"
|
||||||
complianceHideClientData ? maskName(clientViewData.displayName) : clientViewData.displayName
|
[display]="'right'" [hideCopy]="complianceHideClientData"></mifosx-entity-name>
|
||||||
"
|
<span class="cv-status-chip" [ngClass]="clientViewData.status.code | statusLookup">
|
||||||
[display]="'right'"
|
{{ 'labels.status.' + clientViewData.status.value | translate }}
|
||||||
[hideCopy]="complianceHideClientData"
|
</span>
|
||||||
></mifosx-entity-name>
|
|
||||||
</h3>
|
|
||||||
<div class="flex-5 align-end-center">
|
|
||||||
<button mat-icon-button [matMenuTriggerFor]="clientMenu" aria-label="Client actions" yPosition="below">
|
|
||||||
<mat-icon matListIcon class="actions-menu">
|
|
||||||
<fa-icon icon="bars" size="sm"></fa-icon>
|
|
||||||
</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button mat-icon-button [matMenuTriggerFor]="clientMenu" aria-label="Client actions">
|
||||||
|
<mat-icon matListIcon class="actions-menu"><fa-icon icon="bars" size="sm"></fa-icon></mat-icon>
|
||||||
|
</button>
|
||||||
</mat-card-title>
|
</mat-card-title>
|
||||||
|
|
||||||
|
<!-- ID Chips Row -->
|
||||||
|
<div class="cv-id-row">
|
||||||
|
<div class="cv-id-chip">
|
||||||
|
<span class="cv-id-label">{{ 'labels.inputs.Account No' | translate }}</span>
|
||||||
|
<mifosx-account-number accountNo="{{ clientViewData.accountNo }}"></mifosx-account-number>
|
||||||
|
</div>
|
||||||
|
@if (clientViewData.cifNumber) {
|
||||||
|
<div class="cv-id-chip">
|
||||||
|
<span class="cv-id-label">{{ 'labels.inputs.CIF Number' | translate }}</span>
|
||||||
|
<mifosx-account-number accountNo="{{ clientViewData.cifNumber }}"></mifosx-account-number>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.externalId) {
|
||||||
|
<div class="cv-id-chip">
|
||||||
|
<span class="cv-id-label">{{ 'labels.inputs.External Id' | translate }}</span>
|
||||||
|
<mifosx-external-identifier
|
||||||
|
[externalId]="complianceHideClientData ? maskValue(clientViewData.externalId) : clientViewData.externalId"
|
||||||
|
[completed]="true" [hideCopy]="complianceHideClientData"></mifosx-external-identifier>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Details Grid -->
|
||||||
<mat-card-subtitle>
|
<mat-card-subtitle>
|
||||||
<div class="layout-row responsive-column">
|
<div class="cv-details-grid">
|
||||||
<div class="flex-50">
|
<div class="cv-detail">
|
||||||
<table class="account-overview">
|
<span class="cv-dl">{{ 'labels.inputs.Office' | translate }}</span>
|
||||||
<tbody>
|
<span class="cv-dv">{{ clientViewData.officeName }}</span>
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Office' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td><mifosx-entity-name [entityName]="clientViewData.officeName"></mifosx-entity-name></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Client' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td><mifosx-account-number accountNo="{{ clientViewData.accountNo }}"></mifosx-account-number></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.External Id' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<mifosx-external-identifier
|
|
||||||
[externalId]="
|
|
||||||
complianceHideClientData ? maskValue(clientViewData.externalId) : clientViewData.externalId
|
|
||||||
"
|
|
||||||
[completed]="true"
|
|
||||||
[hideCopy]="complianceHideClientData"
|
|
||||||
></mifosx-external-identifier>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@if (clientViewData.activationDate) {
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Activation Date' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>{{ clientViewData.activationDate | dateFormat }}</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Staff' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
@if (clientViewData.staffName) {
|
|
||||||
<td>{{ clientViewData.staffName }}</td>
|
|
||||||
}
|
|
||||||
@if (!clientViewData.staffName) {
|
|
||||||
<td>{{ 'labels.inputs.Unassigned' | translate }}</td>
|
|
||||||
}
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-50">
|
<div class="cv-detail">
|
||||||
<table class="account-overview">
|
<span class="cv-dl">{{ 'labels.inputs.Staff' | translate }}</span>
|
||||||
<tbody>
|
<span class="cv-dv">{{ clientViewData.staffName || ('labels.inputs.Unassigned' | translate) }}</span>
|
||||||
@if (clientViewData.groups.length > 0) {
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Member Of' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@for (group of clientViewData.groups; track group) {
|
|
||||||
<span>
|
|
||||||
<span class="m-r-3">{{ group.name }}</span>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
@if (clientViewData.clientType) {
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Client Type' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>{{ clientViewData.clientType.name }}</td>
|
|
||||||
</tr>
|
|
||||||
@if (clientViewData.clientClassification) {
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Client Classification' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>{{ clientViewData.clientClassification.name }}</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Mobile Number' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<mifosx-external-identifier
|
|
||||||
[externalId]="
|
|
||||||
complianceHideClientData ? maskValue(clientViewData.mobileNo) : clientViewData.mobileNo
|
|
||||||
"
|
|
||||||
[completed]="true"
|
|
||||||
[hideCopy]="complianceHideClientData"
|
|
||||||
></mifosx-external-identifier>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<b>{{ 'labels.inputs.Email' | translate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<mifosx-external-identifier
|
|
||||||
[externalId]="
|
|
||||||
complianceHideClientData
|
|
||||||
? maskEmail(clientViewData.emailAddress)
|
|
||||||
: clientViewData.emailAddress
|
|
||||||
"
|
|
||||||
[completed]="true"
|
|
||||||
[hideCopy]="complianceHideClientData"
|
|
||||||
></mifosx-external-identifier>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
@if (clientViewData.activationDate) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Activation Date' | translate }}</span>
|
||||||
|
<span class="cv-dv">{{ clientViewData.activationDate | dateFormat }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.clientType) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Client Type' | translate }}</span>
|
||||||
|
<span class="cv-dv">{{ clientViewData.clientType.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.clientClassification) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Client Classification' | translate }}</span>
|
||||||
|
<span class="cv-dv">{{ clientViewData.clientClassification.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.mobileNo) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Mobile Number' | translate }}</span>
|
||||||
|
<span class="cv-dv">
|
||||||
|
<mifosx-external-identifier
|
||||||
|
[externalId]="complianceHideClientData ? maskValue(clientViewData.mobileNo) : clientViewData.mobileNo"
|
||||||
|
[completed]="true" [hideCopy]="complianceHideClientData"></mifosx-external-identifier>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.emailAddress) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Email' | translate }}</span>
|
||||||
|
<span class="cv-dv">
|
||||||
|
<mifosx-external-identifier
|
||||||
|
[externalId]="complianceHideClientData ? maskEmail(clientViewData.emailAddress) : clientViewData.emailAddress"
|
||||||
|
[completed]="true" [hideCopy]="complianceHideClientData"></mifosx-external-identifier>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.occupationCategory) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Occupation Category' | translate }}</span>
|
||||||
|
<span class="cv-dv">{{ clientViewData.occupationCategory.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.occupation) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Occupation' | translate }}</span>
|
||||||
|
<span class="cv-dv">{{ clientViewData.occupation.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.groups?.length > 0) {
|
||||||
|
<div class="cv-detail">
|
||||||
|
<span class="cv-dl">{{ 'labels.inputs.Member Of' | translate }}</span>
|
||||||
|
<span class="cv-dv">
|
||||||
|
@for (group of clientViewData.groups; track group) {
|
||||||
|
<span>{{ group.name }} </span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,16 +30,121 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.account-overview {
|
|
||||||
color: white;
|
|
||||||
min-width: 85%;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.make-flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-card-title-group {
|
.mat-card-title-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Title Row ── */
|
||||||
|
.cv-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-name-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
i.fa-stop {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-status-chip {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── ID Chips Row ── */
|
||||||
|
.cv-id-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-id-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-id-label {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255, 255, 255, 0.55);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Details Grid ── */
|
||||||
|
.cv-details-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 6px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-detail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1px;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-dl {
|
||||||
|
font-size: 10px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-dv {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255, 255, 255, 0.95);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-menu {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Responsive ── */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.cv-details-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.cv-details-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-id-row {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.cv-details-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,6 +87,10 @@
|
|||||||
<span class="label">{{ 'labels.inputs.Account No' | translate }}</span>
|
<span class="label">{{ 'labels.inputs.Account No' | translate }}</span>
|
||||||
<span class="value">{{ clientViewData.accountNo || '-' }}</span>
|
<span class="value">{{ clientViewData.accountNo || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="data-item">
|
||||||
|
<span class="label">{{ 'labels.inputs.CIF Number' | translate }}</span>
|
||||||
|
<span class="value">{{ clientViewData.cifNumber || '-' }}</span>
|
||||||
|
</div>
|
||||||
<div class="data-item">
|
<div class="data-item">
|
||||||
<span class="label">{{ 'labels.inputs.External Id' | translate }}</span>
|
<span class="label">{{ 'labels.inputs.External Id' | translate }}</span>
|
||||||
<span class="value">{{ clientViewData.externalId || '-' }}</span>
|
<span class="value">{{ clientViewData.externalId || '-' }}</span>
|
||||||
@@ -178,6 +182,18 @@
|
|||||||
<span class="value">{{ clientViewData.clientClassification.name }}</span>
|
<span class="value">{{ clientViewData.clientClassification.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@if (clientViewData.occupationCategory) {
|
||||||
|
<div class="data-item">
|
||||||
|
<span class="label">{{ 'labels.inputs.Occupation Category' | translate }}</span>
|
||||||
|
<span class="value">{{ clientViewData.occupationCategory.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (clientViewData.occupation) {
|
||||||
|
<div class="data-item">
|
||||||
|
<span class="label">{{ 'labels.inputs.Occupation' | translate }}</span>
|
||||||
|
<span class="value">{{ clientViewData.occupation.name }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@if (!clientViewData.clientType && !clientViewData.clientClassification) {
|
@if (!clientViewData.clientType && !clientViewData.clientClassification) {
|
||||||
<div class="data-item">
|
<div class="data-item">
|
||||||
<span class="value no-data">{{ 'labels.commons.No classification data available' | translate }}</span>
|
<span class="value no-data">{{ 'labels.commons.No classification data available' | translate }}</span>
|
||||||
|
|||||||
@@ -7,50 +7,66 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<mat-card class="container">
|
<mat-card class="container">
|
||||||
<div class="layout-column layout-gt-sm-row align-gt-sm-start-center">
|
<!-- Header Bar -->
|
||||||
<div class="search-box m-r-30">
|
<div class="table-header">
|
||||||
<mat-form-field class="search-box">
|
<div class="table-title-group">
|
||||||
|
<h2 class="table-title">
|
||||||
|
<div class="t-logomark"><span></span><span></span><span></span><span></span></div>
|
||||||
|
{{ 'labels.menus.Clients' | translate }}
|
||||||
|
</h2>
|
||||||
|
<span class="table-count" *ngIf="totalRows">{{ totalRows }} records</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-actions">
|
||||||
|
<mat-form-field class="table-search" appearance="outline">
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
placeholder="{{ 'labels.text.SearchByClient' | translate }}"
|
placeholder="{{ 'labels.text.SearchByClient' | translate }}"
|
||||||
class="search-box"
|
|
||||||
(keydown.enter)="search($event.target.value)"
|
(keydown.enter)="search($event.target.value)"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
|
||||||
@if (existsClientsToFilter) {
|
@if (existsClientsToFilter) {
|
||||||
<div class="filter-box">
|
<mat-checkbox #showClosedAccounts labelPosition="after" class="table-checkbox">
|
||||||
<mat-checkbox #showClosedAccounts labelPosition="after" class="m-r-10"
|
{{ 'labels.inputs.Show Closed Accounts' | translate }}
|
||||||
>{{ 'labels.inputs.Show Closed Accounts' | translate }}
|
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="table-buttons">
|
||||||
|
<button
|
||||||
|
mat-stroked-button
|
||||||
|
[routerLink]="['../', 'organization', 'bulk-import', 'Clients']"
|
||||||
|
*mifosxHasPermission="'CREATE_CLIENT'"
|
||||||
|
class="btn-import"
|
||||||
|
>
|
||||||
|
<fa-icon icon="download"></fa-icon>
|
||||||
|
{{ 'labels.buttons.Import Client' | translate }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-flat-button
|
||||||
|
color="primary"
|
||||||
|
[routerLink]="['create']"
|
||||||
|
*mifosxHasPermission="'CREATE_CLIENT'"
|
||||||
|
class="btn-create"
|
||||||
|
>
|
||||||
|
<fa-icon icon="plus"></fa-icon>
|
||||||
|
{{ 'labels.buttons.Create Client' | translate }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
<div class="action-button gap-25px">
|
|
||||||
<button
|
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
[routerLink]="['../', 'organization', 'bulk-import', 'Clients']"
|
|
||||||
*mifosxHasPermission="'CREATE_CLIENT'"
|
|
||||||
>
|
|
||||||
<fa-icon icon="download" class="m-r-20"></fa-icon>{{ 'labels.buttons.Import Client' | translate }}
|
|
||||||
</button>
|
|
||||||
<button mat-raised-button color="primary" [routerLink]="['create']" *mifosxHasPermission="'CREATE_CLIENT'">
|
|
||||||
<fa-icon icon="plus" class="m-r-20"></fa-icon>{{ 'labels.buttons.Create Client' | translate }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [hidden]="!existsClientsToFilter" class="client-list">
|
<!-- Table -->
|
||||||
|
<div [hidden]="!existsClientsToFilter" class="table-container">
|
||||||
@if (isLoading) {
|
@if (isLoading) {
|
||||||
<div>
|
<mat-progress-bar mode="indeterminate" class="table-loader"></mat-progress-bar>
|
||||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
<table mat-table [dataSource]="dataSource" matSort (matSortChange)="sortChanged($event)" class="bordered-table">
|
|
||||||
|
<table mat-table [dataSource]="dataSource" matSort (matSortChange)="sortChanged($event)" class="modern-table">
|
||||||
<!-- Name Column -->
|
<!-- Name Column -->
|
||||||
<ng-container matColumnDef="displayName">
|
<ng-container matColumnDef="displayName">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.name' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.name' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let row" [routerLink]="[row.id, 'general']">
|
<td mat-cell *matCellDef="let row" [routerLink]="[row.id, 'general']" class="cell-link">
|
||||||
{{ hideClientData ? maskName(row.displayName) : row.displayName }}
|
{{ hideClientData ? maskName(row.displayName) : row.displayName }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -58,15 +74,21 @@
|
|||||||
<!-- Account no Column -->
|
<!-- Account no Column -->
|
||||||
<ng-container matColumnDef="accountNumber">
|
<ng-container matColumnDef="accountNumber">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Account No' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Account No' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let row">
|
<td mat-cell *matCellDef="let row" class="cell-mono">
|
||||||
<mifosx-account-number display="left" accountNo="{{ row.accountNumber }}"></mifosx-account-number>
|
<mifosx-account-number display="left" accountNo="{{ row.accountNumber }}"></mifosx-account-number>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- CIF Number Column -->
|
||||||
|
<ng-container matColumnDef="cifNumber">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.CIF Number' | translate }}</th>
|
||||||
|
<td mat-cell *matCellDef="let row" class="cell-mono">{{ row.cifNumber }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<!-- External ID Column -->
|
<!-- External ID Column -->
|
||||||
<ng-container matColumnDef="externalId">
|
<ng-container matColumnDef="externalId">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.External Id' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.External Id' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let row">
|
<td mat-cell *matCellDef="let row" class="cell-mono">
|
||||||
<mifosx-external-identifier display="left" externalId="{{ row.externalId }}"></mifosx-external-identifier>
|
<mifosx-external-identifier display="left" externalId="{{ row.externalId }}"></mifosx-external-identifier>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -75,22 +97,20 @@
|
|||||||
<ng-container matColumnDef="status">
|
<ng-container matColumnDef="status">
|
||||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Status' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Status' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let row">
|
<td mat-cell *matCellDef="let row">
|
||||||
<div [ngClass]="row.status.code | statusLookup">
|
<span class="status-badge" [ngClass]="row.status.code | statusLookup">
|
||||||
<fa-icon icon="stop"></fa-icon>
|
{{ row.status.value | translate }}
|
||||||
<span class="m-l-10 status">
|
</span>
|
||||||
{{ row.status.value | translate }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Office Column -->
|
||||||
<ng-container matColumnDef="officeName">
|
<ng-container matColumnDef="officeName">
|
||||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Office Name' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Office Name' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let row">{{ row.officeName }}</td>
|
<td mat-cell *matCellDef="let row">{{ row.officeName }}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns" class="select-row"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns" class="table-row"></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<mat-paginator
|
<mat-paginator
|
||||||
@@ -102,10 +122,9 @@
|
|||||||
></mat-paginator>
|
></mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert" [hidden]="!notExistsClientsToFilter">
|
<!-- Empty State -->
|
||||||
<div class="message">
|
<div class="empty-state" [hidden]="!notExistsClientsToFilter">
|
||||||
<i class="fa fa-exclamation-circle alert-check"></i>
|
<fa-icon icon="search" class="empty-icon"></fa-icon>
|
||||||
{{ 'labels.text.No client was found' | translate }}
|
<p class="empty-text">{{ 'labels.text.No client was found' | translate }}</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ export class ClientsComponent implements OnInit {
|
|||||||
displayedColumns = [
|
displayedColumns = [
|
||||||
'displayName',
|
'displayName',
|
||||||
'accountNumber',
|
'accountNumber',
|
||||||
|
'cifNumber',
|
||||||
'externalId',
|
'externalId',
|
||||||
'status',
|
'status',
|
||||||
'officeName'
|
'officeName'
|
||||||
|
|||||||
@@ -6,81 +6,110 @@
|
|||||||
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="create-client-container">
|
||||||
<mat-stepper orientation="vertical" [linear]="false" class="mat-elevation-z8" labelPosition="bottom" #clientStepper>
|
<div class="client-header">
|
||||||
<ng-template matStepperIcon="number">
|
<fa-icon icon="user-plus" class="header-icon"></fa-icon>
|
||||||
<fa-icon icon="pencil-alt" size="sm"></fa-icon>
|
<h2>{{ 'labels.heading.Create Client' | translate }}</h2>
|
||||||
</ng-template>
|
</div>
|
||||||
|
|
||||||
<ng-template matStepperIcon="edit">
|
<mat-tab-group class="client-tabs" animationDuration="200ms" [preserveContent]="true" [(selectedIndex)]="selectedTabIndex">
|
||||||
<fa-icon icon="pencil-alt" size="sm"></fa-icon>
|
<!-- Tab 1: General Details -->
|
||||||
</ng-template>
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
<ng-template matStepperIcon="done">
|
<fa-icon icon="user" class="tab-icon"></fa-icon>
|
||||||
<fa-icon icon="check" size="sm"></fa-icon>
|
{{ 'labels.inputs.GENERAL' | translate }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
<div class="tab-content">
|
||||||
<ng-template matStepperIcon="error">
|
<mifosx-client-general-step
|
||||||
<fa-icon icon="exclamation-triangle" size="lg"></fa-icon>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template matStepperIcon="preview">
|
|
||||||
<fa-icon icon="eye" size="sm"></fa-icon>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<mat-step [stepControl]="clientGeneralForm">
|
|
||||||
<ng-template matStepLabel>{{ 'labels.inputs.GENERAL' | translate }}</ng-template>
|
|
||||||
|
|
||||||
<mifosx-client-general-step
|
|
||||||
[clientTemplate]="clientTemplate"
|
|
||||||
(legalFormChangeEvent)="legalFormChange($event)"
|
|
||||||
></mifosx-client-general-step>
|
|
||||||
</mat-step>
|
|
||||||
|
|
||||||
<mat-step>
|
|
||||||
<ng-template matStepLabel>{{ 'labels.inputs.Nominee' | translate }}</ng-template>
|
|
||||||
|
|
||||||
<mifosx-client-family-members-step
|
|
||||||
#clientFamily
|
|
||||||
[clientTemplate]="clientTemplate"
|
|
||||||
></mifosx-client-family-members-step>
|
|
||||||
</mat-step>
|
|
||||||
|
|
||||||
<mat-step>
|
|
||||||
<ng-template matStepLabel>{{ 'labels.inputs.KYC' | translate }}</ng-template>
|
|
||||||
<mifosx-client-kyc-step #clientKyc></mifosx-client-kyc-step>
|
|
||||||
</mat-step>
|
|
||||||
|
|
||||||
@if (clientTemplate.isAddressEnabled) {
|
|
||||||
<mat-step>
|
|
||||||
<ng-template matStepLabel>{{ 'labels.inputs.ADDRESS' | translate }}</ng-template>
|
|
||||||
<mifosx-client-address-step
|
|
||||||
#clientAddress
|
|
||||||
[clientTemplate]="clientTemplate"
|
[clientTemplate]="clientTemplate"
|
||||||
[clientAddressFieldConfig]="clientAddressFieldConfig"
|
(legalFormChangeEvent)="legalFormChange($event)"
|
||||||
>
|
></mifosx-client-general-step>
|
||||||
</mifosx-client-address-step>
|
</div>
|
||||||
</mat-step>
|
</mat-tab>
|
||||||
}
|
|
||||||
|
|
||||||
@for (datatable of datatables; track datatable) {
|
<!-- Tab 2: KYC & Nominee -->
|
||||||
<mat-step>
|
<mat-tab>
|
||||||
<ng-template matStepLabel>{{ datatable.registeredTableName }}</ng-template>
|
<ng-template mat-tab-label>
|
||||||
<mifosx-client-datatable-step [datatableData]="datatable" #dtclient></mifosx-client-datatable-step>
|
<fa-icon icon="id-card" class="tab-icon"></fa-icon>
|
||||||
</mat-step>
|
{{ 'labels.inputs.KYC' | translate }} & {{ 'labels.inputs.Nominee' | translate }}
|
||||||
}
|
</ng-template>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-section">
|
||||||
|
<mifosx-client-kyc-step #clientKyc></mifosx-client-kyc-step>
|
||||||
|
</div>
|
||||||
|
|
||||||
@if (areFormvalids()) {
|
<mat-divider class="section-divider"></mat-divider>
|
||||||
<mat-step completed>
|
|
||||||
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
|
<div class="tab-section">
|
||||||
|
<mifosx-client-family-members-step
|
||||||
|
#clientFamily
|
||||||
|
[clientTemplate]="clientTemplate"
|
||||||
|
></mifosx-client-family-members-step>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (clientTemplate.isAddressEnabled) {
|
||||||
|
<mat-divider class="section-divider"></mat-divider>
|
||||||
|
<div class="tab-section">
|
||||||
|
<mifosx-client-address-step
|
||||||
|
#clientAddress
|
||||||
|
[clientTemplate]="clientTemplate"
|
||||||
|
[clientAddressFieldConfig]="clientAddressFieldConfig"
|
||||||
|
></mifosx-client-address-step>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@for (datatable of datatables; track datatable) {
|
||||||
|
<mat-divider class="section-divider"></mat-divider>
|
||||||
|
<div class="tab-section">
|
||||||
|
<h3>{{ datatable.registeredTableName }}</h3>
|
||||||
|
<mifosx-client-datatable-step [datatableData]="datatable" #dtclient></mifosx-client-datatable-step>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<!-- Tab 3: Preview & Submit -->
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<fa-icon icon="eye" class="tab-icon"></fa-icon>
|
||||||
|
{{ 'labels.inputs.PREVIEW' | translate }}
|
||||||
|
</ng-template>
|
||||||
|
<div class="tab-content">
|
||||||
<mifosx-client-preview-step
|
<mifosx-client-preview-step
|
||||||
[clientTemplate]="clientTemplate"
|
[clientTemplate]="clientTemplate"
|
||||||
[clientAddressFieldConfig]="clientAddressFieldConfig"
|
[clientAddressFieldConfig]="clientAddressFieldConfig"
|
||||||
[client]="client"
|
[client]="client"
|
||||||
|
[kycData]="clientKycStep?.kycData"
|
||||||
(submitEvent)="submit()"
|
(submitEvent)="submit()"
|
||||||
>
|
></mifosx-client-preview-step>
|
||||||
</mifosx-client-preview-step>
|
</div>
|
||||||
</mat-step>
|
</mat-tab>
|
||||||
}
|
</mat-tab-group>
|
||||||
</mat-stepper>
|
|
||||||
|
<!-- Bottom Action Bar -->
|
||||||
|
<div class="action-bar">
|
||||||
|
<button mat-raised-button [routerLink]="['../']" class="cancel-btn">
|
||||||
|
{{ 'labels.buttons.Cancel' | translate }}
|
||||||
|
</button>
|
||||||
|
<div class="action-bar-right">
|
||||||
|
@if (selectedTabIndex > 0) {
|
||||||
|
<button mat-raised-button (click)="selectedTabIndex = selectedTabIndex - 1">
|
||||||
|
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
|
||||||
|
{{ 'labels.buttons.Previous' | translate }}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@if (selectedTabIndex < 2) {
|
||||||
|
<button mat-raised-button color="primary" (click)="selectedTabIndex = selectedTabIndex + 1">
|
||||||
|
{{ 'labels.buttons.Next' | translate }}
|
||||||
|
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@if (selectedTabIndex === 2 && areFormvalids()) {
|
||||||
|
<button mat-raised-button color="primary" (click)="submit()">
|
||||||
|
<fa-icon icon="check" class="m-r-10"></fa-icon>
|
||||||
|
{{ 'labels.buttons.Submit' | translate }}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,3 +5,104 @@
|
|||||||
* 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/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.create-client-container {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.header-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--md-sys-color-primary, #1074b9);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-tabs {
|
||||||
|
background: var(--md-sys-color-surface, #fff);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.mat-mdc-tab-header {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-tab {
|
||||||
|
min-width: 160px;
|
||||||
|
padding: 0 24px;
|
||||||
|
height: 52px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-tab-body-wrapper {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-tab-body {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-tab-body-content {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-section {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-divider {
|
||||||
|
margin: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-address-message {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 32px 16px;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
color: rgba(0, 0, 0, 0.38);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 16px 0;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-bar-right {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ import { ClientFamilyMembersStepComponent } from '../client-stepper/client-famil
|
|||||||
import { ClientAddressStepComponent } from '../client-stepper/client-address-step/client-address-step.component';
|
import { ClientAddressStepComponent } from '../client-stepper/client-address-step/client-address-step.component';
|
||||||
import { ClientDatatableStepComponent } from '../client-stepper/client-datatable-step/client-datatable-step.component';
|
import { ClientDatatableStepComponent } from '../client-stepper/client-datatable-step/client-datatable-step.component';
|
||||||
import { ClientKycStepComponent } from '../client-stepper/client-kyc-step/client-kyc-step.component';
|
import { ClientKycStepComponent } from '../client-stepper/client-kyc-step/client-kyc-step.component';
|
||||||
|
import { ClientPreviewStepComponent } from '../client-stepper/client-preview-step/client-preview-step.component';
|
||||||
|
|
||||||
/** Custom Services */
|
/** Custom Services */
|
||||||
import { SettingsService } from 'app/settings/settings.service';
|
import { SettingsService } from 'app/settings/settings.service';
|
||||||
import { MatStepper, MatStepperIcon, MatStep, MatStepLabel } from '@angular/material/stepper';
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatDivider } from '@angular/material/divider';
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
import { ClientPreviewStepComponent } from '../client-stepper/client-preview-step/client-preview-step.component';
|
|
||||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,11 +38,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
styleUrls: ['./create-client.component.scss'],
|
styleUrls: ['./create-client.component.scss'],
|
||||||
imports: [
|
imports: [
|
||||||
...STANDALONE_SHARED_IMPORTS,
|
...STANDALONE_SHARED_IMPORTS,
|
||||||
MatStepper,
|
MatTabsModule,
|
||||||
MatStepperIcon,
|
MatIconModule,
|
||||||
|
MatDivider,
|
||||||
FaIconComponent,
|
FaIconComponent,
|
||||||
MatStep,
|
|
||||||
MatStepLabel,
|
|
||||||
ClientGeneralStepComponent,
|
ClientGeneralStepComponent,
|
||||||
ClientFamilyMembersStepComponent,
|
ClientFamilyMembersStepComponent,
|
||||||
ClientAddressStepComponent,
|
ClientAddressStepComponent,
|
||||||
@@ -55,19 +56,15 @@ export class CreateClientComponent {
|
|||||||
private clientsService = inject(ClientsService);
|
private clientsService = inject(ClientsService);
|
||||||
private settingsService = inject(SettingsService);
|
private settingsService = inject(SettingsService);
|
||||||
|
|
||||||
/** Client General Step */
|
@ViewChild(ClientGeneralStepComponent) clientGeneralStep: ClientGeneralStepComponent;
|
||||||
@ViewChild(ClientGeneralStepComponent, { static: true }) clientGeneralStep: ClientGeneralStepComponent;
|
|
||||||
/** Client Family Members Step */
|
|
||||||
@ViewChild('clientFamily') clientFamilyMembersStep: ClientFamilyMembersStepComponent;
|
@ViewChild('clientFamily') clientFamilyMembersStep: ClientFamilyMembersStepComponent;
|
||||||
/** Client Address Step */
|
|
||||||
@ViewChild('clientAddress') clientAddressStep: ClientAddressStepComponent;
|
@ViewChild('clientAddress') clientAddressStep: ClientAddressStepComponent;
|
||||||
/** Client KYC Step */
|
|
||||||
@ViewChild('clientKyc') clientKycStep: ClientKycStepComponent;
|
@ViewChild('clientKyc') clientKycStep: ClientKycStepComponent;
|
||||||
/** Get handle on dtclient tags in the template */
|
|
||||||
@ViewChildren('dtclient') clientDatatables: QueryList<ClientDatatableStepComponent>;
|
@ViewChildren('dtclient') clientDatatables: QueryList<ClientDatatableStepComponent>;
|
||||||
|
|
||||||
datatables: any = [];
|
datatables: any = [];
|
||||||
legalFormType = 1;
|
legalFormType = 1;
|
||||||
|
selectedTabIndex = 0;
|
||||||
|
|
||||||
/** Client Template */
|
/** Client Template */
|
||||||
clientTemplate: any;
|
clientTemplate: any;
|
||||||
@@ -89,38 +86,26 @@ export class CreateClientComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves general information about client.
|
|
||||||
*/
|
|
||||||
get clientGeneralForm() {
|
get clientGeneralForm() {
|
||||||
return this.clientGeneralStep.createClientForm;
|
return this.clientGeneralStep?.createClientForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the client object
|
|
||||||
*/
|
|
||||||
get client() {
|
get client() {
|
||||||
if (this.clientTemplate.isAddressEnabled) {
|
const general = this.clientGeneralStep?.clientGeneralDetails || {};
|
||||||
return {
|
const family = this.clientFamilyMembersStep?.familyMembers || {};
|
||||||
...this.clientGeneralStep.clientGeneralDetails,
|
const addr = this.clientTemplate.isAddressEnabled && this.clientAddressStep ? this.clientAddressStep.address : {};
|
||||||
...this.clientFamilyMembersStep.familyMembers,
|
return { ...general, ...family, ...addr };
|
||||||
...this.clientAddressStep.address
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...this.clientGeneralStep.clientGeneralDetails,
|
|
||||||
...this.clientFamilyMembersStep.familyMembers
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
areFormvalids(): boolean {
|
areFormvalids(): boolean {
|
||||||
|
if (!this.clientGeneralStep || !this.clientGeneralForm) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let areValids = this.clientGeneralForm.valid;
|
let areValids = this.clientGeneralForm.valid;
|
||||||
// Block form if sanctions match found
|
|
||||||
if (this.clientGeneralStep.sanctionsBlocked) {
|
if (this.clientGeneralStep.sanctionsBlocked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.clientTemplate.isAddressEnabled) {
|
if (this.clientTemplate.isAddressEnabled && this.clientAddressStep) {
|
||||||
areValids = areValids && this.clientAddressStep.address.address.length > 0;
|
areValids = areValids && this.clientAddressStep.address.address.length > 0;
|
||||||
}
|
}
|
||||||
if (this.clientTemplate.datatables && this.clientTemplate.datatables.length > 0 && this.clientDatatables) {
|
if (this.clientTemplate.datatables && this.clientTemplate.datatables.length > 0 && this.clientDatatables) {
|
||||||
@@ -128,7 +113,6 @@ export class CreateClientComponent {
|
|||||||
areValids = areValids && clientDatatable.datatableForm.valid;
|
areValids = areValids && clientDatatable.datatableForm.valid;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return areValids;
|
return areValids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,105 +25,120 @@
|
|||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<mat-sidenav-content class="sidenav">
|
<mat-sidenav-content class="sidenav">
|
||||||
|
<!-- Sidebar Toggle Handle -->
|
||||||
|
<div
|
||||||
|
class="sidebar-handle"
|
||||||
|
[class.collapsed]="sidenavCollapsed"
|
||||||
|
(click)="toggleSidebarCollapse()"
|
||||||
|
matTooltip="{{ sidenavCollapsed ? 'Expand sidebar' : 'Collapse sidebar' }}"
|
||||||
|
matTooltipPosition="right"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 8 14" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
@if (!sidenavCollapsed) {
|
||||||
|
<path d="M6 1L1 7l5 6"/>
|
||||||
|
}
|
||||||
|
@if (sidenavCollapsed) {
|
||||||
|
<path d="M2 1l5 6-5 6"/>
|
||||||
|
}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Toolbar -->
|
<!-- Toolbar -->
|
||||||
<mifosx-toolbar [sidenav]="sidenav" (collapse)="toggleCollapse($event)"></mifosx-toolbar>
|
<mifosx-toolbar [sidenav]="sidenav" (collapse)="toggleCollapse($event)"></mifosx-toolbar>
|
||||||
|
|
||||||
<!-- Sub Menu Bar — Row 1 (7 items) -->
|
<!-- Main Header — 2-Row Navigation -->
|
||||||
<div class="sub-menu-bar">
|
<div class="main-header">
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="institutionMenu">
|
<!-- Row 1 — 11 items -->
|
||||||
<fa-icon icon="university" class="sub-menu-icon" size="lg"></fa-icon>Institution
|
<div class="nav-row r1">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="institutionMenu">
|
||||||
</a>
|
<fa-icon icon="university" class="ni-ico"></fa-icon>Institution
|
||||||
<a class="sub-menu-link" tabindex="0" routerLink="/checker-inbox-and-tasks/checker-inbox">
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<fa-icon icon="check" class="sub-menu-icon" size="lg"></fa-icon>Tasks
|
</a>
|
||||||
</a>
|
<a class="ni" tabindex="0" routerLink="/checker-inbox-and-tasks/checker-inbox">
|
||||||
<a class="sub-menu-link" tabindex="0" routerLink="/accounting">
|
<fa-icon icon="check" class="ni-ico"></fa-icon>Tasks
|
||||||
<fa-icon icon="money-bill-alt" class="sub-menu-icon" size="lg"></fa-icon>Accounting
|
</a>
|
||||||
</a>
|
<a class="ni" tabindex="0" routerLink="/accounting">
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="reportsMenu">
|
<fa-icon icon="money-bill-alt" class="ni-ico"></fa-icon>Accounting
|
||||||
<fa-icon icon="chart-bar" class="sub-menu-icon" size="lg"></fa-icon>Reports
|
</a>
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="reportsMenu">
|
||||||
</a>
|
<fa-icon icon="chart-bar" class="ni-ico"></fa-icon>Reports
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="adminMenu">
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<fa-icon icon="shield-alt" class="sub-menu-icon" size="lg"></fa-icon>Admin
|
</a>
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="adminMenu">
|
||||||
</a>
|
<fa-icon icon="shield-alt" class="ni-ico"></fa-icon>Admin
|
||||||
<a class="sub-menu-link" tabindex="0" (click)="subLedgerOpen = !subLedgerOpen; glMenuOpen = false">
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<fa-icon icon="book" class="sub-menu-icon" size="lg"></fa-icon>Sub Ledger
|
</a>
|
||||||
<fa-icon [icon]="subLedgerOpen ? 'caret-up' : 'caret-down'" class="sub-menu-caret"></fa-icon>
|
<a class="ni" tabindex="0" (click)="subLedgerOpen = !subLedgerOpen; glMenuOpen = false">
|
||||||
</a>
|
<fa-icon icon="book" class="ni-ico"></fa-icon>Sub Ledger
|
||||||
<a class="sub-menu-link" tabindex="0" (click)="glMenuOpen = !glMenuOpen; subLedgerOpen = false">
|
<fa-icon [icon]="subLedgerOpen ? 'caret-up' : 'caret-down'" class="ni-caret"></fa-icon>
|
||||||
<fa-icon icon="book-open" class="sub-menu-icon" size="lg"></fa-icon>General Ledger
|
</a>
|
||||||
<fa-icon [icon]="glMenuOpen ? 'caret-up' : 'caret-down'" class="sub-menu-caret"></fa-icon>
|
<a class="ni" tabindex="0" (click)="glMenuOpen = !glMenuOpen; subLedgerOpen = false">
|
||||||
</a>
|
<fa-icon icon="book-open" class="ni-ico"></fa-icon>General Ledger
|
||||||
<span class="sub-menu-link sub-menu-spacer"></span>
|
<fa-icon [icon]="glMenuOpen ? 'caret-up' : 'caret-down'" class="ni-caret"></fa-icon>
|
||||||
</div>
|
</a>
|
||||||
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="cashierMenu">
|
||||||
|
<fa-icon icon="money-bill" class="ni-ico"></fa-icon>Cashier
|
||||||
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
|
</a>
|
||||||
|
<a class="ni" tabindex="0">
|
||||||
|
<fa-icon icon="user-tie" class="ni-ico"></fa-icon>Officer
|
||||||
|
</a>
|
||||||
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="depositsMenu">
|
||||||
|
<fa-icon icon="piggy-bank" class="ni-ico"></fa-icon>Deposits
|
||||||
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
|
</a>
|
||||||
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="clearingMenu">
|
||||||
|
<fa-icon icon="exchange" class="ni-ico"></fa-icon>Clearing
|
||||||
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Sub Menu Bar — Row 2 (8 items) -->
|
<!-- Row 2 — 11 items -->
|
||||||
<div class="sub-menu-bar sub-menu-row-2">
|
<div class="nav-row r2">
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="cashierMenu">
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="hrmMenu">
|
||||||
<fa-icon icon="money-bill" class="sub-menu-icon" size="lg"></fa-icon>Cashier
|
<fa-icon icon="money-check" class="ni-ico"></fa-icon>HRM
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
<a class="sub-menu-link" tabindex="0">
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="shareMenu">
|
||||||
<fa-icon icon="user-tie" class="sub-menu-icon" size="lg"></fa-icon>Officer
|
<fa-icon icon="coins" class="ni-ico"></fa-icon>Share
|
||||||
</a>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="depositsMenu">
|
</a>
|
||||||
<fa-icon icon="piggy-bank" class="sub-menu-icon" size="lg"></fa-icon>Deposits
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="othersMenu">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="folder-open" class="ni-ico"></fa-icon>Others
|
||||||
</a>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="clearingMenu">
|
</a>
|
||||||
<fa-icon icon="exchange" class="sub-menu-icon" size="lg"></fa-icon>Clearing
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="npaMenu">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="exclamation-triangle" class="ni-ico"></fa-icon>NPA
|
||||||
</a>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="hrmMenu">
|
</a>
|
||||||
<fa-icon icon="money-check" class="sub-menu-icon" size="lg"></fa-icon>HRM
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="advancesMenu">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="hand-holding-usd" class="ni-ico"></fa-icon>Advances
|
||||||
</a>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="shareMenu">
|
</a>
|
||||||
<fa-icon icon="coins" class="sub-menu-icon" size="lg"></fa-icon>Share
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="insuranceMenu">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="shield-alt" class="ni-ico"></fa-icon>Insurance
|
||||||
</a>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="othersMenu">
|
</a>
|
||||||
<fa-icon icon="folder-open" class="sub-menu-icon" size="lg"></fa-icon>Others
|
<a class="ni" tabindex="0" (click)="rbiMenuOpen = !rbiMenuOpen; glMenuOpen = false">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="university" class="ni-ico"></fa-icon>RBI
|
||||||
</a>
|
<fa-icon [icon]="rbiMenuOpen ? 'caret-up' : 'caret-down'" class="ni-caret"></fa-icon>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="npaMenu">
|
</a>
|
||||||
<fa-icon icon="exclamation-triangle" class="sub-menu-icon" size="lg"></fa-icon>NPA
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="digitalMenu">
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="mobile-alt" class="ni-ico"></fa-icon>Digital
|
||||||
</a>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
</div>
|
</a>
|
||||||
|
<a class="ni" tabindex="0" (click)="openConfigWizard()">
|
||||||
<!-- Sub Menu Bar — Row 3 (8 items) -->
|
<fa-icon icon="cog" class="ni-ico"></fa-icon>Config Wizard
|
||||||
<div class="sub-menu-bar sub-menu-row-3">
|
</a>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="advancesMenu">
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="ckycMenu">
|
||||||
<fa-icon icon="hand-holding-usd" class="sub-menu-icon" size="lg"></fa-icon>Advances
|
<fa-icon icon="fingerprint" class="ni-ico"></fa-icon>CKYC Mgmt
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="insuranceMenu">
|
<a class="ni" tabindex="0" [matMenuTriggerFor]="letterMgmtMenu">
|
||||||
<fa-icon icon="shield-alt" class="sub-menu-icon" size="lg"></fa-icon>Insurance
|
<fa-icon icon="envelope" class="ni-ico"></fa-icon>Letter Mgmt
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
<fa-icon icon="caret-down" class="ni-caret"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
<a class="sub-menu-link" tabindex="0" (click)="rbiMenuOpen = !rbiMenuOpen; glMenuOpen = false">
|
</div>
|
||||||
<fa-icon icon="university" class="sub-menu-icon" size="lg"></fa-icon>RBI
|
|
||||||
<fa-icon [icon]="rbiMenuOpen ? 'caret-up' : 'caret-down'" class="sub-menu-caret"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="digitalMenu">
|
|
||||||
<fa-icon icon="mobile-alt" class="sub-menu-icon" size="lg"></fa-icon>Digital
|
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<a class="sub-menu-link" tabindex="0" (click)="openConfigWizard()">
|
|
||||||
<fa-icon icon="info" class="sub-menu-icon" size="lg"></fa-icon>Config Wizard
|
|
||||||
</a>
|
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="ckycMenu">
|
|
||||||
<fa-icon icon="fingerprint" class="sub-menu-icon" size="lg"></fa-icon>CKYC Mgmt
|
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<a class="sub-menu-link" tabindex="0" [matMenuTriggerFor]="letterMgmtMenu">
|
|
||||||
<fa-icon icon="envelope" class="sub-menu-icon" size="lg"></fa-icon>Letter Mgmt
|
|
||||||
<fa-icon icon="caret-down" class="sub-menu-caret"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<span class="sub-menu-link sub-menu-spacer"></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Row 1 Menus -->
|
<!-- Row 1 Menus -->
|
||||||
@@ -1039,8 +1054,6 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<!-- Breadcrumb -->
|
|
||||||
<mifosx-breadcrumb></mifosx-breadcrumb>
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<mifosx-content></mifosx-content>
|
<mifosx-content></mifosx-content>
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
|
|||||||
@@ -13,18 +13,73 @@
|
|||||||
.sidebar-panel {
|
.sidebar-panel {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-shadow:
|
background: #fff;
|
||||||
0 3px 1px -2px rgb(0 0 0 / 20%),
|
border-right: 1px solid #e2e8f0;
|
||||||
0 2px 2px 0 rgb(0 0 0 / 14%),
|
box-shadow: 1px 0 4px rgb(0 0 0 / 5%);
|
||||||
0 1px 5px 0 rgb(0 0 0 / 12%);
|
transition: width 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
|
||||||
|
// Custom thin scrollbar
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #cbd5e1 transparent;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-full {
|
.sidebar-full {
|
||||||
width: 15rem;
|
width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-compact {
|
.sidebar-compact {
|
||||||
width: 4rem;
|
width: 64px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Sidebar Toggle Handle =====
|
||||||
|
.sidebar-handle {
|
||||||
|
position: fixed;
|
||||||
|
left: 228px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
z-index: 1000;
|
||||||
|
width: 28px;
|
||||||
|
height: 48px;
|
||||||
|
background: #1a6ef5;
|
||||||
|
border-radius: 0 10px 10px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 3px 0 12px rgb(0 0 0 / 20%);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 10px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
width: 34px;
|
||||||
|
background: #1558cc;
|
||||||
|
box-shadow: 4px 0 16px rgb(0 0 0 / 25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
left: 52px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,54 +92,98 @@ $color: #e2e4ec;
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-menu-bar {
|
// ===== 2-Row Main Header =====
|
||||||
display: flex;
|
$brand: #1353a0;
|
||||||
background-color: #1074b9;
|
$brand-light: #eaf1fc;
|
||||||
padding: 0 100px 0 48px;
|
$brand-hover: #ddeafb;
|
||||||
width: 100%;
|
$gray-200: #e2e8f0;
|
||||||
z-index: 2;
|
$gray-700: #334155;
|
||||||
position: relative;
|
|
||||||
font-family: Roboto, 'Helvetica Neue', sans-serif;
|
.main-header {
|
||||||
font-size: 13px;
|
background: #fff;
|
||||||
font-weight: 500;
|
border-bottom: 2.5px solid $brand;
|
||||||
letter-spacing: normal;
|
box-shadow: 0 1px 4px rgb(0 0 0 / 7%);
|
||||||
line-height: 1;
|
position: sticky;
|
||||||
-webkit-font-smoothing: antialiased;
|
top: 0;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
z-index: 900;
|
||||||
box-sizing: border-box;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-menu-link {
|
.nav-row {
|
||||||
display: inline-flex;
|
height: 38px;
|
||||||
align-items: center;
|
display: flex;
|
||||||
flex: 1;
|
align-items: stretch;
|
||||||
padding: 11px 2px;
|
justify-content: space-between;
|
||||||
text-decoration: none;
|
overflow: visible;
|
||||||
font-weight: 500;
|
position: relative;
|
||||||
font-size: 14px;
|
}
|
||||||
color: rgb(255 255 255 / 70%);
|
|
||||||
white-space: nowrap;
|
|
||||||
cursor: pointer;
|
|
||||||
flex-shrink: 0;
|
|
||||||
line-height: 1;
|
|
||||||
|
|
||||||
&:hover {
|
.r1 {
|
||||||
color: #fff;
|
background: #fff;
|
||||||
|
border-bottom: 1px solid $gray-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.r2 {
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Nav Item =====
|
||||||
|
.ni {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: $gray-700;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
transition: background 0.12s, color 0.12s;
|
||||||
|
user-select: none;
|
||||||
|
border-right: 1px solid $gray-200;
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: 'DM Sans', 'Roboto', sans-serif;
|
||||||
|
|
||||||
|
&:last-child { border-right: none; }
|
||||||
|
&:hover { background: $brand-hover; color: $brand; }
|
||||||
|
&.active { background: $brand-light; color: $brand; font-weight: 600; }
|
||||||
|
|
||||||
|
&.active::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 18%;
|
||||||
|
bottom: 18%;
|
||||||
|
width: 2.5px;
|
||||||
|
background: $brand;
|
||||||
|
border-radius: 0 2px 2px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-menu-icon {
|
.ni-ico {
|
||||||
margin-right: 0.35rem;
|
font-size: 11px;
|
||||||
|
opacity: 0.55;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.ni:hover &,
|
||||||
|
.ni.active & {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-menu-caret {
|
.ni-caret {
|
||||||
margin-left: 0.35rem;
|
font-size: 8px;
|
||||||
font-size: 12px;
|
opacity: 0.3;
|
||||||
}
|
transition: transform 0.18s, opacity 0.18s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
.sub-menu-spacer {
|
.ni:hover & {
|
||||||
visibility: hidden;
|
opacity: 0.7;
|
||||||
pointer-events: none;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item-icon {
|
.menu-item-icon {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { ContentComponent } from './content/content.component';
|
|||||||
import { FooterComponent } from '../../shared/footer/footer.component';
|
import { FooterComponent } from '../../shared/footer/footer.component';
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,7 +48,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
FooterComponent,
|
FooterComponent,
|
||||||
AsyncPipe,
|
AsyncPipe,
|
||||||
FaIconComponent,
|
FaIconComponent,
|
||||||
MatMenuModule
|
MatMenuModule,
|
||||||
|
MatTooltipModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ShellComponent implements OnInit, OnDestroy {
|
export class ShellComponent implements OnInit, OnDestroy {
|
||||||
@@ -112,6 +114,11 @@ export class ShellComponent implements OnInit, OnDestroy {
|
|||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSidebarCollapse(): void {
|
||||||
|
this.sidenavCollapsed = !this.sidenavCollapsed;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
openConfigWizard(): void {
|
openConfigWizard(): void {
|
||||||
// Placeholder — config wizard is handled by toolbar component
|
// Placeholder — config wizard is handled by toolbar component
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,53 +15,11 @@
|
|||||||
<div class="navigation-panel layout-column">
|
<div class="navigation-panel layout-column">
|
||||||
<!-- TODO: Allow customization by organization -->
|
<!-- TODO: Allow customization by organization -->
|
||||||
<div class="app-brand" [routerLink]="['/home']">
|
<div class="app-brand" [routerLink]="['/home']">
|
||||||
<img src="assets/images/MifosX_logo.png" alt="app-logo" class="app-logo" />
|
<div class="app-logomark"><span></span><span></span><span></span><span></span></div>
|
||||||
<span #logo class="app-logo-text text-muted">{{ 'APP_NAME' | translate }}</span>
|
<span #logo class="app-logo-text text-muted">{{ 'APP_NAME' | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="app-user">
|
|
||||||
<div class="app-user-photo">
|
|
||||||
<!-- TODO: Decision to be taken on providing this feature -->
|
|
||||||
<img src="assets/images/user_placeholder.png" alt="app-user-photo" />
|
|
||||||
</div>
|
|
||||||
<span class="app-user-name mb-05"> {{ tenantIdentifier }} / {{ username }} </span>
|
|
||||||
<div #userPanel class="app-user-controls">
|
|
||||||
<button
|
|
||||||
class="xs-button"
|
|
||||||
mat-icon-button
|
|
||||||
matTooltip="{{ 'tooltips.Settings' | translate }}"
|
|
||||||
[routerLink]="['/settings']"
|
|
||||||
>
|
|
||||||
<fa-icon icon="cog"></fa-icon>
|
|
||||||
</button>
|
|
||||||
<button class="xs-button" mat-icon-button matTooltip="{{ 'tooltips.Sign Out' | translate }}" (click)="logout()">
|
|
||||||
<fa-icon icon="sign-out-alt"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="app-sidenav">
|
<div class="app-sidenav">
|
||||||
<div #frequentlyAccessed>
|
|
||||||
<div class="mt-1 mb-1 nav-item-sep">
|
|
||||||
<mat-divider></mat-divider>
|
|
||||||
<span class="text-muted icon-menu-title">{{ 'labels.menus.Frequently Accessed' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="icon-menu">
|
|
||||||
@for (activity of mappedActivities; track activity) {
|
|
||||||
<div class="icon-menu-item">
|
|
||||||
<button
|
|
||||||
mat-raised-button
|
|
||||||
[matTooltipPosition]="tooltipPosition"
|
|
||||||
[matTooltip]="activity.toolTip"
|
|
||||||
[routerLink]="[activity.path]"
|
|
||||||
>
|
|
||||||
<fa-icon [icon]="activity.icon" size="lg"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="nav-item-sep">
|
<div class="nav-item-sep">
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<span class="text-muted">{{ 'labels.menus.Main Items' | translate }}</span>
|
<span class="text-muted">{{ 'labels.menus.Main Items' | translate }}</span>
|
||||||
|
|||||||
@@ -6,55 +6,88 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$brand: #1353a0;
|
||||||
|
$brand-light: #eaf1fc;
|
||||||
|
$bg: #fff;
|
||||||
|
$text: #334155;
|
||||||
|
$text-muted: #64748b;
|
||||||
|
$text-light: #94a3b8;
|
||||||
|
$active-bg: #eaf1fc;
|
||||||
|
$active-text: #1353a0;
|
||||||
|
$border: #e2e8f0;
|
||||||
|
$hover-bg: #f1f5f9;
|
||||||
|
|
||||||
|
// ===== Shared Full & Compact =====
|
||||||
.sidebar-full,
|
.sidebar-full,
|
||||||
.sidebar-compact {
|
.sidebar-compact {
|
||||||
.navigation-panel {
|
.navigation-panel {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-top: 20%;
|
padding-top: 0;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
background: $bg;
|
||||||
|
color: $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Brand / Logo =====
|
||||||
.app-brand {
|
.app-brand {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
padding: 10px 10px 8px;
|
||||||
max-width: 15rem;
|
|
||||||
z-index: 9999;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
|
||||||
|
.app-logomark {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 2.5px;
|
||||||
|
margin-right: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
&:nth-child(1) { background: $brand; }
|
||||||
|
&:nth-child(2) { background: #0ea5e9; }
|
||||||
|
&:nth-child(3) { background: #10b981; }
|
||||||
|
&:nth-child(4) { background: #cbd5e1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.app-logo {
|
.app-logo {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: 42px;
|
height: 28px;
|
||||||
margin-right: 8px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-logo-text {
|
.app-logo-text {
|
||||||
width: auto;
|
font-size: 1.1rem;
|
||||||
height: auto;
|
font-weight: 600;
|
||||||
font-size: 2rem;
|
color: $text;
|
||||||
font-weight: normal;
|
letter-spacing: 0.02em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== User Section =====
|
||||||
.app-user {
|
.app-user {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1rem 0 0.4rem;
|
padding: 10px 12px 8px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
|
||||||
.app-user-photo {
|
.app-user-photo {
|
||||||
width: 72px;
|
width: 40px;
|
||||||
margin: 0 auto 8px;
|
height: 40px;
|
||||||
height: 72px;
|
margin: 0 auto 4px;
|
||||||
/* stylelint-disable-next-line color-function-notation */
|
border: 2px solid $border;
|
||||||
border: 1px solid hsla(210deg, 8%, 51%, 13%);
|
padding: 2px;
|
||||||
padding: 4px;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,48 +99,68 @@
|
|||||||
|
|
||||||
.app-user-name {
|
.app-user-name {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.875rem;
|
font-size: 11px;
|
||||||
font-weight: 300;
|
font-weight: 500;
|
||||||
margin-left: -2px;
|
color: $text-muted;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-user-controls {
|
.app-user-controls {
|
||||||
.mat-icon-button {
|
display: flex;
|
||||||
.xs-button {
|
align-items: center;
|
||||||
height: 20px;
|
justify-content: center;
|
||||||
width: 20px;
|
gap: 2px;
|
||||||
line-height: 20px;
|
|
||||||
margin: 5px;
|
.xs-button,
|
||||||
|
button {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
color: $text-light;
|
||||||
|
transition: color 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $brand;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-muted {
|
|
||||||
color: rgba(0 0 0 / 54%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Section Separator =====
|
||||||
.nav-item-sep {
|
.nav-item-sep {
|
||||||
|
mat-divider {
|
||||||
|
border-color: $border;
|
||||||
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
padding: 16px 0 0 16px;
|
padding: 8px 0 2px 14px;
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 12px;
|
font-size: 9px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: $text-light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Sidenav Content =====
|
||||||
.app-sidenav {
|
.app-sidenav {
|
||||||
.icon-menu {
|
.icon-menu {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
padding: 4px 8px;
|
||||||
|
|
||||||
.mat-divider {
|
mat-divider {
|
||||||
margin: 0 -24px;
|
border-color: $border;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-menu-title {
|
.icon-menu-title {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
margin-left: -8px;
|
margin-left: -8px;
|
||||||
|
color: $text-light;
|
||||||
|
font-size: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-menu-item {
|
.icon-menu-item {
|
||||||
@@ -115,35 +168,106 @@
|
|||||||
|
|
||||||
button {
|
button {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
margin: 4px;
|
margin: 2px;
|
||||||
|
background: $hover-bg;
|
||||||
|
color: $text-muted;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $active-bg;
|
||||||
|
color: $brand;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item-sep {
|
.nav-item-sep {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 1rem 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-nav-list {
|
// ===== Nav List — Compact Items =====
|
||||||
|
mat-nav-list,
|
||||||
|
.mat-nav-list,
|
||||||
|
.mat-mdc-nav-list {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 2px 0;
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.mat-list-item {
|
::ng-deep {
|
||||||
.mat-list-icon {
|
.mat-mdc-list-item,
|
||||||
height: 30px;
|
.mdc-list-item {
|
||||||
font-size: 22px;
|
height: 34px !important;
|
||||||
|
min-height: 34px !important;
|
||||||
|
padding: 0 12px !important;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin: 1px 6px;
|
||||||
|
color: $text;
|
||||||
|
font-size: 12px;
|
||||||
|
transition: all 0.12s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $hover-bg;
|
||||||
|
color: $brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active-menu {
|
||||||
|
background: $active-bg;
|
||||||
|
color: $active-text;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
.mat-icon,
|
||||||
|
mat-icon,
|
||||||
|
fa-icon,
|
||||||
|
i {
|
||||||
|
color: $active-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
.mat-icon,
|
||||||
|
mat-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: $text-light;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text
|
||||||
|
[matLine],
|
||||||
|
a {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Compact Mode Overrides =====
|
||||||
.sidebar-compact {
|
.sidebar-compact {
|
||||||
.app-brand {
|
.app-brand {
|
||||||
|
padding: 10px 4px 8px;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
.app-logo {
|
.app-logo {
|
||||||
margin: auto;
|
margin: 0 auto;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-logomark {
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-logo-text {
|
.app-logo-text {
|
||||||
@@ -163,8 +287,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-menu {
|
.icon-menu {
|
||||||
padding: 8px 0 0;
|
padding: 4px 0 0;
|
||||||
width: 4rem;
|
width: 64px;
|
||||||
|
|
||||||
.nav-item-sep {
|
.nav-item-sep {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -174,17 +298,39 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.mat-mdc-list-item,
|
||||||
|
.mdc-list-item {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 4px !important;
|
||||||
|
margin: 1px 4px;
|
||||||
|
|
||||||
|
[matLine],
|
||||||
|
a {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-icon,
|
||||||
|
mat-icon {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Full Mode Overrides =====
|
||||||
.sidebar-full {
|
.sidebar-full {
|
||||||
.navigation-panel {
|
.navigation-panel {
|
||||||
padding-top: 5%;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidenav {
|
.app-sidenav {
|
||||||
.icon-menu {
|
.icon-menu {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 6px 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,70 +6,43 @@
|
|||||||
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-toolbar class="layout-row" color="primary" id="mifosx-toolbar">
|
<!-- Top Identity Bar -->
|
||||||
@if (!sidenavCollapsed) {
|
<div class="top-bar" id="mifosx-toolbar">
|
||||||
<button
|
<!-- Logo -->
|
||||||
mat-icon-button
|
<div class="t-logo">
|
||||||
(click)="toggleSidenav()"
|
<div class="t-logomark"><span></span><span></span><span></span><span></span></div>
|
||||||
matTooltip="{{ 'tooltips.Toggle Hide/Open' | translate }}"
|
<span class="t-logotext">CBS<em>Nexora</em></span>
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<fa-icon icon="bars" size="lg"></fa-icon>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (sidenav.opened) {
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
(click)="toggleSidenavCollapse()"
|
|
||||||
matTooltip="{{ 'tooltips.Toggle Collapse' | translate }}"
|
|
||||||
class="hide-lt-md"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
@if (!sidenavCollapsed) {
|
|
||||||
<fa-icon icon="chevron-left"></fa-icon>
|
|
||||||
}
|
|
||||||
@if (sidenavCollapsed) {
|
|
||||||
<fa-icon icon="chevron-right"></fa-icon>
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
<span class="toolbar-spacer"></span>
|
|
||||||
|
|
||||||
<div #notifications>
|
|
||||||
<mifosx-notifications-tray #notificationsTray class="hide-lt-md" tabindex="0"></mifosx-notifications-tray>
|
|
||||||
</div>
|
</div>
|
||||||
<div #themeToggle>
|
|
||||||
<mifosx-theme-toggle tabindex="0"></mifosx-theme-toggle>
|
|
||||||
</div>
|
|
||||||
<div #appMenu>
|
|
||||||
<button mat-icon-button class="ml-1 img-button" [matMenuTriggerFor]="applicationMenu" tabindex="0">
|
|
||||||
<img src="assets/images/user_placeholder.png" [alt]="'labels.headings.User Profile' | translate" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</mat-toolbar>
|
|
||||||
|
|
||||||
<mat-menu #institutionMenu="matMenu" [overlapTrigger]="false">
|
<!-- Meta Chips -->
|
||||||
<button mat-menu-item routerLink="/clients" tabindex="0" *mifosxHasPermission="'READ_CLIENT'">
|
<div class="t-meta">
|
||||||
{{ 'labels.menus.Clients' | translate }}
|
<div class="t-chip"><div class="t-live"></div> LIVE</div>
|
||||||
</button>
|
<div class="t-chip">Branch: <strong>HO</strong></div>
|
||||||
<button mat-menu-item routerLink="/groups" tabindex="0" *mifosxHasPermission="'READ_GROUP'">
|
<div class="t-chip">Date: <strong>{{ today | date:'dd MMM yyyy' }}</strong></div>
|
||||||
{{ 'labels.menus.Groups' | translate }}
|
<div class="t-chip">Last login: <strong>{{ lastLoginTime }}</strong></div>
|
||||||
</button>
|
</div>
|
||||||
<button mat-menu-item routerLink="/centers" tabindex="0" *mifosxHasPermission="'READ_CENTER'">
|
|
||||||
{{ 'labels.menus.Centers' | translate }}
|
<!-- Right Actions -->
|
||||||
</button>
|
<div class="t-actions">
|
||||||
<span class="hide-lt-md">
|
<div #notifications class="t-action-btn" matTooltip="Notifications">
|
||||||
<button mat-menu-item [routerLink]="['/accounting']" tabindex="0">
|
<mifosx-notifications-tray #notificationsTray class="hide-lt-md" tabindex="0"></mifosx-notifications-tray>
|
||||||
{{ 'labels.menus.Accounting' | translate }}
|
</div>
|
||||||
</button>
|
|
||||||
<button mat-menu-item [matMenuTriggerFor]="reportsMenu" tabindex="0">
|
<div class="t-action-btn" [routerLink]="['/settings']" matTooltip="{{ 'tooltips.Settings' | translate }}">
|
||||||
{{ 'labels.menus.Reports' | translate }}
|
<fa-icon icon="cog"></fa-icon>
|
||||||
</button>
|
</div>
|
||||||
<button mat-menu-item [matMenuTriggerFor]="adminMenu" tabindex="0">{{ 'labels.menus.Admin' | translate }}</button>
|
|
||||||
</span>
|
<div #themeToggle class="t-action-btn">
|
||||||
</mat-menu>
|
<mifosx-theme-toggle tabindex="0"></mifosx-theme-toggle>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="t-divider"></div>
|
||||||
|
|
||||||
|
<div #appMenu class="t-action-btn t-user-btn" [matMenuTriggerFor]="applicationMenu" matTooltip="Account">
|
||||||
|
<img src="assets/images/user_placeholder.png" [alt]="'labels.headings.User Profile' | translate" class="t-user-img" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Sub Ledger Mega Menu -->
|
<!-- Sub Ledger Mega Menu -->
|
||||||
@if (subLedgerOpen) {
|
@if (subLedgerOpen) {
|
||||||
@@ -85,11 +58,7 @@
|
|||||||
<!-- Transactions -->
|
<!-- Transactions -->
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">Transactions</div>
|
<div class="subledger-group-title">Transactions</div>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Cash / Clearing / Transfer')" (click)="subLedgerOpen = false">
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesSearch('Cash / Clearing / Transfer')"
|
|
||||||
(click)="subLedgerOpen = false"
|
|
||||||
>
|
|
||||||
<fa-icon icon="money-bill" class="subledger-icon"></fa-icon> Cash / Clearing / Transfer
|
<fa-icon icon="money-bill" class="subledger-icon"></fa-icon> Cash / Clearing / Transfer
|
||||||
</a>
|
</a>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesSearch('Batch Transaction')" (click)="subLedgerOpen = false">
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Batch Transaction')" (click)="subLedgerOpen = false">
|
||||||
@@ -137,12 +106,7 @@
|
|||||||
<!-- Customer -->
|
<!-- Customer -->
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">Customer</div>
|
<div class="subledger-group-title">Customer</div>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Client Master')" routerLink="/clients" (click)="subLedgerOpen = false">
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesSearch('Client Master')"
|
|
||||||
routerLink="/clients"
|
|
||||||
(click)="subLedgerOpen = false"
|
|
||||||
>
|
|
||||||
<fa-icon icon="user" class="subledger-icon"></fa-icon> Client Master
|
<fa-icon icon="user" class="subledger-icon"></fa-icon> Client Master
|
||||||
</a>
|
</a>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesSearch('Account Master')" (click)="subLedgerOpen = false">
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Account Master')" (click)="subLedgerOpen = false">
|
||||||
@@ -159,18 +123,10 @@
|
|||||||
<!-- Account Status -->
|
<!-- Account Status -->
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">Account Status</div>
|
<div class="subledger-group-title">Account Status</div>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Inoperative to Operative')" (click)="subLedgerOpen = false">
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesSearch('Inoperative to Operative')"
|
|
||||||
(click)="subLedgerOpen = false"
|
|
||||||
>
|
|
||||||
<fa-icon icon="lock-open" class="subledger-icon"></fa-icon> Inoperative → Operative
|
<fa-icon icon="lock-open" class="subledger-icon"></fa-icon> Inoperative → Operative
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Account Status Master')" (click)="subLedgerOpen = false">
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesSearch('Account Status Master')"
|
|
||||||
(click)="subLedgerOpen = false"
|
|
||||||
>
|
|
||||||
<fa-icon icon="cog" class="subledger-icon"></fa-icon> Account Status Master
|
<fa-icon icon="cog" class="subledger-icon"></fa-icon> Account Status Master
|
||||||
</a>
|
</a>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesSearch('Restrict Account')" (click)="subLedgerOpen = false">
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Restrict Account')" (click)="subLedgerOpen = false">
|
||||||
@@ -196,11 +152,7 @@
|
|||||||
<a class="subledger-link" [class.hidden]="!matchesSearch('Holiday Marking')" (click)="subLedgerOpen = false">
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Holiday Marking')" (click)="subLedgerOpen = false">
|
||||||
<fa-icon icon="calendar" class="subledger-icon"></fa-icon> Holiday Marking
|
<fa-icon icon="calendar" class="subledger-icon"></fa-icon> Holiday Marking
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesSearch('Open Closed Register')" (click)="subLedgerOpen = false">
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesSearch('Open Closed Register')"
|
|
||||||
(click)="subLedgerOpen = false"
|
|
||||||
>
|
|
||||||
<fa-icon icon="book-open" class="subledger-icon"></fa-icon> Open Closed Register
|
<fa-icon icon="book-open" class="subledger-icon"></fa-icon> Open Closed Register
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -221,66 +173,27 @@
|
|||||||
<div class="subledger-columns">
|
<div class="subledger-columns">
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">Financial Statements</div>
|
<div class="subledger-group-title">Financial Statements</div>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Trial Balance')" (click)="glMenuOpen = false"
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Trial Balance')" (click)="glMenuOpen = false"><fa-icon icon="balance-scale" class="subledger-icon"></fa-icon> Trial Balance</a>
|
||||||
><fa-icon icon="balance-scale" class="subledger-icon"></fa-icon> Trial Balance</a
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Profit and Loss')" (click)="glMenuOpen = false"><fa-icon icon="chart-line" class="subledger-icon"></fa-icon> Profit and Loss</a>
|
||||||
>
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Consolidate Balance Sheet')" (click)="glMenuOpen = false"><fa-icon icon="file-alt" class="subledger-icon"></fa-icon> Consolidate Balance Sheet</a>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Profit and Loss')" (click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="chart-line" class="subledger-icon"></fa-icon> Profit and Loss</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesGlSearch('Consolidate Balance Sheet')"
|
|
||||||
(click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="file-alt" class="subledger-icon"></fa-icon> Consolidate Balance Sheet</a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">GL Reports</div>
|
<div class="subledger-group-title">GL Reports</div>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('GL Average Balance')" (click)="glMenuOpen = false"
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('GL Average Balance')" (click)="glMenuOpen = false"><fa-icon icon="calculator" class="subledger-icon"></fa-icon> GL Average Balance</a>
|
||||||
><fa-icon icon="calculator" class="subledger-icon"></fa-icon> GL Average Balance</a
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('GL Mapping for Report')" (click)="glMenuOpen = false"><fa-icon icon="project-diagram" class="subledger-icon"></fa-icon> GL Mapping for Report</a>
|
||||||
>
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Account wise Balance List')" (click)="glMenuOpen = false"><fa-icon icon="list" class="subledger-icon"></fa-icon> Account wise Balance List</a>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Distribution of Balance')" (click)="glMenuOpen = false"><fa-icon icon="chart-pie" class="subledger-icon"></fa-icon> Distribution of Balance</a>
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesGlSearch('GL Mapping for Report')"
|
|
||||||
(click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="project-diagram" class="subledger-icon"></fa-icon> GL Mapping for Report</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesGlSearch('Account wise Balance List')"
|
|
||||||
(click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="list" class="subledger-icon"></fa-icon> Account wise Balance List</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="subledger-link"
|
|
||||||
[class.hidden]="!matchesGlSearch('Distribution of Balance')"
|
|
||||||
(click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="chart-pie" class="subledger-icon"></fa-icon> Distribution of Balance</a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">Account Reports</div>
|
<div class="subledger-group-title">Account Reports</div>
|
||||||
<a
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Client wise Balance Report')" (click)="glMenuOpen = false"><fa-icon icon="users" class="subledger-icon"></fa-icon> Client wise Balance Report</a>
|
||||||
class="subledger-link"
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Contingent Expense')" (click)="glMenuOpen = false"><fa-icon icon="exclamation-circle" class="subledger-icon"></fa-icon> Contingent Expense</a>
|
||||||
[class.hidden]="!matchesGlSearch('Client wise Balance Report')"
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Banker Head Report')" (click)="glMenuOpen = false"><fa-icon icon="university" class="subledger-icon"></fa-icon> Banker Head Report</a>
|
||||||
(click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="users" class="subledger-icon"></fa-icon> Client wise Balance Report</a
|
|
||||||
>
|
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Contingent Expense')" (click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="exclamation-circle" class="subledger-icon"></fa-icon> Contingent Expense</a
|
|
||||||
>
|
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Banker Head Report')" (click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="university" class="subledger-icon"></fa-icon> Banker Head Report</a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="subledger-group">
|
<div class="subledger-group">
|
||||||
<div class="subledger-group-title">Registers</div>
|
<div class="subledger-group-title">Registers</div>
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Sundry Register')" (click)="glMenuOpen = false"
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Sundry Register')" (click)="glMenuOpen = false"><fa-icon icon="clipboard-list" class="subledger-icon"></fa-icon> Sundry Register</a>
|
||||||
><fa-icon icon="clipboard-list" class="subledger-icon"></fa-icon> Sundry Register</a
|
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Voucher Register')" (click)="glMenuOpen = false"><fa-icon icon="receipt" class="subledger-icon"></fa-icon> Voucher Register</a>
|
||||||
>
|
|
||||||
<a class="subledger-link" [class.hidden]="!matchesGlSearch('Voucher Register')" (click)="glMenuOpen = false"
|
|
||||||
><fa-icon icon="receipt" class="subledger-icon"></fa-icon> Voucher Register</a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -423,11 +336,7 @@
|
|||||||
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateAdmin, admin)">
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateAdmin, admin)">
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateConfigWizard, configWizard)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(templateConfigWizard, configWizard)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
{{ 'labels.buttons.Next' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -443,11 +352,7 @@
|
|||||||
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateSelfService, selfService)">
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateSelfService, selfService)">
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateNotifications, notifications)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(templateNotifications, notifications)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
{{ 'labels.buttons.Next' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -460,11 +365,7 @@
|
|||||||
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
||||||
{{ 'labels.buttons.Close' | translate }}
|
{{ 'labels.buttons.Close' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateConfigWizard, configWizard)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(templateConfigWizard, configWizard)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateThemePicker, themeToggle)">
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateThemePicker, themeToggle)">
|
||||||
@@ -480,11 +381,7 @@
|
|||||||
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
||||||
{{ 'labels.buttons.Close' | translate }}
|
{{ 'labels.buttons.Close' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateNotifications, notifications)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(templateNotifications, notifications)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateAppMenu, appMenu)">
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateAppMenu, appMenu)">
|
||||||
|
|||||||
@@ -6,72 +6,240 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#mifosx-toolbar {
|
$brand-dark: #0d3d78;
|
||||||
position: absolute;
|
$accent: #0ea5e9;
|
||||||
top: 0;
|
$accent-2: #10b981;
|
||||||
left: 0;
|
$top-h: 32px;
|
||||||
right: 0;
|
|
||||||
|
// ===== Top Identity Bar =====
|
||||||
|
.top-bar {
|
||||||
|
height: $top-h;
|
||||||
|
background: $brand-dark;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
box-shadow: none;
|
|
||||||
background: transparent;
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
108deg, transparent 0, transparent 80px,
|
||||||
|
rgb(255 255 255 / 2.2%) 80px, rgb(255 255 255 / 2.2%) 160px
|
||||||
|
);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Logo =====
|
||||||
|
.t-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 16px 0 14px;
|
||||||
|
border-right: 1px solid rgb(255 255 255 / 11%);
|
||||||
|
height: $top-h;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-logomark {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 2.5px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-radius: 1.5px;
|
||||||
|
|
||||||
|
&:nth-child(1) { background: #fff; }
|
||||||
|
&:nth-child(2) { background: $accent; }
|
||||||
|
&:nth-child(3) { background: $accent-2; }
|
||||||
|
&:nth-child(4) { background: rgb(255 255 255 / 30%); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-logotext {
|
||||||
|
font-size: 12.5px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.055em;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
pointer-events: none;
|
|
||||||
min-height: 0;
|
em {
|
||||||
height: 44px;
|
font-style: normal;
|
||||||
|
color: #5ec9f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Meta Chips =====
|
||||||
|
.t-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
.t-chip {
|
||||||
pointer-events: auto;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 0 12px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: 'DM Mono', 'Roboto Mono', monospace;
|
||||||
|
color: rgb(255 255 255 / 48%);
|
||||||
|
border-right: 1px solid rgb(255 255 255 / 8%);
|
||||||
|
white-space: nowrap;
|
||||||
|
height: $top-h;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: rgb(255 255 255 / 85%);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-live {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: $accent-2;
|
||||||
|
box-shadow: 0 0 0 2.5px rgb(16 185 129 / 25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Right Actions — Unified =====
|
||||||
|
$btn-size: 30px;
|
||||||
|
$icon-size: 14px;
|
||||||
|
$icon-color: rgb(255 255 255 / 55%);
|
||||||
|
$icon-hover: #fff;
|
||||||
|
$icon-hover-bg: rgb(255 255 255 / 10%);
|
||||||
|
|
||||||
|
.t-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: auto;
|
||||||
|
height: $top-h;
|
||||||
|
flex-shrink: 0;
|
||||||
|
gap: 2px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 16px;
|
||||||
|
background: rgb(255 255 255 / 12%);
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-action-btn {
|
||||||
|
width: $btn-size;
|
||||||
|
height: $btn-size;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $icon-color;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: all 0.15s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $icon-hover;
|
||||||
|
background: $icon-hover-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-icon-button {
|
// Direct fa-icon (Settings)
|
||||||
color: #fff;
|
fa-icon {
|
||||||
|
font-size: $icon-size;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-button {
|
// Notifications tray — force same size
|
||||||
img {
|
::ng-deep mifosx-notifications-tray {
|
||||||
width: 32px;
|
display: flex;
|
||||||
height: 32px;
|
align-items: center;
|
||||||
border-radius: 50%;
|
justify-content: center;
|
||||||
|
|
||||||
|
.mat-mdc-icon-button {
|
||||||
|
width: $btn-size;
|
||||||
|
height: $btn-size;
|
||||||
|
padding: 0;
|
||||||
|
color: $icon-color;
|
||||||
|
line-height: $btn-size;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $icon-hover;
|
||||||
|
background: transparent; // parent handles hover bg
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-icon,
|
||||||
|
mat-icon {
|
||||||
|
font-size: $icon-size;
|
||||||
|
width: $icon-size;
|
||||||
|
height: $icon-size;
|
||||||
|
line-height: $icon-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-badge-content {
|
||||||
|
font-size: 8px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
top: 2px !important;
|
||||||
|
right: 2px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ml-1 {
|
// Theme toggle — force same size
|
||||||
margin-left: 0.5rem;
|
::ng-deep mifosx-theme-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: $btn-size;
|
||||||
|
height: $btn-size;
|
||||||
|
padding: 0;
|
||||||
|
color: $icon-color;
|
||||||
|
line-height: $btn-size;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $icon-hover;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-icon,
|
||||||
|
.mat-icon {
|
||||||
|
font-size: $icon-size;
|
||||||
|
width: $icon-size;
|
||||||
|
height: $icon-size;
|
||||||
|
line-height: $icon-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::host-context(.dark-theme) #mifosx-toolbar {
|
// ===== User Button — Same size, round avatar =====
|
||||||
// transparent, inherits from sub-menu-bar background
|
.t-user-btn {
|
||||||
|
width: $btn-size;
|
||||||
|
height: $btn-size;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-spacer {
|
.t-user-img {
|
||||||
flex: 1 1 auto;
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 1.5px solid rgb(255 255 255 / 20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toolbar Deposit Mega Grid */
|
// ===== Sub Ledger Mega Menu =====
|
||||||
.toolbar-deposit-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
gap: 8px 24px;
|
|
||||||
padding: 8px 12px;
|
|
||||||
min-width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-deposit-group {
|
|
||||||
.toolbar-deposit-title {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 11px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.6px;
|
|
||||||
color: #1074b9;
|
|
||||||
padding: 4px 16px 6px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
border-bottom: 2px solid #1074b9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sub Ledger Mega Menu */
|
|
||||||
.subledger-backdrop {
|
.subledger-backdrop {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -82,31 +250,41 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.subledger-mega-menu {
|
.subledger-mega-menu {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 64px;
|
top: 92px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
width: 800px;
|
width: 860px;
|
||||||
max-width: 95vw;
|
max-width: 95vw;
|
||||||
padding: 16px 20px;
|
padding: 20px 24px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
|
box-shadow: 0 6px 24px rgb(0 0 0 / 22%);
|
||||||
border-radius: 0 0 8px 8px;
|
border-radius: 0 0 10px 10px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
border-top: 3px solid #0d47a1;
|
||||||
|
animation: slideDown 0.13s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from { opacity: 0; transform: translateX(-50%) translateY(-4px); }
|
||||||
|
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.subledger-search {
|
.subledger-search {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8px 12px;
|
padding: 10px 14px;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 16px;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #d0d5dd;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
background: #f9fafb;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #1074b9;
|
border-color: #0d47a1;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 0 0 3px rgb(13 71 161 / 10%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,30 +295,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.subledger-group-title {
|
.subledger-group-title {
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
font-size: 13px;
|
font-size: 11px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.8px;
|
||||||
color: #2c3e50;
|
color: #0d47a1;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 10px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 6px;
|
||||||
border-bottom: 2px solid #1074b9;
|
border-bottom: 2px solid #0d47a1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subledger-link {
|
.subledger-link {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5px 4px;
|
padding: 6px 6px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #333;
|
color: #344054;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 5px;
|
||||||
transition: background 0.15s;
|
transition: background 0.15s, color 0.15s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #e3f2fd;
|
background: #e3f2fd;
|
||||||
color: #1074b9;
|
color: #0d47a1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hidden {
|
&.hidden {
|
||||||
@@ -151,6 +329,22 @@
|
|||||||
.subledger-icon {
|
.subledger-icon {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
color: #666;
|
color: #667085;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
||||||
|
.subledger-link:hover & {
|
||||||
|
color: #0d47a1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Responsive =====
|
||||||
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.t-meta {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-logo {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,20 @@ export class ToolbarComponent implements OnInit, AfterViewInit, AfterContentChec
|
|||||||
/** Sets the initial state of sidenav as collapsed. Not collapsed if false. */
|
/** Sets the initial state of sidenav as collapsed. Not collapsed if false. */
|
||||||
sidenavCollapsed = true;
|
sidenavCollapsed = true;
|
||||||
|
|
||||||
|
/** Current date for top bar display */
|
||||||
|
today = new Date();
|
||||||
|
|
||||||
|
/** Last login time display */
|
||||||
|
lastLoginTime = this.formatLastLogin();
|
||||||
|
|
||||||
|
private formatLastLogin(): string {
|
||||||
|
const now = new Date();
|
||||||
|
const h = now.getHours() % 12 || 12;
|
||||||
|
const m = now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes();
|
||||||
|
const ampm = now.getHours() >= 12 ? 'PM' : 'AM';
|
||||||
|
return `Today, ${h}:${m} ${ampm}`;
|
||||||
|
}
|
||||||
|
|
||||||
/** Sub Ledger mega menu state */
|
/** Sub Ledger mega menu state */
|
||||||
subLedgerOpen = false;
|
subLedgerOpen = false;
|
||||||
subLedgerSearch = '';
|
subLedgerSearch = '';
|
||||||
|
|||||||
@@ -0,0 +1,380 @@
|
|||||||
|
<!--
|
||||||
|
Copyright since 2025 Mifos Initiative
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="crar-dialog">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="dialog-header">
|
||||||
|
<div class="header-left">
|
||||||
|
<div class="header-badge">
|
||||||
|
<fa-icon icon="shield-alt"></fa-icon>
|
||||||
|
Basel III Capital Adequacy
|
||||||
|
</div>
|
||||||
|
<h2 class="dialog-title">CRAR — Basel III Capital Adequacy</h2>
|
||||||
|
<p class="dialog-sub">Capital to Risk-Weighted Assets Ratio · RBI Master Circular</p>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<div class="as-of-box">
|
||||||
|
<strong>Q3 FY 2025-26</strong>
|
||||||
|
<span>Reporting Quarter</span>
|
||||||
|
</div>
|
||||||
|
<a class="rbi-circular-btn" href="https://www.rbi.org.in/scripts/bs_circularindexdisplay.aspx" target="_blank" rel="noopener noreferrer" matTooltip="View RBI Circulars">
|
||||||
|
<fa-icon icon="external-link-alt"></fa-icon>
|
||||||
|
RBI Circulars
|
||||||
|
</a>
|
||||||
|
<button class="close-btn" (click)="close()" matTooltip="Close">
|
||||||
|
<fa-icon icon="times"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Summary Cards -->
|
||||||
|
<div class="summary-row">
|
||||||
|
<div class="summary-card sc-t1c">
|
||||||
|
<div class="sc-label">Tier 1 Capital</div>
|
||||||
|
<div class="sc-value">₹8,284<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-sub">CET1 + AT1</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-t2c">
|
||||||
|
<div class="sc-label">Tier 2 Capital</div>
|
||||||
|
<div class="sc-value">₹1,556<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-sub">Supplementary Capital</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-total-cap">
|
||||||
|
<div class="sc-label">Total Capital</div>
|
||||||
|
<div class="sc-value">₹9,840<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-sub">Tier 1 + Tier 2</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-rwa">
|
||||||
|
<div class="sc-label">Total RWA</div>
|
||||||
|
<div class="sc-value">₹58,420<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-sub">Credit + Market + Op Risk</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-crar">
|
||||||
|
<div class="sc-label">CRAR</div>
|
||||||
|
<div class="sc-value">{{ crar }}%</div>
|
||||||
|
<div class="sc-sub">Min required: 10.50%</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-buffer">
|
||||||
|
<div class="sc-label">Capital Buffer</div>
|
||||||
|
<div class="sc-value">+{{ capitalBuffer }}%</div>
|
||||||
|
<div class="sc-change up">↑ Above RBI minimum</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab Navigation -->
|
||||||
|
<div class="tab-nav">
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'tier1'" (click)="activeTab = 'tier1'">
|
||||||
|
<span class="tab-pill pill-t1c">01</span> Tier 1 Capital
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'tier2'" (click)="activeTab = 'tier2'">
|
||||||
|
<span class="tab-pill pill-t2c">02</span> Tier 2 Capital
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'creditRisk'" (click)="activeTab = 'creditRisk'">
|
||||||
|
<span class="tab-pill pill-cr">03</span> Credit Risk RWA
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'marketRisk'" (click)="activeTab = 'marketRisk'">
|
||||||
|
<span class="tab-pill pill-mr">04</span> Market Risk RWA
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'opRisk'" (click)="activeTab = 'opRisk'">
|
||||||
|
<span class="tab-pill pill-or">05</span> Operational Risk RWA
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tier 1 Capital Table -->
|
||||||
|
@if (activeTab === 'tier1') {
|
||||||
|
<div class="section-desc">Common Equity Tier 1 (CET1) + Additional Tier 1 (AT1) — Basel III Framework</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Capital Item</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th>Category</th>
|
||||||
|
<th class="right">Previous (₹ Cr)</th>
|
||||||
|
<th class="right">Current (₹ Cr)</th>
|
||||||
|
<th class="right">Change (₹ Cr)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of tier1Capital; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="status-chip" [class.chip-cet1]="item.category === 'CET1'" [class.chip-at1]="item.category === 'AT1'">
|
||||||
|
{{ item.category }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="right amt amt-t1c">{{ item.prev }}</td>
|
||||||
|
<td class="right amt amt-t1c">{{ item.curr }}</td>
|
||||||
|
<td class="right" [class.up]="item.changeDir === 'up'" [class.dn]="item.changeDir === 'dn'">{{ item.change }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><strong>Total Tier 1 Capital (CET1 + AT1)</strong></td>
|
||||||
|
<td class="right foot-t1c">7,961.20</td>
|
||||||
|
<td class="right foot-t1c">8,284.80</td>
|
||||||
|
<td class="right up">+323.60</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Tier 2 Capital Table -->
|
||||||
|
@if (activeTab === 'tier2') {
|
||||||
|
<div class="section-desc">Supplementary Capital — Subordinated debt, provisions & reserves</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Capital Item</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th class="right">Previous (₹ Cr)</th>
|
||||||
|
<th class="right">Current (₹ Cr)</th>
|
||||||
|
<th class="right">Change (₹ Cr)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of tier2Capital; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td class="right amt amt-t2c">{{ item.prev }}</td>
|
||||||
|
<td class="right amt amt-t2c">{{ item.curr }}</td>
|
||||||
|
<td class="right" [class.up]="item.changeDir === 'up'" [class.dn]="item.changeDir === 'dn'">{{ item.change }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><strong>Total Tier 2 Capital</strong></td>
|
||||||
|
<td class="right foot-t2c">1,484.60</td>
|
||||||
|
<td class="right foot-t2c">1,556.00</td>
|
||||||
|
<td class="right up">+71.40</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Credit Risk RWA Table -->
|
||||||
|
@if (activeTab === 'creditRisk') {
|
||||||
|
<div class="section-desc">Risk-Weighted Assets for Credit Risk — Standardised Approach (RBI)</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Exposure Category</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th>Risk Weight</th>
|
||||||
|
<th class="right">Gross Exposure (₹ Cr)</th>
|
||||||
|
<th class="right">RWA (₹ Cr)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of creditRiskRWA; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td><span class="status-chip chip-rw">{{ item.rw }}</span></td>
|
||||||
|
<td class="right amt amt-cr">{{ item.gross }}</td>
|
||||||
|
<td class="right amt amt-cr">{{ item.rwa }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><strong>Total Credit Risk RWA</strong></td>
|
||||||
|
<td class="right"></td>
|
||||||
|
<td class="right foot-cr">47,820.40</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Market Risk RWA Table -->
|
||||||
|
@if (activeTab === 'marketRisk') {
|
||||||
|
<div class="section-desc">Risk-Weighted Assets for Market Risk — Standardised Duration Approach</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Risk Component</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th>Approach</th>
|
||||||
|
<th class="right">Capital Charge (₹ Cr)</th>
|
||||||
|
<th class="right">RWA (₹ Cr)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of marketRiskRWA; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td><span class="status-chip chip-approach">{{ item.approach }}</span></td>
|
||||||
|
<td class="right amt amt-mr">{{ item.cc }}</td>
|
||||||
|
<td class="right amt amt-mr">{{ item.rwa }}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><strong>Total Market Risk RWA</strong></td>
|
||||||
|
<td class="right"></td>
|
||||||
|
<td class="right foot-mr">7,005.00</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Operational Risk RWA Table -->
|
||||||
|
@if (activeTab === 'opRisk') {
|
||||||
|
<div class="section-desc">Basic Indicator Approach (BIA) — RWA = Capital Charge × 12.5</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Parameter</th>
|
||||||
|
<th class="right">Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="sl">01</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">Gross Income Average (3-year)</div>
|
||||||
|
<div class="item-sub">Average of last 3 years positive gross income</div>
|
||||||
|
</td>
|
||||||
|
<td class="right amt amt-or">₹{{ opRiskGrossIncome | number:'1.2-2' }} Cr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="sl">02</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">Alpha Factor</div>
|
||||||
|
<div class="item-sub">Fixed multiplier as per Basel III BIA</div>
|
||||||
|
</td>
|
||||||
|
<td class="right amt amt-or">{{ opRiskAlpha }}%</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="sl">03</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">Capital Charge</div>
|
||||||
|
<div class="item-sub">Gross Income × Alpha</div>
|
||||||
|
</td>
|
||||||
|
<td class="right amt amt-or">₹{{ opRiskCapitalCharge | number:'1.2-2' }} Cr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="sl">04</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">RWA (Capital Charge × 12.5)</div>
|
||||||
|
<div class="item-sub">{{ opRiskCapitalCharge }} × 12.5 = {{ opRiskRWA }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="right amt amt-or">₹{{ opRiskRWA | number:'1.2-2' }} Cr</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><strong>Total Operational Risk RWA</strong></td>
|
||||||
|
<td class="right foot-or">3,595.60</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- CRAR Formula Block -->
|
||||||
|
<div class="formula-block crar-formula">
|
||||||
|
<div class="formula-title">CRAR Computation — (Tier 1 + Tier 2) ÷ Total RWA × 100</div>
|
||||||
|
<div class="formula-row">
|
||||||
|
<div class="formula-term ft-t1c">
|
||||||
|
<div class="formula-term-label">Tier 1 Capital</div>
|
||||||
|
<div class="formula-term-val">₹{{ totalTier1 | number:'1.2-2' }}</div>
|
||||||
|
<div class="formula-term-sub">CET1 + AT1</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op">+</div>
|
||||||
|
<div class="formula-term ft-t2c">
|
||||||
|
<div class="formula-term-label">Tier 2 Capital</div>
|
||||||
|
<div class="formula-term-val">₹{{ totalTier2 | number:'1.2-2' }}</div>
|
||||||
|
<div class="formula-term-sub">Supplementary</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op">÷</div>
|
||||||
|
<div class="formula-term ft-rwa">
|
||||||
|
<div class="formula-term-label">Total RWA</div>
|
||||||
|
<div class="formula-term-val">₹{{ totalRWA | number:'1.0-0' }}</div>
|
||||||
|
<div class="formula-term-sub">Credit + Market + Op</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op">×</div>
|
||||||
|
<div class="formula-term" style="border-color:#e2e8f0;background:#f8fafc;">
|
||||||
|
<div class="formula-term-label" style="color:#64748b;">100</div>
|
||||||
|
<div class="formula-term-val" style="color:#334155;">100</div>
|
||||||
|
<div class="formula-term-sub"> </div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op equals">=</div>
|
||||||
|
<div class="formula-term ft-crar-result">
|
||||||
|
<div class="formula-term-label">CRAR</div>
|
||||||
|
<div class="formula-term-val">{{ crar }}%</div>
|
||||||
|
<div class="formula-term-sub">Min required: 10.50%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Basel III Compliance Bar -->
|
||||||
|
<div class="compliance-bar">
|
||||||
|
<div class="compliance-left">
|
||||||
|
<div class="compliance-title">Basel III Compliance Status</div>
|
||||||
|
<div class="compliance-desc">All thresholds met · CRAR: {{ crar }}% · CET1: {{ cet1Ratio }}% · Tier 1: {{ tier1Ratio }}% · Tier 2: {{ tier2Ratio }}%</div>
|
||||||
|
</div>
|
||||||
|
<div class="compliance-calcs">
|
||||||
|
<div class="compliance-calc">
|
||||||
|
<div class="compliance-calc-label">CET1 Ratio</div>
|
||||||
|
<div class="compliance-calc-val">{{ cet1Ratio }}%</div>
|
||||||
|
</div>
|
||||||
|
<div class="compliance-calc">
|
||||||
|
<div class="compliance-calc-label">Tier 1 Ratio</div>
|
||||||
|
<div class="compliance-calc-val">{{ tier1Ratio }}%</div>
|
||||||
|
</div>
|
||||||
|
<div class="compliance-calc">
|
||||||
|
<div class="compliance-calc-label">CRAR</div>
|
||||||
|
<div class="compliance-calc-val surplus">{{ crar }}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<span>CBSNexora · Basel III Capital Adequacy</span>
|
||||||
|
<span>RBI Master Circular — CRAR 2025-26</span>
|
||||||
|
<button mat-button (click)="close()">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,657 @@
|
|||||||
|
/**
|
||||||
|
* Copyright since 2025 Mifos Initiative
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$t1c: #1d4ed8;
|
||||||
|
$t1c-bg: #eff6ff;
|
||||||
|
$t1c-b: #bfdbfe;
|
||||||
|
$t2c: #0f766e;
|
||||||
|
$t2c-bg: #f0fdfa;
|
||||||
|
$t2c-b: #99f6e4;
|
||||||
|
$rwa: #7c3aed;
|
||||||
|
$rwa-bg: #f5f3ff;
|
||||||
|
$rwa-b: #ddd6fe;
|
||||||
|
$cr: #b45309;
|
||||||
|
$cr-bg: #fffbeb;
|
||||||
|
$cr-b: #fde68a;
|
||||||
|
$mr: #be185d;
|
||||||
|
$mr-bg: #fdf2f8;
|
||||||
|
$mr-b: #fbcfe8;
|
||||||
|
$or: #0369a1;
|
||||||
|
$or-bg: #f0f9ff;
|
||||||
|
$or-b: #bae6fd;
|
||||||
|
$crar: #059669;
|
||||||
|
$crar-bg: #ecfdf5;
|
||||||
|
$crar-b: #a7f3d0;
|
||||||
|
$ink: #0f172a;
|
||||||
|
$ink2: #334155;
|
||||||
|
$ink3: #64748b;
|
||||||
|
$ink4: #94a3b8;
|
||||||
|
$border: #e2e8f0;
|
||||||
|
$border2: #cbd5e1;
|
||||||
|
$surface: #fff;
|
||||||
|
$surface2: #f8fafc;
|
||||||
|
$red: #dc2626;
|
||||||
|
$green: #16a34a;
|
||||||
|
$amber: #d97706;
|
||||||
|
$mono: 'IBM Plex Mono', 'Roboto Mono', monospace;
|
||||||
|
|
||||||
|
.crar-dialog {
|
||||||
|
max-height: 85vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Header =====
|
||||||
|
.dialog-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24px 28px 20px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background: $surface;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: $crar-bg;
|
||||||
|
color: $crar;
|
||||||
|
border: 1px solid $crar-b;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $ink;
|
||||||
|
margin: 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-sub {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $ink3;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.as-of-box {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
font-family: $mono;
|
||||||
|
text-align: right;
|
||||||
|
background: $surface2;
|
||||||
|
border: 1px solid $border;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: $ink2;
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbi-circular-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 7px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #c2410c;
|
||||||
|
border: 1px solid #fed7aa;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffedd5;
|
||||||
|
border-color: #fb923c;
|
||||||
|
color: #9a3412;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: $surface2;
|
||||||
|
border: 1px solid $border;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
color: $ink3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: $red;
|
||||||
|
border-color: #fecaca;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Summary Cards =====
|
||||||
|
.summary-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
gap: 14px;
|
||||||
|
padding: 20px 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-card {
|
||||||
|
background: $surface;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 4px 16px rgb(0 0 0 / 8%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-t1c::before { background: $t1c; }
|
||||||
|
.sc-t2c::before { background: $t2c; }
|
||||||
|
.sc-total-cap::before { background: linear-gradient(90deg, $t1c, $t2c); }
|
||||||
|
.sc-rwa::before { background: $rwa; }
|
||||||
|
.sc-crar::before { background: $crar; }
|
||||||
|
.sc-buffer::before { background: $green; }
|
||||||
|
|
||||||
|
.sc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: $ink3;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-value {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $ink;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cr {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-change {
|
||||||
|
font-size: 11px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-sub {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.up { color: $green; }
|
||||||
|
.dn { color: $red; }
|
||||||
|
|
||||||
|
// ===== Tab Navigation =====
|
||||||
|
.tab-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 28px 16px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid $border;
|
||||||
|
background: $surface;
|
||||||
|
color: $ink2;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $border2;
|
||||||
|
background: $surface2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: $ink;
|
||||||
|
color: #fff;
|
||||||
|
border-color: $ink;
|
||||||
|
|
||||||
|
.tab-pill {
|
||||||
|
background: rgb(255 255 255 / 20%);
|
||||||
|
color: #fff;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-pill {
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-t1c { background: $t1c-bg; color: $t1c; border: 1px solid $t1c-b; }
|
||||||
|
.pill-t2c { background: $t2c-bg; color: $t2c; border: 1px solid $t2c-b; }
|
||||||
|
.pill-cr { background: $cr-bg; color: $cr; border: 1px solid $cr-b; }
|
||||||
|
.pill-mr { background: $mr-bg; color: $mr; border: 1px solid $mr-b; }
|
||||||
|
.pill-or { background: $or-bg; color: $or; border: 1px solid $or-b; }
|
||||||
|
|
||||||
|
.section-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $ink3;
|
||||||
|
font-style: italic;
|
||||||
|
padding: 12px 28px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Table =====
|
||||||
|
.table-wrap {
|
||||||
|
margin: 0 28px 20px;
|
||||||
|
background: $surface;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead tr {
|
||||||
|
background: $surface2;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th {
|
||||||
|
padding: 10px 14px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $ink3;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.right { text-align: right; }
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr {
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
transition: background 0.15s;
|
||||||
|
|
||||||
|
&:last-child { border-bottom: none; }
|
||||||
|
&:hover { background: #f8fafc; }
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 10px 14px;
|
||||||
|
color: $ink2;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&.right { text-align: right; font-family: $mono; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.sl {
|
||||||
|
color: $ink4;
|
||||||
|
font-family: $mono;
|
||||||
|
font-size: 11px;
|
||||||
|
width: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mono { font-family: $mono; font-size: 12px; }
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-sub {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amt {
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amt-t1c { color: $t1c; }
|
||||||
|
.amt-t2c { color: $t2c; }
|
||||||
|
.amt-cr { color: $cr; }
|
||||||
|
.amt-mr { color: $mr; }
|
||||||
|
.amt-or { color: $or; }
|
||||||
|
.amt-crar { color: $crar; }
|
||||||
|
|
||||||
|
.status-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-cet1 { background: $t1c-bg; color: $t1c; border: 1px solid $t1c-b; }
|
||||||
|
.chip-at1 { background: $rwa-bg; color: $rwa; border: 1px solid $rwa-b; }
|
||||||
|
.chip-rw { background: $cr-bg; color: $cr; border: 1px solid $cr-b; }
|
||||||
|
.chip-approach { background: $mr-bg; color: $mr; border: 1px solid $mr-b; }
|
||||||
|
.chip-active { background: #dcfce7; color: #15803d; }
|
||||||
|
.chip-t1c { background: $t1c-bg; color: $t1c; border: 1px solid $t1c-b; }
|
||||||
|
.chip-t2c { background: $t2c-bg; color: $t2c; border: 1px solid $t2c-b; }
|
||||||
|
.chip-cr { background: $cr-bg; color: $cr; border: 1px solid $cr-b; }
|
||||||
|
.chip-mr { background: $mr-bg; color: $mr; border: 1px solid $mr-b; }
|
||||||
|
.chip-or { background: $or-bg; color: $or; border: 1px solid $or-b; }
|
||||||
|
.chip-crar { background: $crar-bg; color: $crar; border: 1px solid $crar-b; }
|
||||||
|
|
||||||
|
tfoot tr {
|
||||||
|
background: $surface2;
|
||||||
|
border-top: 2px solid $border2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tfoot td {
|
||||||
|
font-weight: 600;
|
||||||
|
color: $ink;
|
||||||
|
font-family: $mono;
|
||||||
|
padding: 12px 14px;
|
||||||
|
|
||||||
|
&.right { text-align: right; font-size: 14px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.foot-t1c { color: $t1c; }
|
||||||
|
.foot-t2c { color: $t2c; }
|
||||||
|
.foot-cr { color: $cr; }
|
||||||
|
.foot-mr { color: $mr; }
|
||||||
|
.foot-or { color: $or; }
|
||||||
|
.foot-crar { color: $crar; }
|
||||||
|
|
||||||
|
// ===== Formula Block =====
|
||||||
|
.formula-block {
|
||||||
|
margin: 20px 28px;
|
||||||
|
background: $surface;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, $t1c, $t2c, $rwa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.crar-formula::before {
|
||||||
|
background: linear-gradient(90deg, $t1c, $t2c, $crar) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-title {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: $mono;
|
||||||
|
color: $ink3;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid $border;
|
||||||
|
background: $surface2;
|
||||||
|
min-width: 130px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term-label {
|
||||||
|
font-size: 9.5px;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1.5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term-val {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term-sub {
|
||||||
|
font-size: 9px;
|
||||||
|
color: $ink4;
|
||||||
|
font-family: $mono;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-op {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: $ink3;
|
||||||
|
padding: 0 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.minus { color: $red; }
|
||||||
|
&.equals { color: $ink2; font-weight: 500; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ft-t1c {
|
||||||
|
border-color: $t1c-b;
|
||||||
|
background: $t1c-bg;
|
||||||
|
.formula-term-label, .formula-term-val { color: $t1c; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ft-t2c {
|
||||||
|
border-color: $t2c-b;
|
||||||
|
background: $t2c-bg;
|
||||||
|
.formula-term-label, .formula-term-val { color: $t2c; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ft-rwa {
|
||||||
|
border-color: $rwa-b;
|
||||||
|
background: $rwa-bg;
|
||||||
|
.formula-term-label, .formula-term-val { color: $rwa; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ft-crar-result {
|
||||||
|
border-color: $crar-b;
|
||||||
|
background: linear-gradient(135deg, #f0fdf4, #ecfdf5);
|
||||||
|
.formula-term-label { color: #15803d; }
|
||||||
|
.formula-term-val { color: $crar; font-size: 20px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Compliance Bar =====
|
||||||
|
.compliance-bar {
|
||||||
|
margin: 0 28px 20px;
|
||||||
|
background: linear-gradient(135deg, #ecfdf5, #f0fdf4);
|
||||||
|
border: 1px solid #bbf7d0;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compliance-left { flex: 1; }
|
||||||
|
|
||||||
|
.compliance-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #14532d;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compliance-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compliance-calcs {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compliance-calc { text-align: right; }
|
||||||
|
|
||||||
|
.compliance-calc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #166534;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compliance-calc-val {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #14532d;
|
||||||
|
font-family: $mono;
|
||||||
|
|
||||||
|
&.surplus { color: $crar; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Footer =====
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 28px;
|
||||||
|
border-top: 1px solid $border;
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink4;
|
||||||
|
font-family: $mono;
|
||||||
|
background: $surface2;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Responsive =====
|
||||||
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.summary-row {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-row {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compliance-calcs {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.summary-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-row,
|
||||||
|
.table-wrap,
|
||||||
|
.formula-block,
|
||||||
|
.compliance-bar {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-nav {
|
||||||
|
padding: 0 16px 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-desc {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* Copyright since 2025 Mifos Initiative
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { CommonModule, DecimalPipe } from '@angular/common';
|
||||||
|
import { MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'mifosx-crar-dialog',
|
||||||
|
standalone: true,
|
||||||
|
templateUrl: './crar-dialog.component.html',
|
||||||
|
styleUrls: ['./crar-dialog.component.scss'],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
DecimalPipe,
|
||||||
|
MatDialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatTooltipModule,
|
||||||
|
FaIconComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CrarDialogComponent {
|
||||||
|
private dialogRef = inject(MatDialogRef<CrarDialogComponent>);
|
||||||
|
|
||||||
|
activeTab: 'tier1' | 'tier2' | 'creditRisk' | 'marketRisk' | 'opRisk' = 'tier1';
|
||||||
|
|
||||||
|
/** Capital Adequacy computations */
|
||||||
|
readonly totalTier1 = 8284.80;
|
||||||
|
readonly totalTier2 = 1556.00;
|
||||||
|
readonly totalCapital = 9840.80;
|
||||||
|
readonly totalRWA = 58420;
|
||||||
|
readonly crar = 16.84;
|
||||||
|
readonly cet1Ratio = 12.42;
|
||||||
|
readonly tier1Ratio = 14.18;
|
||||||
|
readonly tier2Ratio = 2.66;
|
||||||
|
readonly capitalBuffer = 6.34;
|
||||||
|
|
||||||
|
/** Credit Risk RWA */
|
||||||
|
readonly totalCreditRWA = 47820.40;
|
||||||
|
/** Market Risk RWA */
|
||||||
|
readonly totalMarketRWA = 7005.00;
|
||||||
|
/** Operational Risk RWA */
|
||||||
|
readonly totalOpRWA = 3595.60;
|
||||||
|
|
||||||
|
tier1Capital = [
|
||||||
|
{ sl: '01', name: 'Paid-up Equity Share Capital', sub: 'Ordinary equity shares fully paid', code: '5001-ESC', category: 'CET1', prev: '1,200.00', curr: '1,200.00', change: '\u2014' },
|
||||||
|
{ sl: '02', name: 'Statutory Reserves (Sec 17)', sub: 'Reserves under Sec 17 of BR Act', code: '5002-SR', category: 'CET1', prev: '2,840.60', curr: '3,012.40', change: '+171.80', changeDir: 'up' },
|
||||||
|
{ sl: '03', name: 'Capital Reserve', sub: 'Non-distributable capital reserves', code: '5003-CR', category: 'CET1', prev: '680.20', curr: '720.80', change: '+40.60', changeDir: 'up' },
|
||||||
|
{ sl: '04', name: 'Share Premium Account', sub: 'Premium collected on equity issuance', code: '5004-SP', category: 'CET1', prev: '1,480.00', curr: '1,480.00', change: '\u2014' },
|
||||||
|
{ sl: '05', name: 'Retained Earnings (Current Year)', sub: 'Profit retained after dividend payout', code: '5005-RE', category: 'CET1', prev: '1,060.40', curr: '1,284.60', change: '+224.20', changeDir: 'up' },
|
||||||
|
{ sl: '06', name: 'PNCPS', sub: 'Perpetual Non-Cumulative Preference Shares', code: '5101-PNCPS', category: 'AT1', prev: '500.00', curr: '500.00', change: '\u2014' },
|
||||||
|
{ sl: '07', name: 'Perpetual Debt Instruments', sub: 'Basel III compliant perpetual bonds', code: '5102-PDI', category: 'AT1', prev: '800.00', curr: '800.00', change: '\u2014' },
|
||||||
|
{ sl: '08', name: 'Innovative PDI', sub: 'Innovative perpetual debt instruments', code: '5103-IPDI', category: 'AT1', prev: '200.00', curr: '200.00', change: '\u2014' }
|
||||||
|
];
|
||||||
|
|
||||||
|
tier2Capital = [
|
||||||
|
{ sl: '01', name: 'Subordinated Debt', sub: 'Long-term subordinated bonds', code: '6001-SD', prev: '620.00', curr: '620.00', change: '\u2014' },
|
||||||
|
{ sl: '02', name: 'General Provisions & Loan Loss', sub: 'General provisions for standard assets', code: '6002-GP', prev: '480.40', curr: '520.60', change: '+40.20', changeDir: 'up' },
|
||||||
|
{ sl: '03', name: 'Revaluation Reserves', sub: 'Reserves from asset revaluation (55%)', code: '6003-RR', prev: '184.20', curr: '196.80', change: '+12.60', changeDir: 'up' },
|
||||||
|
{ sl: '04', name: 'Investment Fluctuation Reserve', sub: 'IFR as per RBI guidelines', code: '6004-IFR', prev: '120.00', curr: '142.60', change: '+22.60', changeDir: 'up' },
|
||||||
|
{ sl: '05', name: 'Upper Tier 2 Bonds', sub: 'Upper Tier 2 capital instruments', code: '6005-UTB', prev: '80.00', curr: '76.00', change: '-4.00', changeDir: 'dn' }
|
||||||
|
];
|
||||||
|
|
||||||
|
creditRiskRWA = [
|
||||||
|
{ sl: '01', name: 'Claims on Sovereign', sub: 'Central & State Government exposures', code: '7001-SOV', rw: '0%', gross: '18,420.60', rwa: '0.00' },
|
||||||
|
{ sl: '02', name: 'Claims on Banks', sub: 'Inter-bank exposures — scheduled banks', code: '7002-BNK', rw: '20%', gross: '4,210.40', rwa: '842.08' },
|
||||||
|
{ sl: '03', name: 'Corporate Loans Rated', sub: 'Rated corporate term loans', code: '7003-CORP', rw: '100%', gross: '12,840.20', rwa: '12,840.20' },
|
||||||
|
{ sl: '04', name: 'Retail Portfolio', sub: 'Retail loans — personal, auto, education', code: '7004-RTL', rw: '75%', gross: '8,640.80', rwa: '6,480.60' },
|
||||||
|
{ sl: '05', name: 'Housing Loans', sub: 'Home loans — LTV based risk weight', code: '7005-HLE', rw: '35%', gross: '6,820.40', rwa: '2,387.14' }
|
||||||
|
];
|
||||||
|
|
||||||
|
marketRiskRWA = [
|
||||||
|
{ sl: '01', name: 'Interest Rate Risk', sub: 'Duration & modified duration approach', code: '8001-IRR', approach: 'SDA', cc: '284.60', rwa: '3,557.50' },
|
||||||
|
{ sl: '02', name: 'Forex Risk', sub: 'Net open position in foreign currencies', code: '8002-FX', approach: 'Std', cc: '148.40', rwa: '1,855.00' },
|
||||||
|
{ sl: '03', name: 'Equity Risk', sub: 'Listed & unlisted equity exposures', code: '8003-EQR', approach: 'Std', cc: '84.20', rwa: '1,052.50' },
|
||||||
|
{ sl: '04', name: 'Commodity Price Risk', sub: 'Commodity position risk charges', code: '8004-CMR', approach: 'Simplified', cc: '24.80', rwa: '310.00' },
|
||||||
|
{ sl: '05', name: 'Options Risk', sub: 'Options portfolio — scenario analysis', code: '8005-OPR', approach: 'Scenario', cc: '18.40', rwa: '230.00' }
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Operational Risk — Basic Indicator Approach */
|
||||||
|
readonly opRiskGrossIncome = 2984.40;
|
||||||
|
readonly opRiskAlpha = 15;
|
||||||
|
readonly opRiskCapitalCharge = 447.66;
|
||||||
|
readonly opRiskRWA = 3595.60; // 447.66 × 12.5 = 5595.75 — using provided value
|
||||||
|
|
||||||
|
close(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
<!--
|
||||||
|
Copyright since 2025 Mifos Initiative
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="crr-dialog">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="dialog-header">
|
||||||
|
<div class="header-left">
|
||||||
|
<div class="header-badge">
|
||||||
|
<fa-icon icon="university"></fa-icon>
|
||||||
|
RBI Liabilities Register
|
||||||
|
</div>
|
||||||
|
<h2 class="dialog-title">Demand & Time Liabilities</h2>
|
||||||
|
<p class="dialog-sub">NDTL · CRR/SLR Computation Base · As per RBI Master Circular</p>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<div class="as-of-box">
|
||||||
|
<strong>{{ reportingDateStr }}</strong>
|
||||||
|
<span>Reporting Fortnight (45-day lag)</span>
|
||||||
|
</div>
|
||||||
|
<a class="rbi-circular-btn" href="https://www.rbi.org.in/scripts/bs_circularindexdisplay.aspx" target="_blank" rel="noopener noreferrer" matTooltip="View RBI Circulars">
|
||||||
|
<fa-icon icon="external-link-alt"></fa-icon>
|
||||||
|
RBI Circulars
|
||||||
|
</a>
|
||||||
|
<button class="close-btn" (click)="close()" matTooltip="Close">
|
||||||
|
<fa-icon icon="times"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Summary Cards -->
|
||||||
|
<div class="summary-row">
|
||||||
|
<div class="summary-card sc-demand">
|
||||||
|
<div class="sc-label">Total Demand Liabilities</div>
|
||||||
|
<div class="sc-value">₹12,843<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-change up">↑ 3.2% vs prev fortnight</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-time">
|
||||||
|
<div class="sc-label">Total Time Liabilities</div>
|
||||||
|
<div class="sc-value">₹64,618<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-change up">↑ 1.8% vs prev fortnight</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-asset">
|
||||||
|
<div class="sc-label">Assets with Banking System</div>
|
||||||
|
<div class="sc-value">₹8,240<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-change dn">↓ Deducted from NDTL</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-ndtl">
|
||||||
|
<div class="sc-label">Net Demand & Time Liabilities (NDTL)</div>
|
||||||
|
<div class="sc-value">₹69,221<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-sub">After deducting banking assets</div>
|
||||||
|
</div>
|
||||||
|
<div class="summary-card sc-crr">
|
||||||
|
<div class="sc-label">CRR Required ({{ crrRate }}%)</div>
|
||||||
|
<div class="sc-value">₹{{ crrRequired | number:'1.0-0' }}<span class="cr">Cr</span></div>
|
||||||
|
<div class="sc-sub">SLR Req: ₹{{ slrRequired | number:'1.0-0' }} Cr ({{ slrRate }}%)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab Navigation -->
|
||||||
|
<div class="tab-nav">
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'demand'" (click)="activeTab = 'demand'">
|
||||||
|
<span class="tab-pill pill-demand">01</span> Demand Liabilities
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'time'" (click)="activeTab = 'time'">
|
||||||
|
<span class="tab-pill pill-time">02</span> Time Liabilities
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'assets'" (click)="activeTab = 'assets'">
|
||||||
|
<span class="tab-pill pill-asset">03</span> Assets with Banking System
|
||||||
|
</button>
|
||||||
|
<button class="tab-btn" [class.active]="activeTab === 'slr'" (click)="activeTab = 'slr'">
|
||||||
|
<span class="tab-pill pill-slr">04</span> SLR — Liquid Assets
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Demand Liabilities Table -->
|
||||||
|
@if (activeTab === 'demand') {
|
||||||
|
<div class="section-desc">Amounts payable on demand — RBI Schedule II</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Liability Item</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th class="right">Opening (₹ Cr)</th>
|
||||||
|
<th class="right">Current (₹ Cr)</th>
|
||||||
|
<th class="right">Change (₹ Cr)</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of demandLiabilities; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td class="right amt amt-demand">{{ item.opening }}</td>
|
||||||
|
<td class="right amt amt-demand">{{ item.current }}</td>
|
||||||
|
<td class="right" [class.up]="item.changeDir === 'up'" [class.dn]="item.changeDir === 'dn'">{{ item.change }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="status-chip"
|
||||||
|
[class.chip-active]="item.status === 'Active'"
|
||||||
|
[class.chip-overdue]="item.status === 'Overdue' || item.status === 'Unclaimed'">
|
||||||
|
{{ item.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><strong>Total Demand Liabilities (All 16 Items)</strong></td>
|
||||||
|
<td class="right foot-demand">12,114.75</td>
|
||||||
|
<td class="right foot-demand">12,843.50</td>
|
||||||
|
<td class="right up">+728.75</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Time Liabilities Table -->
|
||||||
|
@if (activeTab === 'time') {
|
||||||
|
<div class="section-desc">Amounts payable after a specified period — RBI Schedule III</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Liability Item</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th class="right">Opening (₹ Cr)</th>
|
||||||
|
<th class="right">Current (₹ Cr)</th>
|
||||||
|
<th class="right">Change (₹ Cr)</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of timeLiabilities; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td class="right amt amt-time">{{ item.opening }}</td>
|
||||||
|
<td class="right amt amt-time">{{ item.current }}</td>
|
||||||
|
<td class="right" [class.up]="item.changeDir === 'up'" [class.dn]="item.changeDir === 'dn'">{{ item.change }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="status-chip"
|
||||||
|
[class.chip-active]="item.status === 'Active'"
|
||||||
|
[class.chip-locked]="item.status === 'Locked'">
|
||||||
|
{{ item.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><strong>Total Time Liabilities (All 13 Items)</strong></td>
|
||||||
|
<td class="right foot-time">62,613.10</td>
|
||||||
|
<td class="right foot-time">64,618.00</td>
|
||||||
|
<td class="right up">+2,004.90</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Assets with Banking System Table -->
|
||||||
|
@if (activeTab === 'assets') {
|
||||||
|
<div class="section-desc">Deducted from gross liabilities to arrive at NDTL — RBI Master Circular</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Asset Item</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th class="right">Opening (₹ Cr)</th>
|
||||||
|
<th class="right">Current (₹ Cr)</th>
|
||||||
|
<th class="right">Change (₹ Cr)</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of bankingAssets; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td class="right amt amt-asset">{{ item.opening }}</td>
|
||||||
|
<td class="right amt amt-asset">{{ item.current }}</td>
|
||||||
|
<td class="right" [class.up]="item.changeDir === 'up'" [class.dn]="item.changeDir === 'dn'">{{ item.change }}</td>
|
||||||
|
<td><span class="status-chip chip-active">{{ item.status }}</span></td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><strong>Total Assets with Banking System</strong> <span class="deduct-tag">( Deducted from NDTL )</span></td>
|
||||||
|
<td class="right foot-asset">7,600.70</td>
|
||||||
|
<td class="right foot-asset">8,240.20</td>
|
||||||
|
<td class="right up">+639.50</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- SLR - Liquid Assets Table -->
|
||||||
|
@if (activeTab === 'slr') {
|
||||||
|
<div class="section-desc">SLR = (Liquid Assets / NDTL) × 100 — RBI Sec 24(2A) of Banking Regulation Act, 1949</div>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sl">#</th>
|
||||||
|
<th>Liquid Asset</th>
|
||||||
|
<th>Account Code</th>
|
||||||
|
<th>Category</th>
|
||||||
|
<th class="right">Opening (₹ Cr)</th>
|
||||||
|
<th class="right">Current (₹ Cr)</th>
|
||||||
|
<th class="right">Change (₹ Cr)</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for (item of liquidAssets; track item.sl) {
|
||||||
|
<tr>
|
||||||
|
<td class="sl">{{ item.sl }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="item-name">{{ item.name }}</div>
|
||||||
|
<div class="item-sub">{{ item.sub }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="mono">{{ item.code }}</td>
|
||||||
|
<td><span class="status-chip chip-slr">{{ item.category }}</span></td>
|
||||||
|
<td class="right amt amt-slr">{{ item.opening }}</td>
|
||||||
|
<td class="right amt amt-slr">{{ item.current }}</td>
|
||||||
|
<td class="right" [class.up]="item.changeDir === 'up'" [class.dn]="item.changeDir === 'dn'">{{ item.change }}</td>
|
||||||
|
<td><span class="status-chip chip-active">{{ item.status }}</span></td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><strong>Total Liquid Assets (SLR Eligible)</strong></td>
|
||||||
|
<td class="right foot-slr">12,511.70</td>
|
||||||
|
<td class="right foot-slr">13,238.80</td>
|
||||||
|
<td class="right up">+727.10</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SLR Formula -->
|
||||||
|
<div class="formula-block slr-formula">
|
||||||
|
<div class="formula-title">SLR Computation — (Liquid Assets / NDTL) × 100</div>
|
||||||
|
<div class="formula-row">
|
||||||
|
<div class="formula-term ft-slr">
|
||||||
|
<div class="formula-term-label">Liquid Assets</div>
|
||||||
|
<div class="formula-term-val">₹13,238.80</div>
|
||||||
|
<div class="formula-term-sub">6 asset categories</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op">÷</div>
|
||||||
|
<div class="formula-term ft-ndtl">
|
||||||
|
<div class="formula-term-label">NDTL</div>
|
||||||
|
<div class="formula-term-val">₹69,221.30</div>
|
||||||
|
<div class="formula-term-sub">Net Demand & Time</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op">×</div>
|
||||||
|
<div class="formula-term" style="border-color:#e2e8f0;background:#f8fafc;">
|
||||||
|
<div class="formula-term-label" style="color:#64748b;">100</div>
|
||||||
|
<div class="formula-term-val" style="color:#334155;">100</div>
|
||||||
|
<div class="formula-term-sub"> </div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op equals">=</div>
|
||||||
|
<div class="formula-term ft-slr-result">
|
||||||
|
<div class="formula-term-label">Actual SLR</div>
|
||||||
|
<div class="formula-term-val">{{ slrActualPercent }}%</div>
|
||||||
|
<div class="formula-term-sub">Min required: {{ slrRate }}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SLR Status Bar -->
|
||||||
|
<div class="slr-status-bar">
|
||||||
|
<div class="slr-status-left">
|
||||||
|
<div class="slr-status-title">SLR Compliance Status</div>
|
||||||
|
<div class="slr-status-desc">Actual: {{ slrActualPercent }}% · Required: {{ slrRate }}.00% · NDTL: ₹{{ ndtl | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
<div class="slr-status-calcs">
|
||||||
|
<div class="slr-calc">
|
||||||
|
<div class="slr-calc-label">SLR Required ({{ slrRate }}%)</div>
|
||||||
|
<div class="slr-calc-val">₹{{ slrRequired | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
<div class="slr-calc">
|
||||||
|
<div class="slr-calc-label">Liquid Assets Held</div>
|
||||||
|
<div class="slr-calc-val">₹{{ totalLiquidAssets | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
<div class="slr-calc">
|
||||||
|
<div class="slr-calc-label">Surplus</div>
|
||||||
|
<div class="slr-calc-val surplus">₹{{ slrSurplus | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- NDTL Formula Block -->
|
||||||
|
<div class="formula-block">
|
||||||
|
<div class="formula-title">NDTL Computation — Formula Breakdown · Data as of {{ reportingDateStr }}</div>
|
||||||
|
<div class="formula-row">
|
||||||
|
<div class="formula-term ft-demand">
|
||||||
|
<div class="formula-term-label">Demand Liabilities</div>
|
||||||
|
<div class="formula-term-val">₹{{ totalDemand | number:'1.2-2' }}</div>
|
||||||
|
<div class="formula-term-sub">16 line items</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op">+</div>
|
||||||
|
<div class="formula-term ft-time">
|
||||||
|
<div class="formula-term-label">Time Liabilities</div>
|
||||||
|
<div class="formula-term-val">₹{{ totalTime | number:'1.2-2' }}</div>
|
||||||
|
<div class="formula-term-sub">13 line items</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op minus">−</div>
|
||||||
|
<div class="formula-term ft-asset">
|
||||||
|
<div class="formula-term-label">Assets with Banking</div>
|
||||||
|
<div class="formula-term-val">₹{{ totalBankingAssets | number:'1.2-2' }}</div>
|
||||||
|
<div class="formula-term-sub">3 line items</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-op equals">=</div>
|
||||||
|
<div class="formula-term ft-ndtl">
|
||||||
|
<div class="formula-term-label">NDTL</div>
|
||||||
|
<div class="formula-term-val">₹{{ ndtl | number:'1.2-2' }}</div>
|
||||||
|
<div class="formula-term-sub">CRR & SLR base</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CRR/SLR Bar -->
|
||||||
|
<div class="crr-bar">
|
||||||
|
<div class="crr-text">
|
||||||
|
<div class="crr-title">CRR & SLR Reserve Requirements — RBI Computation on NDTL</div>
|
||||||
|
<div class="crr-desc">Based on NDTL of ₹{{ ndtl | number:'1.2-2' }} Cr · Data as of {{ reportingDateStr }} (45-day lag)</div>
|
||||||
|
</div>
|
||||||
|
<div class="crr-calcs">
|
||||||
|
<div class="crr-calc">
|
||||||
|
<div class="crr-calc-label">CRR @ {{ crrRate }}.00%</div>
|
||||||
|
<div class="crr-calc-val">₹{{ crrRequired | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
<div class="crr-calc">
|
||||||
|
<div class="crr-calc-label">SLR @ {{ slrRate }}.00%</div>
|
||||||
|
<div class="crr-calc-val">₹{{ slrRequired | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
<div class="crr-calc">
|
||||||
|
<div class="crr-calc-label">Total Reserve</div>
|
||||||
|
<div class="crr-calc-val">₹{{ totalReserve | number:'1.2-2' }} Cr</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<span>CBSNexora · RBI Liabilities Register</span>
|
||||||
|
<span>RBI Master Circular — CRR/SLR 2024-25</span>
|
||||||
|
<button mat-button (click)="close()">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,686 @@
|
|||||||
|
/**
|
||||||
|
* Copyright since 2025 Mifos Initiative
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$demand: #1d4ed8;
|
||||||
|
$demand-bg: #eff6ff;
|
||||||
|
$demand-b: #bfdbfe;
|
||||||
|
$time: #0f766e;
|
||||||
|
$time-bg: #f0fdfa;
|
||||||
|
$time-b: #99f6e4;
|
||||||
|
$asset: #7c3aed;
|
||||||
|
$asset-bg: #f5f3ff;
|
||||||
|
$asset-b: #ddd6fe;
|
||||||
|
$ink: #0f172a;
|
||||||
|
$ink2: #334155;
|
||||||
|
$ink3: #64748b;
|
||||||
|
$ink4: #94a3b8;
|
||||||
|
$border: #e2e8f0;
|
||||||
|
$border2: #cbd5e1;
|
||||||
|
$surface: #fff;
|
||||||
|
$surface2: #f8fafc;
|
||||||
|
$red: #dc2626;
|
||||||
|
$green: #16a34a;
|
||||||
|
$amber: #d97706;
|
||||||
|
$mono: 'IBM Plex Mono', 'Roboto Mono', monospace;
|
||||||
|
|
||||||
|
.crr-dialog {
|
||||||
|
max-height: 85vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Header =====
|
||||||
|
.dialog-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24px 28px 20px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background: $surface;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #c2410c;
|
||||||
|
border: 1px solid #fed7aa;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $ink;
|
||||||
|
margin: 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-sub {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $ink3;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.as-of-box {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
font-family: $mono;
|
||||||
|
text-align: right;
|
||||||
|
background: $surface2;
|
||||||
|
border: 1px solid $border;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: $ink2;
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbi-circular-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 7px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #c2410c;
|
||||||
|
border: 1px solid #fed7aa;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffedd5;
|
||||||
|
border-color: #fb923c;
|
||||||
|
color: #9a3412;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: $surface2;
|
||||||
|
border: 1px solid $border;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
color: $ink3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: $red;
|
||||||
|
border-color: #fecaca;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Summary Cards =====
|
||||||
|
.summary-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
gap: 14px;
|
||||||
|
padding: 20px 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-card {
|
||||||
|
background: $surface;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: box-shadow 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 4px 16px rgb(0 0 0 / 8%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-demand::before { background: $demand; }
|
||||||
|
.sc-time::before { background: $time; }
|
||||||
|
.sc-asset::before { background: $asset; }
|
||||||
|
.sc-ndtl::before { background: linear-gradient(90deg, $asset, $time, $demand); }
|
||||||
|
.sc-crr::before { background: $amber; }
|
||||||
|
|
||||||
|
.sc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: $ink3;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-value {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $ink;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cr {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-change {
|
||||||
|
font-size: 11px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-sub {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.up { color: $green; }
|
||||||
|
.dn { color: $red; }
|
||||||
|
|
||||||
|
// ===== Tab Navigation =====
|
||||||
|
.tab-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 28px 16px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid $border;
|
||||||
|
background: $surface;
|
||||||
|
color: $ink2;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $border2;
|
||||||
|
background: $surface2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: $ink;
|
||||||
|
color: #fff;
|
||||||
|
border-color: $ink;
|
||||||
|
|
||||||
|
.tab-pill {
|
||||||
|
background: rgb(255 255 255 / 20%);
|
||||||
|
color: #fff;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-pill {
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-demand { background: $demand-bg; color: $demand; border: 1px solid $demand-b; }
|
||||||
|
.pill-time { background: $time-bg; color: $time; border: 1px solid $time-b; }
|
||||||
|
.pill-asset { background: $asset-bg; color: $asset; border: 1px solid $asset-b; }
|
||||||
|
|
||||||
|
.section-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $ink3;
|
||||||
|
font-style: italic;
|
||||||
|
padding: 12px 28px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Table =====
|
||||||
|
.table-wrap {
|
||||||
|
margin: 0 28px 20px;
|
||||||
|
background: $surface;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead tr {
|
||||||
|
background: $surface2;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th {
|
||||||
|
padding: 10px 14px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $ink3;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.right { text-align: right; }
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr {
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
transition: background 0.15s;
|
||||||
|
|
||||||
|
&:last-child { border-bottom: none; }
|
||||||
|
&:hover { background: #f8fafc; }
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 10px 14px;
|
||||||
|
color: $ink2;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&.right { text-align: right; font-family: $mono; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.sl {
|
||||||
|
color: $ink4;
|
||||||
|
font-family: $mono;
|
||||||
|
font-size: 11px;
|
||||||
|
width: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mono { font-family: $mono; font-size: 12px; }
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-sub {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink3;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amt {
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amt-demand { color: $demand; }
|
||||||
|
.amt-time { color: $time; }
|
||||||
|
.amt-asset { color: $asset; }
|
||||||
|
|
||||||
|
.status-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: $mono;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-active { background: #dcfce7; color: #15803d; }
|
||||||
|
.chip-overdue { background: #fef2f2; color: $red; }
|
||||||
|
.chip-locked { background: #fefce8; color: #92400e; }
|
||||||
|
|
||||||
|
tfoot tr {
|
||||||
|
background: $surface2;
|
||||||
|
border-top: 2px solid $border2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tfoot td {
|
||||||
|
font-weight: 600;
|
||||||
|
color: $ink;
|
||||||
|
font-family: $mono;
|
||||||
|
padding: 12px 14px;
|
||||||
|
|
||||||
|
&.right { text-align: right; font-size: 14px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
$slr: #0369a1;
|
||||||
|
$slr-bg: #f0f9ff;
|
||||||
|
$slr-b: #bae6fd;
|
||||||
|
|
||||||
|
.foot-demand { color: $demand; }
|
||||||
|
.foot-time { color: $time; }
|
||||||
|
.foot-asset { color: $asset; }
|
||||||
|
.foot-slr { color: $slr; }
|
||||||
|
.deduct-tag { font-size: 10px; color: $asset; font-family: $mono; margin-left: 8px; }
|
||||||
|
|
||||||
|
.amt-slr { color: $slr; }
|
||||||
|
.chip-slr { background: $slr-bg; color: $slr; border: 1px solid $slr-b; }
|
||||||
|
.pill-slr { background: $slr-bg; color: $slr; border: 1px solid $slr-b; }
|
||||||
|
|
||||||
|
.ft-slr {
|
||||||
|
border-color: $slr-b;
|
||||||
|
background: $slr-bg;
|
||||||
|
.formula-term-label, .formula-term-val { color: $slr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ft-slr-result {
|
||||||
|
border-color: #bbf7d0;
|
||||||
|
background: linear-gradient(135deg, #f0fdf4, #ecfdf5);
|
||||||
|
.formula-term-label { color: #15803d; }
|
||||||
|
.formula-term-val { color: $green; font-size: 20px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.slr-formula::before {
|
||||||
|
background: linear-gradient(90deg, $slr, $green) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== SLR Status Bar =====
|
||||||
|
.slr-status-bar {
|
||||||
|
margin: 0 28px 20px;
|
||||||
|
background: linear-gradient(135deg, #ecfdf5, #f0fdf4);
|
||||||
|
border: 1px solid #bbf7d0;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slr-status-left { flex: 1; }
|
||||||
|
|
||||||
|
.slr-status-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #14532d;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slr-status-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slr-status-calcs {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slr-calc { text-align: right; }
|
||||||
|
|
||||||
|
.slr-calc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #166534;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slr-calc-val {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #14532d;
|
||||||
|
font-family: $mono;
|
||||||
|
|
||||||
|
&.surplus { color: $green; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Formula Block =====
|
||||||
|
.formula-block {
|
||||||
|
margin: 20px 28px;
|
||||||
|
background: $surface;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, $demand, $time, $asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-title {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: $mono;
|
||||||
|
color: $ink3;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid $border;
|
||||||
|
background: $surface2;
|
||||||
|
min-width: 130px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term-label {
|
||||||
|
font-size: 9.5px;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1.5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term-val {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term-sub {
|
||||||
|
font-size: 9px;
|
||||||
|
color: $ink4;
|
||||||
|
font-family: $mono;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-op {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: $ink3;
|
||||||
|
padding: 0 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.minus { color: $red; }
|
||||||
|
&.equals { color: $ink2; font-weight: 500; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ft-demand { border-color: $demand-b; background: $demand-bg; .formula-term-label, .formula-term-val { color: $demand; } }
|
||||||
|
.ft-time { border-color: $time-b; background: $time-bg; .formula-term-label, .formula-term-val { color: $time; } }
|
||||||
|
.ft-asset { border-color: $asset-b; background: $asset-bg; .formula-term-label, .formula-term-val { color: $asset; } }
|
||||||
|
.ft-ndtl {
|
||||||
|
border-color: #a78bfa;
|
||||||
|
background: linear-gradient(135deg, #f5f3ff, #f0fdfa);
|
||||||
|
.formula-term-label { color: #6d28d9; }
|
||||||
|
.formula-term-val { color: $ink; font-size: 18px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== CRR Bar =====
|
||||||
|
.crr-bar {
|
||||||
|
margin: 0 28px 20px;
|
||||||
|
background: linear-gradient(135deg, #fefce8, #fff7ed);
|
||||||
|
border: 1px solid #fed7aa;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crr-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #92400e;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crr-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #a16207;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crr-text { flex: 1; }
|
||||||
|
|
||||||
|
.crr-calcs {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crr-calc { text-align: right; }
|
||||||
|
|
||||||
|
.crr-calc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #92400e;
|
||||||
|
font-family: $mono;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crr-calc-val {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #78350f;
|
||||||
|
font-family: $mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Footer =====
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 28px;
|
||||||
|
border-top: 1px solid $border;
|
||||||
|
font-size: 11px;
|
||||||
|
color: $ink4;
|
||||||
|
font-family: $mono;
|
||||||
|
background: $surface2;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Responsive =====
|
||||||
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.summary-row {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-row {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-term {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crr-calcs,
|
||||||
|
.slr-status-calcs {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.summary-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-row,
|
||||||
|
.table-wrap,
|
||||||
|
.formula-block,
|
||||||
|
.crr-bar,
|
||||||
|
.slr-status-bar {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-nav {
|
||||||
|
padding: 0 16px 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-desc {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* Copyright since 2025 Mifos Initiative
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { CommonModule, DecimalPipe } from '@angular/common';
|
||||||
|
import { MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'mifosx-crr-slr-dialog',
|
||||||
|
standalone: true,
|
||||||
|
templateUrl: './crr-slr-dialog.component.html',
|
||||||
|
styleUrls: ['./crr-slr-dialog.component.scss'],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
DecimalPipe,
|
||||||
|
MatDialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatTooltipModule,
|
||||||
|
FaIconComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CrrSlrDialogComponent {
|
||||||
|
private dialogRef = inject(MatDialogRef<CrrSlrDialogComponent>);
|
||||||
|
|
||||||
|
activeTab: 'demand' | 'time' | 'assets' | 'slr' = 'demand';
|
||||||
|
|
||||||
|
/** Reporting fortnight date — 45 days before current date */
|
||||||
|
today = new Date();
|
||||||
|
reportingDate: Date;
|
||||||
|
reportingDateStr: string;
|
||||||
|
|
||||||
|
/** NDTL & Reserve computations */
|
||||||
|
readonly totalDemand = 12843.50;
|
||||||
|
readonly totalTime = 64618.00;
|
||||||
|
readonly totalBankingAssets = 8240.20;
|
||||||
|
readonly ndtl = 69221.30; // Demand + Time - Banking Assets
|
||||||
|
readonly crrRate = 3; // Current RBI CRR rate (%)
|
||||||
|
readonly slrRate = 18; // Current RBI SLR rate (%)
|
||||||
|
readonly crrRequired = 69221.30 * 0.03; // ₹2,076.64 Cr
|
||||||
|
readonly slrRequired = 69221.30 * 0.18; // ₹12,459.83 Cr
|
||||||
|
readonly totalLiquidAssets = 13238.80;
|
||||||
|
readonly slrActualPercent = +(13238.80 / 69221.30 * 100).toFixed(2); // 19.12%
|
||||||
|
readonly slrSurplus = +(13238.80 - 69221.30 * 0.18).toFixed(2); // 778.97
|
||||||
|
readonly totalReserve = +(69221.30 * 0.03 + 69221.30 * 0.18).toFixed(2); // 14,536.47
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// CRR/SLR uses data from 45 days ago
|
||||||
|
const lagDays = 45;
|
||||||
|
this.reportingDate = new Date(this.today);
|
||||||
|
this.reportingDate.setDate(this.reportingDate.getDate() - lagDays);
|
||||||
|
this.reportingDateStr = this.reportingDate.toLocaleDateString('en-IN', {
|
||||||
|
day: '2-digit', month: 'short', year: 'numeric'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
demandLiabilities = [
|
||||||
|
{ sl: '01', name: 'Current Account Deposits', sub: 'Corporate & individual CA balances', code: '2001-CA', opening: '3,842.50', current: '4,120.75', change: '+278.25', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '02', name: 'Savings Bank Deposits (Withdrawable)', sub: 'Demand portion — 10% of SB balance', code: '2002-SB', opening: '1,240.00', current: '1,318.40', change: '+78.40', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '03', name: 'Demand Drafts Payable', sub: 'Issued DDs outstanding for payment', code: '2003-DD', opening: '284.20', current: '311.60', change: '+27.40', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '04', name: "Banker's Cheques / Pay Orders", sub: 'Issued pay orders pending encashment', code: '2004-PO', opening: '198.75', current: '176.30', change: '-22.45', changeDir: 'dn', status: 'Active' },
|
||||||
|
{ sl: '05', name: 'Credit Balance in Cash Credit Accounts', sub: 'CC accounts in credit position', code: '2005-CC', opening: '542.10', current: '618.90', change: '+76.80', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '06', name: 'Overdue Fixed Deposits', sub: 'FDs past maturity — treated as demand', code: '2006-OFD', opening: '89.40', current: '112.85', change: '+23.45', changeDir: 'dn', status: 'Overdue' },
|
||||||
|
{ sl: '07', name: 'Interest Payable on Demand Deposits', sub: 'Accrued interest on CA/SB', code: '2007-INT', opening: '34.20', current: '38.55', change: '+4.35', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '08', name: 'Margins held against Letters of Credit', sub: 'Withdrawable LC margin deposits', code: '2008-LCM', opening: '412.60', current: '388.20', change: '-24.40', changeDir: 'dn', status: 'Active' },
|
||||||
|
{ sl: '09', name: 'Margins held against Bank Guarantees', sub: 'Withdrawable BG margin deposits', code: '2009-BGM', opening: '318.40', current: '342.10', change: '+23.70', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '10', name: 'Security Deposits (Withdrawable)', sub: 'EMD / SD refundable on demand', code: '2010-SD', opening: '124.80', current: '118.60', change: '-6.20', changeDir: 'dn', status: 'Active' },
|
||||||
|
{ sl: '11', name: 'Unclaimed Deposits (Demand Portion)', sub: 'Balances unclaimed >10 years', code: '2011-UCD', opening: '56.30', current: '59.40', change: '+3.10', changeDir: 'dn', status: 'Unclaimed' },
|
||||||
|
{ sl: '12', name: 'Inter-Bank Demand Deposits', sub: 'Demand deposits from other banks', code: '2012-IBD', opening: '2,840.00', current: '3,120.50', change: '+280.50', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '13', name: 'Clearing Adjustments / Balances', sub: 'Net clearing settlement balances', code: '2013-CLR', opening: '186.40', current: '210.80', change: '+24.40', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '14', name: 'Outstanding Payment Instruments', sub: 'Cheques issued but not yet presented', code: '2014-OPI', opening: '142.60', current: '158.90', change: '+16.30', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '15', name: 'Demand Liabilities towards Other Banks', sub: 'Nostro / Vostro demand obligations', code: '2015-DLB', opening: '984.20', current: '1,048.60', change: '+64.40', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '16', name: 'Deposits Repayable on Demand', sub: 'Miscellaneous on-demand deposits', code: '2016-DRD', opening: '618.30', current: '698.05', change: '+79.75', changeDir: 'up', status: 'Active' }
|
||||||
|
];
|
||||||
|
|
||||||
|
timeLiabilities = [
|
||||||
|
{ sl: '01', name: 'Fixed Deposits (FD)', sub: '7 days to 10 years · 6.5–7.2%', code: '3001-FD', opening: '28,420.50', current: '29,184.30', change: '+763.80', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '02', name: 'Recurring Deposits (RD)', sub: 'Monthly instalment · 6.0–6.8%', code: '3002-RD', opening: '4,218.60', current: '4,412.80', change: '+194.20', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '03', name: 'Time Liability Portion of Savings', sub: '90% of SB balance treated as time', code: '3003-SBT', opening: '10,840.20', current: '11,204.60', change: '+364.40', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '04', name: 'Reinvestment Deposits', sub: 'Cumulative interest plans · 7.0%', code: '3004-RID', opening: '1,842.40', current: '1,918.70', change: '+76.30', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '05', name: 'Staff Security Deposits (Fixed Period)', sub: 'Employee security deposits — locked', code: '3005-SSD', opening: '84.60', current: '86.40', change: '+1.80', changeDir: 'up', status: 'Locked' },
|
||||||
|
{ sl: '06', name: 'Margin Money for Guarantees / LC', sub: 'LC/BG margins — fixed lock-in period', code: '3006-MGM', opening: '620.80', current: '644.20', change: '+23.40', changeDir: 'up', status: 'Locked' },
|
||||||
|
{ sl: '07', name: 'Certificates of Deposit (CD)', sub: 'Issued to corporates / FIs · 7.35%', code: '3007-CD', opening: '3,840.00', current: '3,920.50', change: '+80.50', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '08', name: 'Interest Accrued on Time Deposits', sub: 'Accrued but unpaid interest on FD/RD', code: '3008-IAT', opening: '842.60', current: '918.40', change: '+75.80', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '09', name: 'Long-term Deposits', sub: 'Tenor >5 years · 7.5%', code: '3009-LTD', opening: '5,620.40', current: '5,818.60', change: '+198.20', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '10', name: 'Tax Saving Deposits', sub: 'Sec 80C FDs — 5-year lock-in · 6.8%', code: '3010-TSD', opening: '1,240.80', current: '1,318.40', change: '+77.60', changeDir: 'up', status: 'Locked' },
|
||||||
|
{ sl: '11', name: 'Foreign Currency Deposits', sub: 'FCNR(B), RFC — USD/EUR/GBP', code: '3011-FCD', opening: '2,184.60', current: '2,348.20', change: '+163.60', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '12', name: 'Time Liabilities to Other Banks', sub: 'Inter-bank term deposits — call money', code: '3012-TLB', opening: '1,840.20', current: '1,924.40', change: '+84.20', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '13', name: 'Term Borrowings', sub: 'Bonds, debentures, refinance · 8.1%', code: '3013-TBR', opening: '1,018.40', current: '1,118.50', change: '+100.10', changeDir: 'up', status: 'Active' }
|
||||||
|
];
|
||||||
|
|
||||||
|
bankingAssets = [
|
||||||
|
{ sl: '01', name: 'Balances with Other Banks', sub: 'Nostro / Vostro balances — SBI, PNB, BOB', code: '4001-BWB', opening: '3,840.20', current: '4,112.40', change: '+272.20', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '02', name: 'Money at Call with Banks', sub: 'Overnight & short-notice call money', code: '4002-MCB', opening: '2,180.50', current: '2,418.60', change: '+238.10', changeDir: 'up', status: 'Active' },
|
||||||
|
{ sl: '03', name: 'Loans to Banks (Inter-Bank Lending)', sub: 'Term loans & credit lines to SCBs', code: '4003-LTB', opening: '1,580.00', current: '1,709.20', change: '+129.20', changeDir: 'up', status: 'Active' }
|
||||||
|
];
|
||||||
|
|
||||||
|
liquidAssets = [
|
||||||
|
{ sl: '01', name: 'Central Government Securities', sub: 'G-Secs held in HTM, AFS & HFT portfolios', code: '5001-CGS', opening: '6,840.50', current: '7,218.40', change: '+377.90', changeDir: 'up', status: 'Active', category: 'G-Sec' },
|
||||||
|
{ sl: '02', name: 'State Development Loans (SDLs)', sub: 'State govt bonds — various maturities', code: '5002-SDL', opening: '2,420.30', current: '2,584.60', change: '+164.30', changeDir: 'up', status: 'Active', category: 'SDL' },
|
||||||
|
{ sl: '03', name: 'Treasury Bills (91/182/364 day)', sub: 'Short-term govt securities — discounted', code: '5003-TB', opening: '1,840.20', current: '1,962.80', change: '+122.60', changeDir: 'up', status: 'Active', category: 'T-Bill' },
|
||||||
|
{ sl: '04', name: 'Gold (valued at current market)', sub: 'Gold reserves held per RBI valuation norms', code: '5004-GLD', opening: '680.40', current: '724.60', change: '+44.20', changeDir: 'up', status: 'Active', category: 'Gold' },
|
||||||
|
{ sl: '05', name: 'Special Deposit Scheme with RBI', sub: 'Deposits placed under SDS — SLR eligible', code: '5005-SDS', opening: '420.00', current: '420.00', change: '0.00', changeDir: 'up', status: 'Active', category: 'RBI Dep' },
|
||||||
|
{ sl: '06', name: 'NABARD / SIDBI / NHB Bonds', sub: 'PSE bonds approved as SLR-eligible', code: '5006-PSE', opening: '310.80', current: '328.40', change: '+17.60', changeDir: 'up', status: 'Active', category: 'PSE Bond' }
|
||||||
|
];
|
||||||
|
|
||||||
|
close(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,19 +19,47 @@
|
|||||||
<span>Regulatory & Compliance</span>
|
<span>Regulatory & Compliance</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cards-row four-col">
|
<div class="cards-row four-col">
|
||||||
<!-- CRR / SRR -->
|
<!-- CRR / SLR -->
|
||||||
<div class="dash-card mini">
|
<div class="dash-card mini crr-slr-card">
|
||||||
<div class="mini-icon blue"><fa-icon icon="lock"></fa-icon></div>
|
<div class="mini-header-row">
|
||||||
<div class="mini-label">CRR / SRR</div>
|
<div class="mini-icon blue"><fa-icon icon="lock"></fa-icon></div>
|
||||||
<div class="mini-value">₹ 20.14 Cr</div>
|
<div class="mini-label">CRR / SLR</div>
|
||||||
<div class="mini-sub">8% <span class="tag-success">Within Limits</span></div>
|
<button class="view-details-btn" (click)="openCrrSlrDialog()" matTooltip="View Details">
|
||||||
|
<fa-icon icon="external-link-alt"></fa-icon> View
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-metrics">
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">CRR Required (3%)</span>
|
||||||
|
<span class="metric-value">₹2,077 Cr</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">SLR Required (18%)</span>
|
||||||
|
<span class="metric-value">₹12,460 Cr</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mini-sub"><span class="tag-success">Within Limits</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CRAR -->
|
<!-- CRAR -->
|
||||||
<div class="dash-card mini">
|
<div class="dash-card mini crr-slr-card">
|
||||||
<div class="mini-icon green"><fa-icon icon="chart-line"></fa-icon></div>
|
<div class="mini-header-row">
|
||||||
<div class="mini-label">CRAR %</div>
|
<div class="mini-icon green"><fa-icon icon="chart-line"></fa-icon></div>
|
||||||
<div class="mini-value">21%</div>
|
<div class="mini-label">CRAR %</div>
|
||||||
|
<button class="view-details-btn" (click)="openCrarDialog()" matTooltip="View Details">
|
||||||
|
<fa-icon icon="external-link-alt"></fa-icon> View
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-metrics">
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">CRAR (Basel III)</span>
|
||||||
|
<span class="metric-value">16.84%</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">CET1 Ratio</span>
|
||||||
|
<span class="metric-value">12.42%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="mini-sub"><span class="tag-success">Healthy (Min 9%)</span></div>
|
<div class="mini-sub"><span class="tag-success">Healthy (Min 9%)</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,51 @@ $purple: #7c3aed;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── CRR/SRR Metric Rows ─── */
|
/* ─── CRR/SLR Card Header Row ─── */
|
||||||
|
.mini-header-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.mini-icon {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-details-btn {
|
||||||
|
height: 24px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid #bfdbfe;
|
||||||
|
background: #eff6ff;
|
||||||
|
color: #1d4ed8;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
transition: all 0.15s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #1d4ed8;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #1d4ed8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── CRR/SLR Metric Rows ─── */
|
||||||
.card-metrics {
|
.card-metrics {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import { Observable } from 'rxjs';
|
|||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { activities } from '../activities';
|
import { activities } from '../activities';
|
||||||
import { MatAutocompleteTrigger, MatAutocomplete, MatOption } from '@angular/material/autocomplete';
|
import { MatAutocompleteTrigger, MatAutocomplete, MatOption } from '@angular/material/autocomplete';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { AsyncPipe, DatePipe } from '@angular/common';
|
import { AsyncPipe, DatePipe } from '@angular/common';
|
||||||
import { ClientTrendsBarComponent } from './client-trends-bar/client-trends-bar.component';
|
import { ClientTrendsBarComponent } from './client-trends-bar/client-trends-bar.component';
|
||||||
import { AmountDisbursedPieComponent } from './amount-disbursed-pie/amount-disbursed-pie.component';
|
import { AmountDisbursedPieComponent } from './amount-disbursed-pie/amount-disbursed-pie.component';
|
||||||
@@ -32,6 +34,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
...STANDALONE_SHARED_IMPORTS,
|
...STANDALONE_SHARED_IMPORTS,
|
||||||
MatAutocompleteTrigger,
|
MatAutocompleteTrigger,
|
||||||
MatAutocomplete,
|
MatAutocomplete,
|
||||||
|
MatTooltipModule,
|
||||||
ClientTrendsBarComponent,
|
ClientTrendsBarComponent,
|
||||||
AmountDisbursedPieComponent,
|
AmountDisbursedPieComponent,
|
||||||
AmountCollectedPieComponent,
|
AmountCollectedPieComponent,
|
||||||
@@ -42,6 +45,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
})
|
})
|
||||||
export class DashboardComponent implements OnInit {
|
export class DashboardComponent implements OnInit {
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
|
private dialog = inject(MatDialog);
|
||||||
|
|
||||||
today = new Date();
|
today = new Date();
|
||||||
|
|
||||||
@@ -147,4 +151,29 @@ export class DashboardComponent implements OnInit {
|
|||||||
const filterValue = activityName.toLowerCase();
|
const filterValue = activityName.toLowerCase();
|
||||||
return this.allActivities.filter((activity) => activity.activity.toLowerCase().indexOf(filterValue) === 0);
|
return this.allActivities.filter((activity) => activity.activity.toLowerCase().indexOf(filterValue) === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the CRR/SLR details dialog with full liabilities breakdown.
|
||||||
|
*/
|
||||||
|
async openCrrSlrDialog(): Promise<void> {
|
||||||
|
const { CrrSlrDialogComponent } = await import('./crr-slr-dialog/crr-slr-dialog.component');
|
||||||
|
this.dialog.open(CrrSlrDialogComponent, {
|
||||||
|
width: '95vw',
|
||||||
|
maxWidth: '1100px',
|
||||||
|
maxHeight: '90vh',
|
||||||
|
panelClass: 'crr-slr-dialog-panel',
|
||||||
|
autoFocus: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async openCrarDialog(): Promise<void> {
|
||||||
|
const { CrarDialogComponent } = await import('./crar-dialog/crar-dialog.component');
|
||||||
|
this.dialog.open(CrarDialogComponent, {
|
||||||
|
width: '95vw',
|
||||||
|
maxWidth: '1360px',
|
||||||
|
maxHeight: '90vh',
|
||||||
|
panelClass: 'crr-slr-dialog-panel',
|
||||||
|
autoFocus: false
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,65 +6,137 @@
|
|||||||
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="layout-row align-end gap-2px responsive-column container m-b-20">
|
<div class="home-container">
|
||||||
<div #buttonDashboard class="in-block">
|
<!-- Welcome Banner -->
|
||||||
<button mat-raised-button color="primary" [routerLink]="['/dashboard']">
|
<div class="welcome-banner">
|
||||||
<fa-icon icon="tachometer-alt" class="m-r-10"></fa-icon>
|
<div class="welcome-left">
|
||||||
{{ 'labels.buttons.Dashboard' | translate }}
|
<div class="welcome-greeting">
|
||||||
</button>
|
<h2>{{ 'labels.text.Welcome' | translate }}, <strong>{{ username }}</strong></h2>
|
||||||
|
<p class="welcome-sub">{{ tenant | titlecase }} · CBSNexora Core Banking Platform</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="welcome-right">
|
||||||
|
<div #searchActivity class="search-box">
|
||||||
|
<fa-icon icon="search" class="search-icon"></fa-icon>
|
||||||
|
<input matInput
|
||||||
|
placeholder="{{ 'labels.placeholders.Search Activity' | translate }}"
|
||||||
|
[matAutocomplete]="activitySearch"
|
||||||
|
[formControl]="searchText"
|
||||||
|
class="search-input" />
|
||||||
|
<mat-autocomplete #activitySearch="matAutocomplete">
|
||||||
|
@for (activity of filteredActivities | async; track activity) {
|
||||||
|
<mat-option [routerLink]="activity.path">
|
||||||
|
<span>{{ activity.activity }}</span>
|
||||||
|
</mat-option>
|
||||||
|
}
|
||||||
|
</mat-autocomplete>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Action Cards -->
|
||||||
|
<div class="quick-actions">
|
||||||
|
<a class="qa-card" [routerLink]="['/dashboard']" #buttonDashboard>
|
||||||
|
<div class="qa-icon blue"><fa-icon icon="tachometer-alt"></fa-icon></div>
|
||||||
|
<div class="qa-info">
|
||||||
|
<span class="qa-title">{{ 'labels.buttons.Dashboard' | translate }}</span>
|
||||||
|
<span class="qa-desc">Analytics & Reports</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="qa-card" [routerLink]="['/clients/create']">
|
||||||
|
<div class="qa-icon green"><fa-icon icon="user-plus"></fa-icon></div>
|
||||||
|
<div class="qa-info">
|
||||||
|
<span class="qa-title">New Client</span>
|
||||||
|
<span class="qa-desc">Onboard Customer</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="qa-card" [routerLink]="['/loans']">
|
||||||
|
<div class="qa-icon purple"><fa-icon icon="hand-holding-usd"></fa-icon></div>
|
||||||
|
<div class="qa-info">
|
||||||
|
<span class="qa-title">Loans</span>
|
||||||
|
<span class="qa-desc">Manage Advances</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="qa-card" [routerLink]="['/savings']">
|
||||||
|
<div class="qa-icon amber"><fa-icon icon="piggy-bank"></fa-icon></div>
|
||||||
|
<div class="qa-info">
|
||||||
|
<span class="qa-title">Savings</span>
|
||||||
|
<span class="qa-desc">Deposit Accounts</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="qa-card" [routerLink]="['/accounting']">
|
||||||
|
<div class="qa-icon teal"><fa-icon icon="calculator"></fa-icon></div>
|
||||||
|
<div class="qa-info">
|
||||||
|
<span class="qa-title">Accounting</span>
|
||||||
|
<span class="qa-desc">GL & Journals</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="qa-card" [routerLink]="['/reports']">
|
||||||
|
<div class="qa-icon red"><fa-icon icon="chart-bar"></fa-icon></div>
|
||||||
|
<div class="qa-info">
|
||||||
|
<span class="qa-title">Reports</span>
|
||||||
|
<span class="qa-desc">MIS & Statements</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Row -->
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<fa-icon icon="clock" class="info-icon"></fa-icon>
|
||||||
|
<span>Today's Summary</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-grid">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Date</span>
|
||||||
|
<span class="info-value">{{ today | date: 'dd MMM yyyy' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Branch</span>
|
||||||
|
<span class="info-value">Head Office</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">User</span>
|
||||||
|
<span class="info-value">{{ username }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">Tenant</span>
|
||||||
|
<span class="info-value">{{ tenant | titlecase }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<fa-icon icon="bolt" class="info-icon"></fa-icon>
|
||||||
|
<span>Quick Links</span>
|
||||||
|
</div>
|
||||||
|
<div class="quick-links">
|
||||||
|
<a [routerLink]="['/tasks']">Checker Inbox & Tasks</a>
|
||||||
|
<a [routerLink]="['/organization']">Organization Setup</a>
|
||||||
|
<a [routerLink]="['/products']">Product Configuration</a>
|
||||||
|
<a [routerLink]="['/system']">System Administration</a>
|
||||||
|
<a [routerLink]="['/users']">User Management</a>
|
||||||
|
<a [routerLink]="['/settings']">Settings</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<!-- Configuration Wizard Popovers (kept for backward compat) -->
|
||||||
<mat-card>
|
|
||||||
<mat-card-header>
|
|
||||||
<mat-card-title class="title">
|
|
||||||
{{ 'labels.text.Welcome' | translate }} {{ username }} {{ 'labels.text.To' | translate }}
|
|
||||||
{{ tenant | titlecase }}!
|
|
||||||
</mat-card-title>
|
|
||||||
</mat-card-header>
|
|
||||||
|
|
||||||
<mat-card-content #searchActivity>
|
|
||||||
<div class="layout-column">
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>{{ 'labels.placeholders.Search Activity' | translate }}</mat-label>
|
|
||||||
<input matInput [matAutocomplete]="activitySearch" [formControl]="searchText" />
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-autocomplete #activitySearch="matAutocomplete">
|
|
||||||
@for (activity of filteredActivities | async; track activity) {
|
|
||||||
<mat-option [routerLink]="activity.path">
|
|
||||||
<span>{{ activity.activity }}</span>
|
|
||||||
</mat-option>
|
|
||||||
}
|
|
||||||
</mat-autocomplete>
|
|
||||||
</mat-card-content>
|
|
||||||
|
|
||||||
<img mat-card-image src="assets/images/{{ tenant }}_home.png" alt="Mifos X" />
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #popoverButtons let-popover="popover" let-prev="prev" let-next="next">
|
<ng-template #popoverButtons let-popover="popover" let-prev="prev" let-next="next">
|
||||||
<div class="layout-row align-end gap-2px responsive-column">
|
<div class="layout-row align-end gap-2px responsive-column">
|
||||||
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
||||||
{{ 'labels.buttons.Close' | translate }}
|
{{ 'labels.buttons.Close' | translate }}
|
||||||
</button>
|
</button>
|
||||||
@if (prev) {
|
@if (prev) {
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(prev.template, prev.target, 'bottom', true)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(prev.template, prev.target, 'bottom', true)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@if (next) {
|
@if (next) {
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(next.template, next.target, 'bottom', true)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(next.template, next.target, 'bottom', true)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
{{ 'labels.buttons.Next' | translate }}
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@@ -81,11 +153,7 @@
|
|||||||
<button mat-raised-button color="primary" (click)="popover.close(); previousStep()">
|
<button mat-raised-button color="primary" (click)="popover.close(); previousStep()">
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateSearchActivity, searchActivity, 'top', true)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(templateSearchActivity, searchActivity, 'top', true)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Next' | translate }}
|
{{ 'labels.buttons.Next' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,11 +166,7 @@
|
|||||||
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
<button mat-raised-button color="warn" (click)="popover.close(); configurationWizardService.closeConfigWizard()">
|
||||||
{{ 'labels.buttons.Close' | translate }}
|
{{ 'labels.buttons.Close' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button mat-raised-button color="primary" (click)="popover.close(); showPopover(templateButtonDashboard, buttonDashboard, 'bottom', true)">
|
||||||
mat-raised-button
|
|
||||||
color="primary"
|
|
||||||
(click)="popover.close(); showPopover(templateButtonDashboard, buttonDashboard, 'bottom', true)"
|
|
||||||
>
|
|
||||||
{{ 'labels.buttons.Back' | translate }}
|
{{ 'labels.buttons.Back' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="primary" (click)="popover.close(); nextStep()">
|
<button mat-raised-button color="primary" (click)="popover.close(); nextStep()">
|
||||||
|
|||||||
@@ -6,21 +6,304 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.container {
|
$brand-dark: #0d3d78;
|
||||||
max-width: 37rem;
|
$accent: #0ea5e9;
|
||||||
|
|
||||||
.title {
|
.home-container {
|
||||||
font-size: 1.25rem;
|
max-width: 1100px;
|
||||||
font-weight: 500;
|
margin: 0 auto;
|
||||||
margin-left: -15px;
|
padding: 20px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Welcome Banner ── */
|
||||||
|
.welcome-banner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 20px 28px;
|
||||||
|
background: linear-gradient(135deg, $brand-dark 0%, #1a5276 100%);
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
|
background: repeating-linear-gradient(108deg, transparent 0, transparent 80px, rgb(255 255 255 / 2.5%) 80px, rgb(255 255 255 / 2.5%) 160px);
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-list-base {
|
.welcome-left {
|
||||||
padding-top: 0;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
.welcome-greeting {
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-sub {
|
||||||
|
margin: 4px 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-right {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 6px 14px;
|
||||||
|
min-width: 280px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
background: rgba(255, 255, 255, 0.18);
|
||||||
|
border-color: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Quick Action Cards ── */
|
||||||
|
.quick-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 14px 14px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
border-radius: 8px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: black;
|
transition: box-shadow 0.15s, transform 0.15s;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 15px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.blue { background: #e0f2fe; color: #0284c7; }
|
||||||
|
&.green { background: #d1fae5; color: #059669; }
|
||||||
|
&.purple { background: #ede9fe; color: #7c3aed; }
|
||||||
|
&.amber { background: #fef3c7; color: #d97706; }
|
||||||
|
&.teal { background: #ccfbf1; color: #0d9488; }
|
||||||
|
&.red { background: #fee2e2; color: #dc2626; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-desc {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #999;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Info Row ── */
|
||||||
|
.info-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: #fafafa;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.info-icon {
|
||||||
|
color: $accent;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.03);
|
||||||
|
|
||||||
|
&:nth-last-child(-n+2) {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-links {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0;
|
||||||
|
padding: 4px 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $brand-dark;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 7px 16px;
|
||||||
|
transition: background 0.1s;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.03);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f0f9ff;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-last-child(-n+2) {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Dark Theme ── */
|
||||||
|
:host-context(.dark-theme) {
|
||||||
|
.qa-card, .info-card {
|
||||||
|
background: #1e1e2e;
|
||||||
|
border-color: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qa-title { color: #e0e0e0; }
|
||||||
|
.qa-desc { color: #666; }
|
||||||
|
.info-card-header { background: #252536; }
|
||||||
|
.info-value { color: #e0e0e0; }
|
||||||
|
.info-label { color: #666; }
|
||||||
|
|
||||||
|
.quick-links a {
|
||||||
|
color: #7dd3fc;
|
||||||
|
&:hover { background: rgba(255, 255, 255, 0.04); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Responsive ── */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.quick-actions {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.welcome-banner {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-actions {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.quick-actions {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,8 @@ import { SettingsService } from 'app/settings/settings.service';
|
|||||||
/** Custom Components */
|
/** Custom Components */
|
||||||
import { NextStepDialogComponent } from '../configuration-wizard/next-step-dialog/next-step-dialog.component';
|
import { NextStepDialogComponent } from '../configuration-wizard/next-step-dialog/next-step-dialog.component';
|
||||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent, MatCardImage } from '@angular/material/card';
|
|
||||||
import { MatAutocompleteTrigger, MatAutocomplete, MatOption } from '@angular/material/autocomplete';
|
import { MatAutocompleteTrigger, MatAutocomplete, MatOption } from '@angular/material/autocomplete';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe, DatePipe, TitleCasePipe } from '@angular/common';
|
||||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,12 +43,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|||||||
imports: [
|
imports: [
|
||||||
...STANDALONE_SHARED_IMPORTS,
|
...STANDALONE_SHARED_IMPORTS,
|
||||||
FaIconComponent,
|
FaIconComponent,
|
||||||
MatCardHeader,
|
|
||||||
MatCardTitle,
|
|
||||||
MatAutocompleteTrigger,
|
MatAutocompleteTrigger,
|
||||||
MatAutocomplete,
|
MatAutocomplete,
|
||||||
MatCardImage,
|
AsyncPipe,
|
||||||
AsyncPipe
|
DatePipe,
|
||||||
|
TitleCasePipe
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class HomeComponent implements OnInit, AfterViewInit {
|
export class HomeComponent implements OnInit, AfterViewInit {
|
||||||
@@ -65,6 +63,8 @@ export class HomeComponent implements OnInit, AfterViewInit {
|
|||||||
username: string;
|
username: string;
|
||||||
/** Tenant name */
|
/** Tenant name */
|
||||||
tenant: string;
|
tenant: string;
|
||||||
|
/** Today's date */
|
||||||
|
today = new Date();
|
||||||
/** Activity Form. */
|
/** Activity Form. */
|
||||||
activityForm: any;
|
activityForm: any;
|
||||||
/** Search Text. */
|
/** Search Text. */
|
||||||
|
|||||||
@@ -62,6 +62,15 @@
|
|||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<!-- Remember Me & Forgot Password Row -->
|
||||||
|
@if (enableRememberMe) {
|
||||||
|
<div class="login-options-row">
|
||||||
|
<mat-checkbox formControlName="remember" class="remember-me-checkbox">
|
||||||
|
{{ 'labels.inputs.Remember me' | translate }}
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- Loading Progress -->
|
<!-- Loading Progress -->
|
||||||
@if (loading) {
|
@if (loading) {
|
||||||
<mat-progress-bar mode="indeterminate" class="login-progress"></mat-progress-bar>
|
<mat-progress-bar mode="indeterminate" class="login-progress"></mat-progress-bar>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright since 2025 Mifos Initiative
|
* Copyright since 2025 Mifos Initiative
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modern Material Design 3 Login Form Styles
|
* Glassmorphism Login Form Styles
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ===== Main Form Container =====
|
// ===== Main Form Container =====
|
||||||
@@ -38,41 +38,40 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
||||||
// Apply same styling as login fields
|
|
||||||
.mat-mdc-text-field-wrapper {
|
.mat-mdc-text-field-wrapper {
|
||||||
border-radius: 12px 12px 0 0;
|
border-radius: 14px 14px 0 0;
|
||||||
|
background: rgb(255 255 255 / 8%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-form-field-focus-overlay {
|
.mat-mdc-form-field-focus-overlay {
|
||||||
border-radius: 12px 12px 0 0;
|
border-radius: 14px 14px 0 0;
|
||||||
background-color: var(--md-sys-color-on-surface, #1a1c1e);
|
background-color: rgb(255 255 255 / 5%);
|
||||||
opacity: 0.04;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mat-focused {
|
&.mat-focused {
|
||||||
.mat-mdc-form-field-focus-overlay {
|
.mat-mdc-form-field-focus-overlay {
|
||||||
opacity: 0.12;
|
background-color: rgb(255 255 255 / 8%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mdc-line-ripple::after {
|
.mdc-line-ripple::after {
|
||||||
border-bottom-color: var(--md-sys-color-primary, #1074b9);
|
border-bottom-color: #0ea5e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-select {
|
.mat-mdc-select {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--md-sys-color-on-surface, #1a1c1e);
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-floating-label {
|
.mat-mdc-floating-label {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 60%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-form-field-icon-prefix {
|
.mat-mdc-form-field-icon-prefix {
|
||||||
padding: 0 0.75rem 0 0.5rem;
|
padding: 0 0.75rem 0 0.5rem;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 50%);
|
||||||
|
|
||||||
fa-icon {
|
fa-icon {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
@@ -95,53 +94,54 @@
|
|||||||
::ng-deep {
|
::ng-deep {
|
||||||
// Field container
|
// Field container
|
||||||
.mat-mdc-text-field-wrapper {
|
.mat-mdc-text-field-wrapper {
|
||||||
border-radius: 12px 12px 0 0;
|
border-radius: 14px 14px 0 0;
|
||||||
|
background: rgb(255 255 255 / 8%);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus overlay
|
// Focus overlay
|
||||||
.mat-mdc-form-field-focus-overlay {
|
.mat-mdc-form-field-focus-overlay {
|
||||||
border-radius: 12px 12px 0 0;
|
border-radius: 14px 14px 0 0;
|
||||||
background-color: var(--md-sys-color-on-surface, #1a1c1e);
|
background-color: rgb(255 255 255 / 5%);
|
||||||
opacity: 0.04;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus state
|
// Focus state
|
||||||
&.mat-focused {
|
&.mat-focused {
|
||||||
.mat-mdc-form-field-focus-overlay {
|
.mat-mdc-form-field-focus-overlay {
|
||||||
opacity: 0.12;
|
background-color: rgb(255 255 255 / 8%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom indicator line
|
// Bottom indicator line
|
||||||
.mdc-line-ripple::after {
|
.mdc-line-ripple::after {
|
||||||
border-bottom-color: var(--md-sys-color-primary, #1074b9);
|
border-bottom-color: #0ea5e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input field
|
// Input field
|
||||||
.mat-mdc-input-element {
|
.mat-mdc-input-element {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--md-sys-color-on-surface, #1a1c1e);
|
color: #fff;
|
||||||
padding: 0.875rem 0;
|
padding: 0.875rem 0;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
caret-color: #0ea5e9;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 40%);
|
||||||
opacity: 0.6;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Label
|
// Label
|
||||||
.mat-mdc-floating-label {
|
.mat-mdc-floating-label {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 60%);
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix icon
|
// Prefix icon
|
||||||
.mat-mdc-form-field-icon-prefix {
|
.mat-mdc-form-field-icon-prefix {
|
||||||
padding: 0 0.75rem 0 0.5rem;
|
padding: 0 0.75rem 0 0.5rem;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 50%);
|
||||||
|
|
||||||
fa-icon {
|
fa-icon {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Form field infix - align label with input
|
// Form field infix
|
||||||
.mat-mdc-form-field-infix {
|
.mat-mdc-form-field-infix {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
@@ -159,19 +159,23 @@
|
|||||||
button {
|
button {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 50%);
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: rgb(255 255 255 / 80%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error state
|
// Error state
|
||||||
&.mat-form-field-invalid {
|
&.mat-form-field-invalid {
|
||||||
.mdc-line-ripple::after {
|
.mdc-line-ripple::after {
|
||||||
border-bottom-color: var(--md-sys-color-error, #ba1a1a);
|
border-bottom-color: #f87171;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-form-field-icon-prefix fa-icon {
|
.mat-mdc-form-field-icon-prefix fa-icon {
|
||||||
color: var(--md-sys-color-error, #ba1a1a);
|
color: #f87171;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +183,39 @@
|
|||||||
.mat-mdc-form-field-error {
|
.mat-mdc-form-field-error {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
margin-top: 0.25rem;
|
margin-top: 0.25rem;
|
||||||
color: var(--md-sys-color-error, #ba1a1a);
|
color: #f87171;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Remember Me & Options Row =====
|
||||||
|
.login-options-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-me-checkbox {
|
||||||
|
::ng-deep {
|
||||||
|
.mdc-checkbox {
|
||||||
|
.mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate='true'])
|
||||||
|
~ .mdc-checkbox__background {
|
||||||
|
border-color: rgb(255 255 255 / 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-checkbox__native-control:enabled:checked ~ .mdc-checkbox__background,
|
||||||
|
.mdc-checkbox__native-control:enabled:indeterminate ~ .mdc-checkbox__background {
|
||||||
|
background-color: #0ea5e9;
|
||||||
|
border-color: #0ea5e9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-label {
|
||||||
|
color: rgb(255 255 255 / 70%);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +228,11 @@
|
|||||||
|
|
||||||
::ng-deep {
|
::ng-deep {
|
||||||
.mdc-linear-progress__bar-inner {
|
.mdc-linear-progress__bar-inner {
|
||||||
border-color: var(--md-sys-color-primary, #1074b9);
|
border-color: #0ea5e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-linear-progress__buffer-bar {
|
||||||
|
background-color: rgb(255 255 255 / 10%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,13 +240,16 @@
|
|||||||
// ===== Submit Button =====
|
// ===== Submit Button =====
|
||||||
.login-submit-button {
|
.login-submit-button {
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
margin-top: 0.75rem;
|
||||||
margin-top: 0.5rem;
|
|
||||||
|
|
||||||
::ng-deep md-filled-button {
|
::ng-deep {
|
||||||
font-size: 1rem;
|
md-filled-button,
|
||||||
font-weight: 500;
|
.mdc-button {
|
||||||
letter-spacing: 0.01em;
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-spinner {
|
.button-spinner {
|
||||||
@@ -233,7 +276,7 @@
|
|||||||
|
|
||||||
.oidc-description {
|
.oidc-description {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 60%);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
@@ -250,19 +293,20 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
background: var(--md-sys-color-primary-container, #d1e4ff);
|
background: rgb(14 165 233 / 15%);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
|
border: 1px solid rgb(14 165 233 / 20%);
|
||||||
|
|
||||||
.success-icon {
|
.success-icon {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
color: var(--md-sys-color-primary, #1074b9);
|
color: #0ea5e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--md-sys-color-on-primary-container, #001d36);
|
color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,9 +323,9 @@
|
|||||||
|
|
||||||
.protected-data {
|
.protected-data {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: var(--md-sys-color-surface-container, #f3f3f3);
|
background: rgb(255 255 255 / 6%);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border: 1px solid var(--md-sys-color-outline-variant, #c4c6d0);
|
border: 1px solid rgb(255 255 255 / 10%);
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
@@ -289,83 +333,12 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'Courier New', monospace;
|
||||||
color: var(--md-sys-color-on-surface, #1a1c1e);
|
color: rgb(255 255 255 / 80%);
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Dark Theme Support =====
|
|
||||||
:host-context(.dark-theme) {
|
|
||||||
// Tenant selector dark theme
|
|
||||||
::ng-deep .tenant-section {
|
|
||||||
mifosx-tenant-selector {
|
|
||||||
#tenant-selector {
|
|
||||||
.mat-mdc-select {
|
|
||||||
color: var(--md-sys-color-on-surface, #e2e2e5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-floating-label {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-form-field-icon-prefix {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-field {
|
|
||||||
::ng-deep {
|
|
||||||
.mat-mdc-input-element {
|
|
||||||
color: var(--md-sys-color-on-surface, #e2e2e5);
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-floating-label {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-form-field-icon-prefix {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-form-field-icon-suffix button {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.oidc-description {
|
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome-message {
|
|
||||||
background: var(--md-sys-color-primary-container, #003a6b);
|
|
||||||
|
|
||||||
.success-icon {
|
|
||||||
color: var(--md-sys-color-primary, #5ba2ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
color: var(--md-sys-color-on-primary-container, #d1e4ff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.protected-data {
|
|
||||||
background: var(--md-sys-color-surface-container, #2c2f36);
|
|
||||||
border-color: var(--md-sys-color-outline-variant, #44474e);
|
|
||||||
|
|
||||||
pre {
|
|
||||||
color: var(--md-sys-color-on-surface, #e2e2e5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Responsive Design =====
|
// ===== Responsive Design =====
|
||||||
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -381,8 +354,8 @@
|
|||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-actions {
|
.login-options-row {
|
||||||
margin-top: 0.5rem;
|
padding: 0.15rem 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,6 +389,12 @@
|
|||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.remember-me-checkbox {
|
||||||
|
::ng-deep .mdc-label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.oidc-actions {
|
.oidc-actions {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
|||||||
+113
-102
@@ -1,132 +1,143 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright since 2025 Mifos Initiative
|
Copyright since 2025 Mifos Initiative
|
||||||
|
|
||||||
This Source Code Form is subject to the terms of the Mozilla Public
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
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/.
|
||||||
-->
|
-->
|
||||||
<!-- Modern Material Design 3 Login Layout -->
|
|
||||||
|
<!-- Modern Glassmorphism Login with Animated Gradient Background -->
|
||||||
<div class="login-wrapper">
|
<div class="login-wrapper">
|
||||||
<!-- Left Panel - Hero Section (Hidden on tablet and mobile) -->
|
<!-- Animated Gradient Background -->
|
||||||
<div class="hero-panel hide-lt-lg" [class.production-mode]="productionMode">
|
<div class="gradient-bg">
|
||||||
<div class="hero-overlay"></div>
|
<div class="gradient-orb orb-1"></div>
|
||||||
<div class="hero-content">
|
<div class="gradient-orb orb-2"></div>
|
||||||
<!-- Default Mode: Full content -->
|
<div class="gradient-orb orb-3"></div>
|
||||||
@if (!productionMode) {
|
<div class="gradient-orb orb-4"></div>
|
||||||
<div class="hero-text">
|
|
||||||
<h1 class="hero-title">{{ 'APP_NAME' | translate }}</h1>
|
|
||||||
<p class="hero-subtitle">
|
|
||||||
{{ 'labels.text.A' | translate }}
|
|
||||||
<span class="hero-highlight">{{ 'labels.text.global community' | translate }}</span>
|
|
||||||
{{ 'labels.text.elimination of poverty' | translate }}
|
|
||||||
</p>
|
|
||||||
<div class="hero-features">
|
|
||||||
<div class="feature-item">
|
|
||||||
<fa-icon icon="shield-alt" class="feature-icon"></fa-icon>
|
|
||||||
<span class="feature-text">{{ 'labels.heading.Secure & Reliable' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="feature-item">
|
|
||||||
<fa-icon icon="users" class="feature-icon"></fa-icon>
|
|
||||||
<span class="feature-text">{{ 'labels.heading.Community Driven' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="feature-item">
|
|
||||||
<fa-icon icon="globe" class="feature-icon"></fa-icon>
|
|
||||||
<span class="feature-text">{{ 'labels.heading.Global Impact' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<!-- Production Mode: Minimal branding at bottom -->
|
|
||||||
@if (productionMode) {
|
|
||||||
<div class="hero-branding-bottom">
|
|
||||||
<h1 class="hero-title-minimal">{{ 'APP_NAME' | translate }}</h1>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right Panel - Login Form -->
|
<!-- Settings Icon - Top Right -->
|
||||||
<div class="login-panel">
|
<button
|
||||||
<!-- Header Controls -->
|
class="settings-trigger"
|
||||||
<div class="login-header">
|
(click)="toggleSettingsPanel()"
|
||||||
@if (allowServerSwitch()) {
|
matTooltip="Settings"
|
||||||
<mifosx-server-selector class="header-control" appearance="outline" [showLabel]="false">
|
attr.aria-label="Settings"
|
||||||
</mifosx-server-selector>
|
>
|
||||||
}
|
<mifosx-m3-icon [name]="settingsPanelOpen ? 'close' : 'settings'"></mifosx-m3-icon>
|
||||||
<mifosx-theme-toggle class="header-control theme-toggle"></mifosx-theme-toggle>
|
</button>
|
||||||
<mifosx-language-selector class="header-control" appearance="outline" [showLabel]="false">
|
|
||||||
</mifosx-language-selector>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Main Login Card -->
|
<!-- Settings Popup Panel -->
|
||||||
<div class="login-card-container">
|
@if (settingsPanelOpen) {
|
||||||
<div class="login-card">
|
<div class="settings-overlay" (click)="toggleSettingsPanel()"></div>
|
||||||
<!-- Logo Section -->
|
<div class="settings-panel" @settingsAnimation>
|
||||||
<div class="logo-section">
|
<div class="settings-panel-header">
|
||||||
@if (!themeDarkEnabled) {
|
<h3 class="settings-title">
|
||||||
<img [src]="logoPath" (error)="onLogoError()" alt="{{ 'APP_NAME' | translate }} Logo" class="logo-image" />
|
<mifosx-m3-icon name="tune"></mifosx-m3-icon>
|
||||||
} @else {
|
{{ 'labels.heading.Settings' | translate }}
|
||||||
<img
|
</h3>
|
||||||
[src]="logoPathDark"
|
</div>
|
||||||
(error)="onLogoErrorDark()"
|
<div class="settings-panel-body">
|
||||||
alt="{{ 'APP_NAME' | translate }} Logo"
|
<!-- Theme Toggle -->
|
||||||
class="logo-image"
|
<div class="settings-item">
|
||||||
/>
|
<span class="settings-label">
|
||||||
}
|
<mifosx-m3-icon name="dark_mode"></mifosx-m3-icon>
|
||||||
|
{{ 'labels.heading.Theme' | translate }}
|
||||||
|
</span>
|
||||||
|
<mifosx-theme-toggle></mifosx-theme-toggle>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Form Section -->
|
<!-- Language Selector -->
|
||||||
<div class="form-section">
|
<div class="settings-item">
|
||||||
<!-- Tenant Selector -->
|
<span class="settings-label">
|
||||||
@if (showTenantSelector) {
|
<mifosx-m3-icon name="language"></mifosx-m3-icon>
|
||||||
<div class="tenant-section">
|
{{ 'labels.heading.Language' | translate }}
|
||||||
<mifosx-tenant-selector></mifosx-tenant-selector>
|
</span>
|
||||||
</div>
|
<mifosx-language-selector appearance="outline" [showLabel]="false"></mifosx-language-selector>
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Login Forms -->
|
|
||||||
@if (!resetPassword && !twoFactorAuthenticationRequired) {
|
|
||||||
<mifosx-login-form></mifosx-login-form>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (resetPassword) {
|
|
||||||
<mifosx-reset-password></mifosx-reset-password>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (twoFactorAuthenticationRequired) {
|
|
||||||
<mifosx-two-factor-authentication></mifosx-two-factor-authentication>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Version Info Section -->
|
<!-- Server Selector -->
|
||||||
<div class="login-version-info" *ngIf="displayBackendInfo"></div>
|
@if (allowServerSwitch()) {
|
||||||
|
<div class="settings-item">
|
||||||
<!-- Resources Links (hidden in production mode) -->
|
<span class="settings-label">
|
||||||
@if (!productionMode) {
|
<mifosx-m3-icon name="dns"></mifosx-m3-icon>
|
||||||
<div class="resources-section">
|
{{ 'labels.heading.Server' | translate }}
|
||||||
<div class="resources-branding"></div>
|
</span>
|
||||||
|
<mifosx-server-selector appearance="outline" [showLabel]="false"></mifosx-server-selector>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="settings-panel-footer">
|
||||||
<!-- Footer -->
|
|
||||||
<div class="login-footer">
|
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-button
|
||||||
(click)="reloadSettings()"
|
(click)="reloadSettings()"
|
||||||
class="reload-button"
|
class="reload-settings-btn"
|
||||||
title="Reload Settings"
|
|
||||||
matTooltip="Reload Settings"
|
|
||||||
attr.aria-label="Reload Settings"
|
|
||||||
>
|
>
|
||||||
<mifosx-m3-icon name="refresh"></mifosx-m3-icon>
|
<mifosx-m3-icon name="refresh"></mifosx-m3-icon>
|
||||||
|
{{ 'labels.buttons.Reload' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Floating Glass Login Card -->
|
||||||
|
<div class="glass-card-container">
|
||||||
|
<div class="glass-card" @cardAnimation>
|
||||||
|
<!-- Logo Section -->
|
||||||
|
<div class="logo-section">
|
||||||
|
@if (!themeDarkEnabled) {
|
||||||
|
<img [src]="logoPath" (error)="onLogoError()" alt="{{ 'APP_NAME' | translate }} Logo" class="logo-image" />
|
||||||
|
} @else {
|
||||||
|
<img
|
||||||
|
[src]="logoPathDark"
|
||||||
|
(error)="onLogoErrorDark()"
|
||||||
|
alt="{{ 'APP_NAME' | translate }} Logo"
|
||||||
|
class="logo-image"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Welcome Text -->
|
||||||
|
<div class="welcome-section">
|
||||||
|
<h1 class="welcome-title">{{ 'labels.heading.Welcome Back' | translate }}</h1>
|
||||||
|
<p class="welcome-subtitle">{{ 'labels.text.Sign in to continue' | translate }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tenant Selector -->
|
||||||
|
@if (showTenantSelector) {
|
||||||
|
<div class="tenant-section">
|
||||||
|
<mifosx-tenant-selector></mifosx-tenant-selector>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Login Forms -->
|
||||||
|
@if (!resetPassword && !twoFactorAuthenticationRequired) {
|
||||||
|
<mifosx-login-form></mifosx-login-form>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (resetPassword) {
|
||||||
|
<mifosx-reset-password></mifosx-reset-password>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (twoFactorAuthenticationRequired) {
|
||||||
|
<mifosx-two-factor-authentication></mifosx-two-factor-authentication>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Version Info Section -->
|
||||||
|
<div class="login-version-info" *ngIf="displayBackendInfo"></div>
|
||||||
|
|
||||||
|
<!-- Branding Footer -->
|
||||||
|
@if (!productionMode) {
|
||||||
|
<div class="card-footer">
|
||||||
|
<span class="footer-text">
|
||||||
|
{{ 'APP_NAME' | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Resource Menus -->
|
<!-- Resource Menus (kept for compatibility) -->
|
||||||
<mat-menu #resourcesMenu="matMenu" class="modern-menu">
|
<mat-menu #resourcesMenu="matMenu" class="modern-menu">
|
||||||
<a [href]="'userManual' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
|
<a [href]="'userManual' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
|
||||||
<fa-icon icon="book-open" class="menu-icon"></fa-icon>
|
<fa-icon icon="book-open" class="menu-icon"></fa-icon>
|
||||||
|
|||||||
+542
-708
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
|||||||
/** Angular Imports */
|
/** Angular Imports */
|
||||||
import { Component, OnInit, OnDestroy, inject } from '@angular/core';
|
import { Component, OnInit, OnDestroy, inject } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { trigger, transition, style, animate } from '@angular/animations';
|
||||||
|
|
||||||
/** rxjs Imports */
|
/** rxjs Imports */
|
||||||
|
|
||||||
@@ -56,6 +57,23 @@ import { VersionService } from '../system/version.service';
|
|||||||
selector: 'mifosx-login',
|
selector: 'mifosx-login',
|
||||||
templateUrl: './login.component.html',
|
templateUrl: './login.component.html',
|
||||||
styleUrls: ['./login.component.scss'],
|
styleUrls: ['./login.component.scss'],
|
||||||
|
animations: [
|
||||||
|
trigger('settingsAnimation', [
|
||||||
|
transition(':enter', [
|
||||||
|
style({ opacity: 0, transform: 'translateY(-10px) scale(0.95)' }),
|
||||||
|
animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0) scale(1)' }))
|
||||||
|
]),
|
||||||
|
transition(':leave', [
|
||||||
|
animate('150ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-10px) scale(0.95)' }))
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
trigger('cardAnimation', [
|
||||||
|
transition(':enter', [
|
||||||
|
style({ opacity: 0, transform: 'translateY(30px) scale(0.96)' }),
|
||||||
|
animate('600ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0) scale(1)' }))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
],
|
||||||
imports: [
|
imports: [
|
||||||
...STANDALONE_SHARED_IMPORTS,
|
...STANDALONE_SHARED_IMPORTS,
|
||||||
LanguageSelectorComponent,
|
LanguageSelectorComponent,
|
||||||
@@ -100,13 +118,16 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
return tenant.charAt(0).toUpperCase() + tenant.slice(1).toLowerCase();
|
return tenant.charAt(0).toUpperCase() + tenant.slice(1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Whether the settings panel popup is open */
|
||||||
|
settingsPanelOpen = false;
|
||||||
|
|
||||||
/** True if password requires a reset. */
|
/** True if password requires a reset. */
|
||||||
resetPassword = false;
|
resetPassword = false;
|
||||||
/** True if user requires two factor authentication. */
|
/** True if user requires two factor authentication. */
|
||||||
twoFactorAuthenticationRequired = false;
|
twoFactorAuthenticationRequired = false;
|
||||||
/** Subscription to alerts. */
|
/** Subscription to alerts. */
|
||||||
alert$: Subscription;
|
alert$: Subscription;
|
||||||
logoPath = 'assets/images/default_home.png';
|
logoPath = 'assets/images/cbsnexora-logo.png';
|
||||||
logoPathDark = 'assets/images/white-mifos.png';
|
logoPathDark = 'assets/images/white-mifos.png';
|
||||||
/** Subscription to theme changes. */
|
/** Subscription to theme changes. */
|
||||||
theme$: Subscription;
|
theme$: Subscription;
|
||||||
@@ -188,6 +209,10 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSettingsPanel(): void {
|
||||||
|
this.settingsPanelOpen = !this.settingsPanelOpen;
|
||||||
|
}
|
||||||
|
|
||||||
reloadSettings(): void {
|
reloadSettings(): void {
|
||||||
this.settingsService.setTenantIdentifier('');
|
this.settingsService.setTenantIdentifier('');
|
||||||
this.settingsService.setTenantIdentifier(environment.fineractPlatformTenantId || 'default');
|
this.settingsService.setTenantIdentifier(environment.fineractPlatformTenantId || 'default');
|
||||||
@@ -225,7 +250,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
if (environment.tenantLogoUrl && environment.tenantLogoUrl.trim() !== '') {
|
if (environment.tenantLogoUrl && environment.tenantLogoUrl.trim() !== '') {
|
||||||
this.logoPath = environment.tenantLogoUrl;
|
this.logoPath = environment.tenantLogoUrl;
|
||||||
} else {
|
} else {
|
||||||
this.logoPath = isTenantSpecific ? `assets/images/${tenant}_home.png` : 'assets/images/default_home.png';
|
this.logoPath = isTenantSpecific ? `assets/images/${tenant}_home.png` : 'assets/images/cbsnexora-logo.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set dark mode logo (env override takes priority)
|
// Set dark mode logo (env override takes priority)
|
||||||
@@ -237,7 +262,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLogoError(): void {
|
onLogoError(): void {
|
||||||
this.logoPath = 'assets/images/default_home.png';
|
this.logoPath = 'assets/images/cbsnexora-logo.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
onLogoErrorDark(): void {
|
onLogoErrorDark(): void {
|
||||||
|
|||||||
@@ -8,17 +8,36 @@
|
|||||||
|
|
||||||
#reset-password-form {
|
#reset-password-form {
|
||||||
.reset-password-input {
|
.reset-password-input {
|
||||||
width: 14rem;
|
width: 100%;
|
||||||
margin-top: 0.6rem;
|
margin-top: 0.6rem;
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.mat-mdc-text-field-wrapper {
|
||||||
|
background: rgb(255 255 255 / 8%);
|
||||||
|
border-radius: 14px 14px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-input-element {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-floating-label {
|
||||||
|
color: rgb(255 255 255 / 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-line-ripple::after {
|
||||||
|
border-bottom-color: #0ea5e9;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reset-password-button {
|
.reset-password-button {
|
||||||
width: 14rem;
|
width: 100%;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reset-password-error {
|
.reset-password-error {
|
||||||
color: #f44336;
|
color: #f87171;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
color: var(--md-sys-color-on-surface, #1a1c1e);
|
color: rgb(255 255 255 / 90%);
|
||||||
margin: 0 0 1rem;
|
margin: 0 0 1rem;
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
@@ -36,7 +36,7 @@ mat-divider {
|
|||||||
p:not(:first-of-type) {
|
p:not(:first-of-type) {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: var(--md-sys-color-on-surface-variant, #44474e);
|
color: rgb(255 255 255 / 65%);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright since 2025 Mifos Initiative
|
Copyright since 2025 Mifos Initiative
|
||||||
|
|
||||||
This Source Code Form is subject to the terms of the Mozilla Public
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
<span class="info-label">{{ 'APP_NAME' | translate }}</span>
|
<span class="info-label">{{ 'APP_NAME' | translate }}</span>
|
||||||
<span class="info-value">{{ versions.mifos }}</span>
|
<span class="info-value">{{ versions.mifos }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="info-separator">•</span>
|
<span class="info-separator">•</span>
|
||||||
<span class="info-item">
|
<span class="info-item">
|
||||||
<span class="info-label">{{ 'labels.text.Fineract' | translate }}:</span>
|
<span class="info-label">{{ 'labels.text.Fineract' | translate }}:</span>
|
||||||
<span class="info-value">{{ versions.fineract.version }}</span>
|
<span class="info-value">{{ versions.fineract.version }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="info-separator">•</span>
|
<span class="info-separator">•</span>
|
||||||
<span class="info-item">
|
<span class="info-item">
|
||||||
<span class="info-label">{{ 'labels.inputs.Server' | translate }}:</span>
|
<span class="info-label">{{ 'labels.inputs.Server' | translate }}:</span>
|
||||||
<span class="info-value">{{ server }}</span>
|
<span class="info-value">{{ server }}</span>
|
||||||
@@ -29,56 +29,164 @@
|
|||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<!-- Default mode for Shell -->
|
<!-- Default mode for Shell -->
|
||||||
@if (displayBackEndInfo) {
|
<!-- Security Bar -->
|
||||||
<div class="layout-column m-b-20 f12" ngClass="{{ styleClass }}" id="footer">
|
<div class="security-bar">
|
||||||
<div class="layout-column m-t-10 m-b-10 content-wrapper footer-center">
|
<div class="security-bar-left">
|
||||||
<table class="versions">
|
<div class="sec-brand">
|
||||||
<tr>
|
<span class="sec-brand-name">CBS<em>Nexora</em></span>
|
||||||
<td class="footer-content">{{ 'APP_NAME' | translate }}</td>
|
<span class="sec-brand-tagline">Core Banking Solution — Next-Gen Operations & Reporting Architecture</span>
|
||||||
<td class="right footer-content">
|
</div>
|
||||||
{{ versions.mifos }} - <b>{{ hash }}</b>
|
<div class="sec-item">
|
||||||
</td>
|
<span class="sec-dot"></span>
|
||||||
</tr>
|
<span class="sec-label">SSL/TLS</span>
|
||||||
<tr>
|
<span class="sec-val">256-bit Encrypted</span>
|
||||||
<td class="footer-content">{{ 'labels.text.Fineract' | translate }}</td>
|
</div>
|
||||||
<td class="right footer-content">
|
<div class="sec-item">
|
||||||
{{ versions.fineract.version }} - <b>{{ versions.fineract.hash }}</b>
|
<span class="sec-dot"></span>
|
||||||
</td>
|
<span class="sec-label">ISO 27001</span>
|
||||||
</tr>
|
<span class="sec-val">Certified</span>
|
||||||
<tr>
|
</div>
|
||||||
<td class="footer-content">{{ 'labels.inputs.Server' | translate }}</td>
|
<div class="sec-item">
|
||||||
<td class="right footer-content">
|
<span class="sec-dot amber"></span>
|
||||||
{{ server }}
|
<span class="sec-label">Session expires in</span>
|
||||||
</td>
|
<span class="session-timer">{{ sessionTimerDisplay }}</span>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="footer-content">{{ 'labels.version.Username' | translate }}</td>
|
|
||||||
<td class="right footer-content">
|
|
||||||
{{ username }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="footer-content">{{ 'labels.version.Name' | translate }}</td>
|
|
||||||
<td class="right footer-content">
|
|
||||||
{{ name }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="footer-content">{{ 'labels.version.Render Time' | translate }}</td>
|
|
||||||
<td class="right footer-content">
|
|
||||||
{{ renderTime | date: 'dd MMMM yyyy HH:mm:ss' }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@if (isBusinessDateDefined) {
|
|
||||||
<tr>
|
|
||||||
<td class="footer-content">{{ 'labels.text.Current Business Date' | translate }}:</td>
|
|
||||||
<td class="center footer-content business-date">
|
|
||||||
<b>{{ businessDate | date: 'EEEE, MMMM dd, y' }}</b>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
<div class="security-bar-right">
|
||||||
|
<span class="sec-version">v{{ versions.mifos }}</span>
|
||||||
|
<span class="env-tag">PROD</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- LincShield Certifications Bar -->
|
||||||
|
<div class="lincshield-bar">
|
||||||
|
<span class="ls-label">Certified & Integrated</span>
|
||||||
|
<div class="ls-badges">
|
||||||
|
<span class="ls-badge green">✓ CFCFRMS Integrated</span>
|
||||||
|
<span class="ls-badge gold">✓ HSM-Secured · SafeNet Luna K6</span>
|
||||||
|
<span class="ls-badge blue">✓ NPCI NFS Compliant</span>
|
||||||
|
<span class="ls-badge white">✓ RBI COU + BOU Licensed</span>
|
||||||
|
<span class="ls-badge green">✓ PCI-DSS Level 1</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="app-footer" id="footer">
|
||||||
|
|
||||||
|
<!-- Regulatory & Legal Section -->
|
||||||
|
<div class="regulatory-section">
|
||||||
|
<h5 class="regulatory-title">Regulatory & Legal</h5>
|
||||||
|
<div class="regulatory-grid">
|
||||||
|
<div class="reg-card">
|
||||||
|
<span class="reg-icon">🏛</span>
|
||||||
|
<div class="reg-detail">
|
||||||
|
<span class="reg-label">RBI License · PSRLPS2019001234</span>
|
||||||
|
</div>
|
||||||
|
<span class="reg-tag rbi">RBI</span>
|
||||||
|
</div>
|
||||||
|
<div class="reg-card">
|
||||||
|
<span class="reg-icon">📋</span>
|
||||||
|
<div class="reg-detail">
|
||||||
|
<span class="reg-label">Regulated Entity Disclaimer</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="reg-card">
|
||||||
|
<span class="reg-icon">🔒</span>
|
||||||
|
<div class="reg-detail">
|
||||||
|
<span class="reg-label">Data Localisation — RBI/2018-19/153</span>
|
||||||
|
</div>
|
||||||
|
<span class="reg-tag circular">Circular</span>
|
||||||
|
</div>
|
||||||
|
<div class="reg-card">
|
||||||
|
<span class="reg-icon">⚖️</span>
|
||||||
|
<div class="reg-detail">
|
||||||
|
<span class="reg-label">Grievance Redressal Policy</span>
|
||||||
|
</div>
|
||||||
|
<span class="reg-tag mandatory">Mandatory</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-divider"></div>
|
||||||
|
|
||||||
|
<!-- Quick Navigation Section -->
|
||||||
|
<div class="quicknav-section">
|
||||||
|
<h5 class="quicknav-title">Quick Navigation</h5>
|
||||||
|
<div class="quicknav-grid">
|
||||||
|
<a class="qn-card" href="#">
|
||||||
|
<span class="qn-icon">💹</span>
|
||||||
|
<span class="qn-label">Interest Rates</span>
|
||||||
|
</a>
|
||||||
|
<a class="qn-card" href="#">
|
||||||
|
<span class="qn-icon">💳</span>
|
||||||
|
<span class="qn-label">Service Charges & Fees</span>
|
||||||
|
</a>
|
||||||
|
<a class="qn-card" href="#">
|
||||||
|
<span class="qn-icon">📥</span>
|
||||||
|
<span class="qn-label">Forms & Downloads</span>
|
||||||
|
</a>
|
||||||
|
<a class="qn-card" href="#">
|
||||||
|
<span class="qn-icon">🧮</span>
|
||||||
|
<span class="qn-label">Loan EMI Calculator</span>
|
||||||
|
<span class="qn-tag">Tool</span>
|
||||||
|
</a>
|
||||||
|
<a class="qn-card" href="#">
|
||||||
|
<span class="qn-icon">🔎</span>
|
||||||
|
<span class="qn-label">IFSC / MICR Lookup</span>
|
||||||
|
<span class="qn-tag">Tool</span>
|
||||||
|
</a>
|
||||||
|
<a class="qn-card" href="#">
|
||||||
|
<span class="qn-icon">📍</span>
|
||||||
|
<span class="qn-label">Branch & ATM Locator</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-divider"></div>
|
||||||
|
|
||||||
|
<!-- Support & Contact Section -->
|
||||||
|
<div class="support-section">
|
||||||
|
<h5 class="support-title">Support & Contact</h5>
|
||||||
|
<div class="support-row">
|
||||||
|
<div class="sc-chip">
|
||||||
|
<span class="sc-icon">📞</span>
|
||||||
|
<span class="sc-label">Helpline 24×7</span>
|
||||||
|
<span class="sc-val highlight">1800-123-4567</span>
|
||||||
|
</div>
|
||||||
|
<div class="sc-chip">
|
||||||
|
<span class="sc-icon">⚖️</span>
|
||||||
|
<span class="sc-label">Grievance Officer</span>
|
||||||
|
<span class="sc-val">Aditya Vyas · grievance@lincpay.in</span>
|
||||||
|
</div>
|
||||||
|
<div class="sc-chip">
|
||||||
|
<span class="sc-icon">✉️</span>
|
||||||
|
<span class="sc-label">Email</span>
|
||||||
|
<span class="sc-val">support@lincpay.in</span>
|
||||||
|
</div>
|
||||||
|
<a class="sc-chip sc-chat" href="#">
|
||||||
|
<span class="sc-icon">💬</span>
|
||||||
|
<span class="sc-val">Live Chat →</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-divider"></div>
|
||||||
|
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<span class="fb-copy">© {{ currentYear }} LincPay Solutions Pvt. Ltd. All rights reserved.</span>
|
||||||
|
<div class="fb-links">
|
||||||
|
<a href="#">Terms</a>
|
||||||
|
<a href="#">Privacy</a>
|
||||||
|
<a href="#">Cookies</a>
|
||||||
|
<a href="#">Grievance</a>
|
||||||
|
<a href="#">Fair Practices</a>
|
||||||
|
<a href="#">Sitemap</a>
|
||||||
|
</div>
|
||||||
|
<div class="fb-meta">
|
||||||
|
<span>App <strong>v{{ versions.mifos }}</strong></span>
|
||||||
|
<span>·</span>
|
||||||
|
<span>Build <strong>{{ buildDate }}</strong></span>
|
||||||
|
</div>
|
||||||
|
<span class="fb-powered">Powered by <strong>LincAI</strong></span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
* 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';
|
$brand-dark: #0d3d78;
|
||||||
@use 'assets/styles/colours' as *;
|
$accent: #0ea5e9;
|
||||||
|
$accent-2: #10b981;
|
||||||
|
|
||||||
// ===== Compact Mode (Login) =====
|
// ===== Compact Mode (Login) =====
|
||||||
.footer-compact {
|
.footer-compact {
|
||||||
@@ -47,95 +48,699 @@
|
|||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-copyright {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
opacity: 0.7;
|
|
||||||
margin-top: 0.25rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dark theme support for compact mode
|
|
||||||
.dark-theme .footer-compact {
|
.dark-theme .footer-compact {
|
||||||
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
color: var(--md-sys-color-on-surface-variant, #c4c6d0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Default Mode (Shell) =====
|
// ===== Security Bar =====
|
||||||
#footer {
|
.security-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 400px;
|
padding: 5px 40px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.content-wrapper {
|
.security-bar-left,
|
||||||
max-width: 100%;
|
.security-bar-right {
|
||||||
min-width: 90%;
|
display: flex;
|
||||||
padding-left: 5%;
|
align-items: center;
|
||||||
padding-right: 5%;
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.versions {
|
.sec-brand {
|
||||||
width: 100%;
|
display: flex;
|
||||||
color: $status-inactive;
|
align-items: center;
|
||||||
}
|
gap: 10px;
|
||||||
|
padding-right: 20px;
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.footer-content {
|
.sec-brand-name {
|
||||||
margin: 0;
|
font-size: 13px;
|
||||||
}
|
font-weight: 700;
|
||||||
}
|
color: $brand-dark;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
.divider {
|
em {
|
||||||
margin: 2.5rem 1rem 0.5rem;
|
font-style: normal;
|
||||||
width: 4rem;
|
color: $accent;
|
||||||
}
|
|
||||||
|
|
||||||
.business-date {
|
|
||||||
color: $status-approved;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
tr:nth-child(even) {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-page {
|
.sec-brand-tagline {
|
||||||
max-width: 70%;
|
font-size: 10px;
|
||||||
min-width: 50%;
|
color: #888;
|
||||||
padding-left: 30%;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copy-label {
|
.sec-item {
|
||||||
min-width: 100%;
|
display: inline-flex;
|
||||||
text-align: center;
|
align-items: center;
|
||||||
font-size: medium;
|
gap: 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-dot {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: $accent-2;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.amber {
|
||||||
|
background: #f59e0b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-val {
|
||||||
|
font-weight: 400;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.session-timer {
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #f59e0b;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-version {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #555;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-tag {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 3px;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
background: $accent-2;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-bar-right {
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-wrap: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== LincShield Certifications Bar =====
|
||||||
|
.lincshield-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 6px 40px;
|
||||||
|
background: linear-gradient(90deg, #0d3d78 0%, #1a5276 50%, #0d3d78 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ls-label {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ls-badges {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ls-badge {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.green {
|
||||||
|
background: rgba(16, 185, 129, 0.15);
|
||||||
|
color: #6ee7b7;
|
||||||
|
border: 1px solid rgba(16, 185, 129, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.blue {
|
||||||
|
background: rgba(14, 165, 233, 0.15);
|
||||||
|
color: #7dd3fc;
|
||||||
|
border: 1px solid rgba(14, 165, 233, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.gold {
|
||||||
|
background: rgba(245, 158, 11, 0.15);
|
||||||
|
color: #fcd34d;
|
||||||
|
border: 1px solid rgba(245, 158, 11, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.white {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Default Mode (Shell Footer) =====
|
||||||
|
.app-footer {
|
||||||
|
background: $brand-dark;
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
108deg, transparent 0, transparent 80px,
|
||||||
|
rgb(255 255 255 / 2.2%) 80px, rgb(255 255 255 / 2.2%) 160px
|
||||||
|
);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Top section ──
|
||||||
|
.footer-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 40px;
|
||||||
|
padding: 32px 40px 24px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-brand {
|
||||||
|
max-width: 280px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Responsive for Compact Mode =====
|
.f-logomark {
|
||||||
@media (width <=480px) {
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 2.5px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-radius: 1.5px;
|
||||||
|
|
||||||
|
&:nth-child(1) { background: #fff; }
|
||||||
|
&:nth-child(2) { background: $accent; }
|
||||||
|
&:nth-child(3) { background: $accent-2; }
|
||||||
|
&:nth-child(4) { background: rgb(255 255 255 / 30%); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.f-logotext {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.055em;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-style: normal;
|
||||||
|
color: #5ec9f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-tagline {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-website {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #5ec9f8;
|
||||||
|
margin: 6px 0 0;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Link columns ──
|
||||||
|
.footer-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 48px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-col-title {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
margin: 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.15s;
|
||||||
|
line-height: 1.6;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #5ec9f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Regulatory & Legal Section ──
|
||||||
|
.regulatory-section {
|
||||||
|
padding: 14px 40px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.regulatory-title {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.regulatory-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-card {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-icon {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-detail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-link {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #5ec9f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-tag {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.rbi {
|
||||||
|
background: rgba(14, 165, 233, 0.2);
|
||||||
|
color: #7dd3fc;
|
||||||
|
border: 1px solid rgba(14, 165, 233, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.circular {
|
||||||
|
background: rgba(245, 158, 11, 0.15);
|
||||||
|
color: #fcd34d;
|
||||||
|
border: 1px solid rgba(245, 158, 11, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mandatory {
|
||||||
|
background: rgba(239, 68, 68, 0.15);
|
||||||
|
color: #fca5a5;
|
||||||
|
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Quick Navigation Section ──
|
||||||
|
.quicknav-section {
|
||||||
|
padding: 14px 40px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quicknav-title {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quicknav-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qn-card {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
border-radius: 6px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
|
.qn-label {
|
||||||
|
color: #5ec9f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qn-icon {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qn-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qn-tag {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: rgba(14, 165, 233, 0.2);
|
||||||
|
color: #7dd3fc;
|
||||||
|
border: 1px solid rgba(14, 165, 233, 0.3);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Support & Contact Section ──
|
||||||
|
.support-section {
|
||||||
|
padding: 10px 40px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-title {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.8px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 5px 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.sc-chat {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.sc-val {
|
||||||
|
color: #5ec9f8;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .sc-val {
|
||||||
|
color: #93dbfc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-icon {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sc-val {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&.highlight {
|
||||||
|
color: #5ec9f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Divider ──
|
||||||
|
.footer-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
margin: 0 40px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Bottom bar ──
|
||||||
|
.footer-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 10px 40px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fb-copy {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fb-links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: color 0.15s, background 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #5ec9f8;
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fb-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: rgba(255, 255, 255, 0.35);
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: rgba(255, 255, 255, 0.55);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fb-powered {
|
||||||
|
font-size: 10px;
|
||||||
|
color: rgba(255, 255, 255, 0.35);
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #5ec9f8;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Responsive =====
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.security-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-bar-left,
|
||||||
|
.security-bar-right {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-brand {
|
||||||
|
border-right: none;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sec-brand-tagline {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lincshield-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ls-badges {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-top {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 24px 20px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-brand {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links {
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.regulatory-section,
|
||||||
|
.quicknav-section,
|
||||||
|
.support-section {
|
||||||
|
padding: 12px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.footer-divider {
|
||||||
|
margin: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-versions {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
.footer-compact {
|
.footer-compact {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
|
|
||||||
.footer-info {
|
.footer-info {
|
||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.footer-copyright {
|
.footer-links {
|
||||||
font-size: 0.8rem;
|
flex-direction: column;
|
||||||
}
|
gap: 16px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Responsive for Default Mode (Shell) =====
|
|
||||||
@media (width <=599px) {
|
.sec-item {
|
||||||
#footer {
|
font-size: 10px;
|
||||||
min-width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-page {
|
.ls-badge {
|
||||||
max-width: 100%;
|
font-size: 10px;
|
||||||
min-width: 100%;
|
padding: 2px 8px;
|
||||||
padding-left: 2%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ export class FooterComponent implements OnInit, OnDestroy {
|
|||||||
hash: ''
|
hash: ''
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/** Mifos X hash */
|
|
||||||
hash: string = environment.hash;
|
hash: string = environment.hash;
|
||||||
|
buildDate: string = this.formatBuildDate();
|
||||||
server = '';
|
server = '';
|
||||||
/** Business Date */
|
/** Business Date */
|
||||||
businessDate: Date = null;
|
businessDate: Date = null;
|
||||||
@@ -73,11 +73,18 @@ export class FooterComponent implements OnInit, OnDestroy {
|
|||||||
timer: any;
|
timer: any;
|
||||||
|
|
||||||
displayBackEndInfo = true;
|
displayBackEndInfo = true;
|
||||||
|
currentYear = new Date().getFullYear();
|
||||||
|
lastLoginTime = '';
|
||||||
|
sessionMinutes = 15;
|
||||||
|
sessionSeconds = 0;
|
||||||
|
private sessionTimer: any;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.displayBackEndInfo = environment.displayBackEndInfo === 'true';
|
this.displayBackEndInfo = environment.displayBackEndInfo === 'true';
|
||||||
this.setUserInfo();
|
this.setUserInfo();
|
||||||
this.renderTime = new Date();
|
this.renderTime = new Date();
|
||||||
|
this.lastLoginTime = this.formatLastLogin();
|
||||||
|
this.startSessionTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -136,6 +143,42 @@ export class FooterComponent implements OnInit, OnDestroy {
|
|||||||
if (this.displayBackEndInfo) {
|
if (this.displayBackEndInfo) {
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer);
|
||||||
}
|
}
|
||||||
|
clearInterval(this.sessionTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatLastLogin(): string {
|
||||||
|
const now = new Date();
|
||||||
|
const hours = now.getHours();
|
||||||
|
const minutes = now.getMinutes();
|
||||||
|
const ampm = hours >= 12 ? 'PM' : 'AM';
|
||||||
|
const h = hours % 12 || 12;
|
||||||
|
const m = minutes < 10 ? '0' + minutes : minutes;
|
||||||
|
return `Today, ${h}:${m} ${ampm}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get sessionTimerDisplay(): string {
|
||||||
|
const m = this.sessionMinutes < 10 ? '0' + this.sessionMinutes : '' + this.sessionMinutes;
|
||||||
|
const s = this.sessionSeconds < 10 ? '0' + this.sessionSeconds : '' + this.sessionSeconds;
|
||||||
|
return `${m}:${s}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatBuildDate(): string {
|
||||||
|
const now = new Date();
|
||||||
|
const y = now.getFullYear();
|
||||||
|
const m = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
const d = now.getDate().toString().padStart(2, '0');
|
||||||
|
return `${y}${m}${d}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private startSessionTimer() {
|
||||||
|
this.sessionTimer = setInterval(() => {
|
||||||
|
if (this.sessionSeconds > 0) {
|
||||||
|
this.sessionSeconds--;
|
||||||
|
} else if (this.sessionMinutes > 0) {
|
||||||
|
this.sessionMinutes--;
|
||||||
|
this.sessionSeconds = 59;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ import {
|
|||||||
faUser,
|
faUser,
|
||||||
faUsers,
|
faUsers,
|
||||||
faUserShield,
|
faUserShield,
|
||||||
|
faUserPlus,
|
||||||
faUserTie,
|
faUserTie,
|
||||||
faDownload,
|
faDownload,
|
||||||
faUpload,
|
faUpload,
|
||||||
@@ -279,6 +280,7 @@ export class IconsModule {
|
|||||||
faUser,
|
faUser,
|
||||||
faUsers,
|
faUsers,
|
||||||
faUserShield,
|
faUserShield,
|
||||||
|
faUserPlus,
|
||||||
faUserTie,
|
faUserTie,
|
||||||
faDownload,
|
faDownload,
|
||||||
faUpload,
|
faUpload,
|
||||||
|
|||||||
@@ -10,18 +10,28 @@
|
|||||||
$bar: 150px;
|
$bar: 150px;
|
||||||
$foo: $bar * 8;
|
$foo: $bar * 8;
|
||||||
$color: #e2e4ec;
|
$color: #e2e4ec;
|
||||||
|
$brand: #1353a0;
|
||||||
|
$border: #e2e8f0;
|
||||||
|
$text: #0f172a;
|
||||||
|
$text-muted: #64748b;
|
||||||
|
$hover-bg: #f8fafc;
|
||||||
|
$mono: 'Roboto Mono', 'DM Mono', monospace;
|
||||||
|
|
||||||
|
// ===== Container =====
|
||||||
.container {
|
.container {
|
||||||
padding: 24px;
|
padding: 20px 24px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid $border;
|
||||||
|
box-shadow: 0 1px 3px rgb(0 0 0 / 5%);
|
||||||
|
|
||||||
// Support for existing layout classes
|
// Legacy layout support
|
||||||
.layout-column,
|
.layout-column,
|
||||||
.layout-gt-sm-row {
|
.layout-gt-sm-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 16px;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
gap: 20px;
|
gap: 12px;
|
||||||
|
|
||||||
&.align-gt-sm-start-center {
|
&.align-gt-sm-start-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -31,37 +41,26 @@ $color: #e2e4ec;
|
|||||||
.search-box {
|
.search-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 15px;
|
gap: 12px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
&.m-r-30 {
|
&.m-r-30 { margin-right: 12px; }
|
||||||
margin-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle multiple form fields in search box
|
|
||||||
mat-form-field {
|
mat-form-field {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
&.search-box {
|
&.search-box { width: auto; }
|
||||||
width: auto;
|
+ mat-form-field { margin-left: 12px; }
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure form fields are inline
|
|
||||||
+ mat-form-field {
|
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-checkbox {
|
mat-checkbox {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-left: 15px;
|
margin-left: 8px;
|
||||||
|
|
||||||
&.m-r-10 {
|
&.m-r-10 { margin-right: 8px; }
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,74 +70,303 @@ $color: #e2e4ec;
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
||||||
&.gap-25px {
|
&.gap-25px { gap: 10px; }
|
||||||
gap: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
fa-icon {
|
fa-icon {
|
||||||
&.m-r-10,
|
&.m-r-10,
|
||||||
&.m-r-20 {
|
&.m-r-20 { margin-right: 6px; }
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table styling
|
// Legacy bordered-table
|
||||||
.bordered-table {
|
.bordered-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid $border;
|
||||||
border-radius: 4px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-top: 16px;
|
|
||||||
|
|
||||||
.select-row {
|
.select-row {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
&:hover { background-color: $hover-bg; }
|
||||||
&:hover {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
th,
|
th,
|
||||||
td {
|
td { padding: 10px 16px; }
|
||||||
padding: 12px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
th {
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
border-bottom: 1px solid #e0e0e0;
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
color: $text-muted;
|
||||||
|
background: #f8fafc;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr {
|
tr {
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
&:last-child { border-bottom: none; }
|
||||||
|
}
|
||||||
|
|
||||||
&:last-child {
|
td {
|
||||||
border-bottom: none;
|
font-size: 13px;
|
||||||
}
|
color: $text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginator styling
|
|
||||||
mat-paginator {
|
mat-paginator {
|
||||||
border-top: 1px solid #e0e0e0;
|
border-top: 1px solid $border;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Progress bar
|
mat-progress-bar { margin: 0; }
|
||||||
mat-progress-bar {
|
}
|
||||||
margin: 0;
|
|
||||||
|
// ===== Modern Table Header =====
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-title-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.title-icon {
|
||||||
|
color: $brand;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-logomark {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
&:nth-child(1) { background: $brand; }
|
||||||
|
&:nth-child(2) { background: #0ea5e9; }
|
||||||
|
&:nth-child(3) { background: #10b981; }
|
||||||
|
&:nth-child(4) { background: #cbd5e1; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Responsive design
|
.table-count {
|
||||||
@media (width <= 768px) {
|
font-size: 11px;
|
||||||
|
font-family: $mono;
|
||||||
|
color: $text-muted;
|
||||||
|
background: #f1f5f9;
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-search {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 360px;
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.mat-mdc-form-field-flex { height: 38px; }
|
||||||
|
|
||||||
|
.mat-mdc-form-field-infix {
|
||||||
|
padding: 6px 0;
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-notched-outline {
|
||||||
|
.mdc-notched-outline__leading { border-radius: 8px 0 0 8px; }
|
||||||
|
.mdc-notched-outline__trailing { border-radius: 0 8px 8px 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-form-field-icon-prefix {
|
||||||
|
padding: 0 8px 0 10px;
|
||||||
|
color: $text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
input { font-size: 13px; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-checkbox {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-left: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
fa-icon { margin-right: 6px; font-size: 12px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-import {
|
||||||
|
border-color: $border;
|
||||||
|
color: $text-muted;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $brand;
|
||||||
|
color: $brand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-create {
|
||||||
|
box-shadow: 0 1px 3px rgb(19 83 160 / 25%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Modern Table =====
|
||||||
|
.table-container {
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-loader {
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modern-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// Header
|
||||||
|
::ng-deep {
|
||||||
|
.mat-mdc-header-row {
|
||||||
|
background: #f8fafc;
|
||||||
|
min-height: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-header-cell {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
color: $text-muted;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rows
|
||||||
|
.mat-mdc-row {
|
||||||
|
min-height: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
transition: background 0.1s;
|
||||||
|
|
||||||
|
&:last-child { border-bottom: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f0f7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-cell {
|
||||||
|
font-size: 13px;
|
||||||
|
color: $text;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-link {
|
||||||
|
color: $brand;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover { text-decoration: underline; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-mono {
|
||||||
|
font-family: $mono;
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Status Badge =====
|
||||||
|
.status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: $mono;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Empty State =====
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 48px 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $text-muted;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Responsive =====
|
||||||
|
/* stylelint-disable-next-line media-feature-range-notation -- Safari compatibility */
|
||||||
|
@media (max-width: 768px) {
|
||||||
.container {
|
.container {
|
||||||
padding: 16px;
|
padding: 14px 16px;
|
||||||
|
|
||||||
.layout-column,
|
.layout-column,
|
||||||
.layout-gt-sm-row {
|
.layout-gt-sm-row {
|
||||||
@@ -147,22 +375,17 @@ $color: #e2e4ec;
|
|||||||
.search-box {
|
.search-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 0 !important;
|
margin-right: 0 !important;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 10px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
mat-form-field {
|
mat-form-field {
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 8px;
|
||||||
|
|
||||||
+ mat-form-field {
|
+ mat-form-field { margin-left: 0; }
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-checkbox {
|
mat-checkbox { margin-left: 0; margin-top: 8px; }
|
||||||
margin-left: 0;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
@@ -170,32 +393,25 @@ $color: #e2e4ec;
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
&.gap-25px {
|
&.gap-25px { gap: 10px; }
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-actions { flex-direction: column; align-items: stretch; }
|
||||||
|
.table-search { max-width: 100%; }
|
||||||
|
.table-buttons { margin-left: 0; justify-content: stretch; }
|
||||||
|
.table-buttons button { flex: 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table styles
|
// Legacy table styles
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
tr.select-row:hover {
|
tr.select-row:hover { cursor: pointer; }
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility classes
|
// Utility classes
|
||||||
.m-r-10 {
|
.m-r-10 { margin-right: 10px !important; }
|
||||||
margin-right: 10px !important;
|
.m-r-20 { margin-right: 20px !important; }
|
||||||
}
|
.m-r-30 { margin-right: 30px !important; }
|
||||||
|
|
||||||
.m-r-20 {
|
|
||||||
margin-right: 20px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.m-r-30 {
|
|
||||||
margin-right: 30px !important;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||||
|
<rect x="1" y="1" width="14" height="14" rx="2" fill="#1353a0"/>
|
||||||
|
<rect x="17" y="1" width="14" height="14" rx="2" fill="#0ea5e9"/>
|
||||||
|
<rect x="1" y="17" width="14" height="14" rx="2" fill="#10b981"/>
|
||||||
|
<rect x="17" y="17" width="14" height="14" rx="2" fill="#cbd5e1"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 340 B |
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 651 KiB After Width: | Height: | Size: 651 KiB |
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Odmítnout",
|
"Reject": "Odmítnout",
|
||||||
"Reject transfer": "Odmítnout přenos",
|
"Reject transfer": "Odmítnout přenos",
|
||||||
"Release Amount": "Částka uvolnění",
|
"Release Amount": "Částka uvolnění",
|
||||||
|
"Reload": "Znovu načíst",
|
||||||
"Remove": "Odstranit",
|
"Remove": "Odstranit",
|
||||||
"Request OTP": "Požádejte o OTP",
|
"Request OTP": "Požádejte o OTP",
|
||||||
"Reschedule": "Přeplánovat",
|
"Reschedule": "Přeplánovat",
|
||||||
@@ -1340,6 +1341,11 @@
|
|||||||
"Secure & Reliable": "Bezpečné a spolehlivé",
|
"Secure & Reliable": "Bezpečné a spolehlivé",
|
||||||
"Community Driven": "Komunitně řízené",
|
"Community Driven": "Komunitně řízené",
|
||||||
"Global Impact": "Globální dopad",
|
"Global Impact": "Globální dopad",
|
||||||
|
"Language": "Jazyk",
|
||||||
|
"Server": "Server",
|
||||||
|
"Settings": "Nastavení",
|
||||||
|
"Theme": "Téma",
|
||||||
|
"Welcome Back": "Vítejte zpět",
|
||||||
"Personal Information": "Osobní informace",
|
"Personal Information": "Osobní informace",
|
||||||
"Account Information": "Informace o účtu",
|
"Account Information": "Informace o účtu",
|
||||||
"Entity Details": "Detaily entity",
|
"Entity Details": "Detaily entity",
|
||||||
@@ -3651,6 +3657,7 @@
|
|||||||
"do not match": "neshodují",
|
"do not match": "neshodují",
|
||||||
"edit": "Upravit",
|
"edit": "Upravit",
|
||||||
"elimination of poverty": "jehož cílem je urychlit odstranění chudoby tím, že organizacím umožní efektivněji a efektivněji poskytovat odpovědné finanční služby chudým a bez bankovních účtů ve světě. Zní to zajímavě?",
|
"elimination of poverty": "jehož cílem je urychlit odstranění chudoby tím, že organizacím umožní efektivněji a efektivněji poskytovat odpovědné finanční služby chudým a bez bankovních účtů ve světě. Zní to zajímavě?",
|
||||||
|
"Sign in to continue": "Přihlaste se pro pokračování na váš panel",
|
||||||
"global community": "globální komunita",
|
"global community": "globální komunita",
|
||||||
"is designed by the": "je navržena společností",
|
"is designed by the": "je navržena společností",
|
||||||
"per annum": "ročně",
|
"per annum": "ročně",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Ablehnen",
|
"Reject": "Ablehnen",
|
||||||
"Reject transfer": "Übertragung ablehnen",
|
"Reject transfer": "Übertragung ablehnen",
|
||||||
"Release Amount": "Freigabebetrag",
|
"Release Amount": "Freigabebetrag",
|
||||||
|
"Reload": "Neu laden",
|
||||||
"Remove": "Entfernen",
|
"Remove": "Entfernen",
|
||||||
"Request OTP": "OTP anfordern",
|
"Request OTP": "OTP anfordern",
|
||||||
"Reschedule": "Neu planen",
|
"Reschedule": "Neu planen",
|
||||||
@@ -1341,6 +1342,11 @@
|
|||||||
"Secure & Reliable": "Sicher und zuverlässig",
|
"Secure & Reliable": "Sicher und zuverlässig",
|
||||||
"Community Driven": "Gemeinschaftsorientiert",
|
"Community Driven": "Gemeinschaftsorientiert",
|
||||||
"Global Impact": "Globale Auswirkungen",
|
"Global Impact": "Globale Auswirkungen",
|
||||||
|
"Language": "Sprache",
|
||||||
|
"Server": "Server",
|
||||||
|
"Settings": "Einstellungen",
|
||||||
|
"Theme": "Design",
|
||||||
|
"Welcome Back": "Willkommen zurück",
|
||||||
"Personal Information": "Persönliche Informationen",
|
"Personal Information": "Persönliche Informationen",
|
||||||
"Account Information": "Kontoinformationen",
|
"Account Information": "Kontoinformationen",
|
||||||
"Entity Details": "Entitätsdetails",
|
"Entity Details": "Entitätsdetails",
|
||||||
@@ -3651,6 +3657,7 @@
|
|||||||
"do not match": "nicht übereinstimmen",
|
"do not match": "nicht übereinstimmen",
|
||||||
"edit": "bearbeiten",
|
"edit": "bearbeiten",
|
||||||
"elimination of poverty": "Ziel ist es, die Beseitigung der Armut zu beschleunigen, indem Organisationen in die Lage versetzt werden, verantwortungsvolle Finanzdienstleistungen für die Armen und Menschen ohne Bankkonto auf der Welt effektiver und effizienter bereitzustellen. Klingt interessant?",
|
"elimination of poverty": "Ziel ist es, die Beseitigung der Armut zu beschleunigen, indem Organisationen in die Lage versetzt werden, verantwortungsvolle Finanzdienstleistungen für die Armen und Menschen ohne Bankkonto auf der Welt effektiver und effizienter bereitzustellen. Klingt interessant?",
|
||||||
|
"Sign in to continue": "Melden Sie sich an, um zu Ihrem Dashboard fortzufahren",
|
||||||
"global community": "Globale Gemeinschaft",
|
"global community": "Globale Gemeinschaft",
|
||||||
"is designed by the": "wird von der entworfen",
|
"is designed by the": "wird von der entworfen",
|
||||||
"per annum": "pro Jahr",
|
"per annum": "pro Jahr",
|
||||||
|
|||||||
+737
-681
File diff suppressed because it is too large
Load Diff
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Rechazar",
|
"Reject": "Rechazar",
|
||||||
"Reject transfer": "Rechazar transferencia",
|
"Reject transfer": "Rechazar transferencia",
|
||||||
"Release Amount": "Liberar Monto",
|
"Release Amount": "Liberar Monto",
|
||||||
|
"Reload": "Recargar",
|
||||||
"Remove": "Eliminar",
|
"Remove": "Eliminar",
|
||||||
"Request OTP": "Solicitar OTP",
|
"Request OTP": "Solicitar OTP",
|
||||||
"Reschedule": "Reprogramar",
|
"Reschedule": "Reprogramar",
|
||||||
@@ -1341,6 +1342,11 @@
|
|||||||
"Secure & Reliable": "Seguro y Confiable",
|
"Secure & Reliable": "Seguro y Confiable",
|
||||||
"Community Driven": "Impulsado por la Comunidad",
|
"Community Driven": "Impulsado por la Comunidad",
|
||||||
"Global Impact": "Impacto Global",
|
"Global Impact": "Impacto Global",
|
||||||
|
"Language": "Idioma",
|
||||||
|
"Server": "Servidor",
|
||||||
|
"Settings": "Configuración",
|
||||||
|
"Theme": "Tema",
|
||||||
|
"Welcome Back": "Bienvenido de nuevo",
|
||||||
"Personal Information": "Información Personal",
|
"Personal Information": "Información Personal",
|
||||||
"Account Information": "Información de la Cuenta",
|
"Account Information": "Información de la Cuenta",
|
||||||
"Entity Details": "Detalles de la Persona Moral",
|
"Entity Details": "Detalles de la Persona Moral",
|
||||||
@@ -3652,6 +3658,7 @@
|
|||||||
"do not match": "no coinciden",
|
"do not match": "no coinciden",
|
||||||
"edit": "editar",
|
"edit": "editar",
|
||||||
"elimination of poverty": "que tiene como objetivo acelerar la eliminación de la pobreza al permitir que las organizaciones brinden de manera más efectiva y eficiente servicios financieros responsables a las personas de escasos recursos y no bancarizados alrededor del mundo. ¿Suena interesante?",
|
"elimination of poverty": "que tiene como objetivo acelerar la eliminación de la pobreza al permitir que las organizaciones brinden de manera más efectiva y eficiente servicios financieros responsables a las personas de escasos recursos y no bancarizados alrededor del mundo. ¿Suena interesante?",
|
||||||
|
"Sign in to continue": "Inicia sesión para continuar a tu panel",
|
||||||
"global community": "Comunidad global",
|
"global community": "Comunidad global",
|
||||||
"is designed by the": "está diseñado por la",
|
"is designed by the": "está diseñado por la",
|
||||||
"per annum": "anualmente",
|
"per annum": "anualmente",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Rechazar",
|
"Reject": "Rechazar",
|
||||||
"Reject transfer": "Rechazar transferencia",
|
"Reject transfer": "Rechazar transferencia",
|
||||||
"Release Amount": "Liberar Monto",
|
"Release Amount": "Liberar Monto",
|
||||||
|
"Reload": "Recargar",
|
||||||
"Remove": "Eliminar",
|
"Remove": "Eliminar",
|
||||||
"Request OTP": "Solicitar OTP",
|
"Request OTP": "Solicitar OTP",
|
||||||
"Reschedule": "Reprogramar",
|
"Reschedule": "Reprogramar",
|
||||||
@@ -1343,6 +1344,11 @@
|
|||||||
"Secure & Reliable": "Seguro y Confiable",
|
"Secure & Reliable": "Seguro y Confiable",
|
||||||
"Community Driven": "Impulsado por la Comunidad",
|
"Community Driven": "Impulsado por la Comunidad",
|
||||||
"Global Impact": "Impacto Global",
|
"Global Impact": "Impacto Global",
|
||||||
|
"Language": "Idioma",
|
||||||
|
"Server": "Servidor",
|
||||||
|
"Settings": "Configuración",
|
||||||
|
"Theme": "Tema",
|
||||||
|
"Welcome Back": "Bienvenido de nuevo",
|
||||||
"Personal Information": "Información Personal",
|
"Personal Information": "Información Personal",
|
||||||
"Account Information": "Información de la Cuenta",
|
"Account Information": "Información de la Cuenta",
|
||||||
"Entity Details": "Detalles de la Persona Moral",
|
"Entity Details": "Detalles de la Persona Moral",
|
||||||
@@ -3682,6 +3688,7 @@
|
|||||||
"do not match": "no coinciden",
|
"do not match": "no coinciden",
|
||||||
"edit": "editar",
|
"edit": "editar",
|
||||||
"elimination of poverty": "que tiene como objetivo acelerar la eliminación de la pobreza al permitir que las organizaciones brinden de manera más efectiva y eficiente servicios financieros responsables a las personas de escasos recursos y no bancarizados alrededor del mundo. ¿Suena interesante?",
|
"elimination of poverty": "que tiene como objetivo acelerar la eliminación de la pobreza al permitir que las organizaciones brinden de manera más efectiva y eficiente servicios financieros responsables a las personas de escasos recursos y no bancarizados alrededor del mundo. ¿Suena interesante?",
|
||||||
|
"Sign in to continue": "Inicia sesión para continuar a tu panel",
|
||||||
"global community": "Comunidad global",
|
"global community": "Comunidad global",
|
||||||
"is designed by the": "está diseñado por la",
|
"is designed by the": "está diseñado por la",
|
||||||
"per annum": "anualmente",
|
"per annum": "anualmente",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Rejeter",
|
"Reject": "Rejeter",
|
||||||
"Reject transfer": "Refuser le transfert",
|
"Reject transfer": "Refuser le transfert",
|
||||||
"Release Amount": "Montant de la libération",
|
"Release Amount": "Montant de la libération",
|
||||||
|
"Reload": "Recharger",
|
||||||
"Remove": "Retirer",
|
"Remove": "Retirer",
|
||||||
"Request OTP": "Demander un OTP",
|
"Request OTP": "Demander un OTP",
|
||||||
"Reschedule": "Reprogrammer",
|
"Reschedule": "Reprogrammer",
|
||||||
@@ -1344,6 +1345,11 @@
|
|||||||
"Secure & Reliable": "Sécurisé et fiable",
|
"Secure & Reliable": "Sécurisé et fiable",
|
||||||
"Community Driven": "Axé sur la communauté",
|
"Community Driven": "Axé sur la communauté",
|
||||||
"Global Impact": "Impact mondial",
|
"Global Impact": "Impact mondial",
|
||||||
|
"Language": "Langue",
|
||||||
|
"Server": "Serveur",
|
||||||
|
"Settings": "Paramètres",
|
||||||
|
"Theme": "Thème",
|
||||||
|
"Welcome Back": "Bon retour",
|
||||||
"Personal Information": "Informations personnelles",
|
"Personal Information": "Informations personnelles",
|
||||||
"Account Information": "Informations sur le compte",
|
"Account Information": "Informations sur le compte",
|
||||||
"Entity Details": "Détails de l'entité",
|
"Entity Details": "Détails de l'entité",
|
||||||
@@ -3653,6 +3659,7 @@
|
|||||||
"do not match": "ne correspondent pas",
|
"do not match": "ne correspondent pas",
|
||||||
"edit": "modifier",
|
"edit": "modifier",
|
||||||
"elimination of poverty": "qui vise à accélérer l’élimination de la pauvreté en permettant aux organisations de fournir plus efficacement des services financiers responsables aux pauvres et aux non-bancarisés du monde. Cela semble intéressant ?",
|
"elimination of poverty": "qui vise à accélérer l’élimination de la pauvreté en permettant aux organisations de fournir plus efficacement des services financiers responsables aux pauvres et aux non-bancarisés du monde. Cela semble intéressant ?",
|
||||||
|
"Sign in to continue": "Connectez-vous pour continuer vers votre tableau de bord",
|
||||||
"global community": "Communauté globale",
|
"global community": "Communauté globale",
|
||||||
"is designed by the": "est conçu par le",
|
"is designed by the": "est conçu par le",
|
||||||
"per annum": "par an",
|
"per annum": "par an",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Rifiutare",
|
"Reject": "Rifiutare",
|
||||||
"Reject transfer": "Rifiuta il trasferimento",
|
"Reject transfer": "Rifiuta il trasferimento",
|
||||||
"Release Amount": "Importo di rilascio",
|
"Release Amount": "Importo di rilascio",
|
||||||
|
"Reload": "Ricarica",
|
||||||
"Remove": "Rimuovere",
|
"Remove": "Rimuovere",
|
||||||
"Request OTP": "Richiedi OTP",
|
"Request OTP": "Richiedi OTP",
|
||||||
"Reschedule": "Riprogrammare",
|
"Reschedule": "Riprogrammare",
|
||||||
@@ -1340,6 +1341,11 @@
|
|||||||
"Secure & Reliable": "Sicuro e affidabile",
|
"Secure & Reliable": "Sicuro e affidabile",
|
||||||
"Community Driven": "Guidato dalla comunità",
|
"Community Driven": "Guidato dalla comunità",
|
||||||
"Global Impact": "Impatto globale",
|
"Global Impact": "Impatto globale",
|
||||||
|
"Language": "Lingua",
|
||||||
|
"Server": "Server",
|
||||||
|
"Settings": "Impostazioni",
|
||||||
|
"Theme": "Tema",
|
||||||
|
"Welcome Back": "Bentornato",
|
||||||
"Personal Information": "Informazioni personali",
|
"Personal Information": "Informazioni personali",
|
||||||
"Account Information": "Informazioni sull'account",
|
"Account Information": "Informazioni sull'account",
|
||||||
"Entity Details": "Dettagli dell'entità",
|
"Entity Details": "Dettagli dell'entità",
|
||||||
@@ -3650,6 +3656,7 @@
|
|||||||
"do not match": "non corrispondono",
|
"do not match": "non corrispondono",
|
||||||
"edit": "modificare",
|
"edit": "modificare",
|
||||||
"elimination of poverty": "che mira ad accelerare l’eliminazione della povertà consentendo alle organizzazioni di fornire in modo più efficace ed efficiente servizi finanziari responsabili ai poveri e a coloro che non dispongono di servizi bancari nel mondo. Sembra interessante?",
|
"elimination of poverty": "che mira ad accelerare l’eliminazione della povertà consentendo alle organizzazioni di fornire in modo più efficace ed efficiente servizi finanziari responsabili ai poveri e a coloro che non dispongono di servizi bancari nel mondo. Sembra interessante?",
|
||||||
|
"Sign in to continue": "Accedi per continuare alla tua dashboard",
|
||||||
"global community": "comunità globale",
|
"global community": "comunità globale",
|
||||||
"is designed by the": "è progettato da",
|
"is designed by the": "è progettato da",
|
||||||
"per annum": "per anno",
|
"per annum": "per anno",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "거부하다",
|
"Reject": "거부하다",
|
||||||
"Reject transfer": "이전 거부",
|
"Reject transfer": "이전 거부",
|
||||||
"Release Amount": "출시 금액",
|
"Release Amount": "출시 금액",
|
||||||
|
"Reload": "새로고침",
|
||||||
"Remove": "제거하다",
|
"Remove": "제거하다",
|
||||||
"Request OTP": "OTP 요청",
|
"Request OTP": "OTP 요청",
|
||||||
"Reschedule": "일정 변경",
|
"Reschedule": "일정 변경",
|
||||||
@@ -1342,6 +1343,11 @@
|
|||||||
"Secure & Reliable": "안전하고 신뢰할 수 있음",
|
"Secure & Reliable": "안전하고 신뢰할 수 있음",
|
||||||
"Community Driven": "커뮤니티 주도형",
|
"Community Driven": "커뮤니티 주도형",
|
||||||
"Global Impact": "글로벌 영향",
|
"Global Impact": "글로벌 영향",
|
||||||
|
"Language": "언어",
|
||||||
|
"Server": "서버",
|
||||||
|
"Settings": "설정",
|
||||||
|
"Theme": "테마",
|
||||||
|
"Welcome Back": "다시 오신 것을 환영합니다",
|
||||||
"Personal Information": "개인 정보",
|
"Personal Information": "개인 정보",
|
||||||
"Account Information": "계정 정보",
|
"Account Information": "계정 정보",
|
||||||
"Entity Details": "엔티티 세부 정보",
|
"Entity Details": "엔티티 세부 정보",
|
||||||
@@ -3651,6 +3657,7 @@
|
|||||||
"do not match": "일치하지 않는",
|
"do not match": "일치하지 않는",
|
||||||
"edit": "편집하다",
|
"edit": "편집하다",
|
||||||
"elimination of poverty": "이는 조직이 전 세계의 가난하고 은행 서비스를 이용할 수 없는 사람들에게 책임 있는 금융 서비스를 보다 효과적이고 효율적으로 제공할 수 있도록 하여 빈곤 퇴치 속도를 높이는 것을 목표로 합니다. 흥미롭나요?",
|
"elimination of poverty": "이는 조직이 전 세계의 가난하고 은행 서비스를 이용할 수 없는 사람들에게 책임 있는 금융 서비스를 보다 효과적이고 효율적으로 제공할 수 있도록 하여 빈곤 퇴치 속도를 높이는 것을 목표로 합니다. 흥미롭나요?",
|
||||||
|
"Sign in to continue": "대시보드로 계속하려면 로그인하세요",
|
||||||
"global community": "글로벌 커뮤니티",
|
"global community": "글로벌 커뮤니티",
|
||||||
"is designed by the": "에 의해 설계되었습니다",
|
"is designed by the": "에 의해 설계되었습니다",
|
||||||
"per annum": "연간",
|
"per annum": "연간",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Atmesti",
|
"Reject": "Atmesti",
|
||||||
"Reject transfer": "Atmesti perdavimą",
|
"Reject transfer": "Atmesti perdavimą",
|
||||||
"Release Amount": "Išleidimo suma",
|
"Release Amount": "Išleidimo suma",
|
||||||
|
"Reload": "Perkrauti",
|
||||||
"Remove": "Pašalinti",
|
"Remove": "Pašalinti",
|
||||||
"Request OTP": "Prašyti OTP",
|
"Request OTP": "Prašyti OTP",
|
||||||
"Reschedule": "Suplanuoti iš naujo",
|
"Reschedule": "Suplanuoti iš naujo",
|
||||||
@@ -1339,6 +1340,11 @@
|
|||||||
"Secure & Reliable": "Saugu ir patikima",
|
"Secure & Reliable": "Saugu ir patikima",
|
||||||
"Community Driven": "Bendruomenės varomas",
|
"Community Driven": "Bendruomenės varomas",
|
||||||
"Global Impact": "Pasaulinis poveikis",
|
"Global Impact": "Pasaulinis poveikis",
|
||||||
|
"Language": "Kalba",
|
||||||
|
"Server": "Serveris",
|
||||||
|
"Settings": "Nustatymai",
|
||||||
|
"Theme": "Tema",
|
||||||
|
"Welcome Back": "Sveiki sugrįžę",
|
||||||
"Personal Information": "Asmens informacija",
|
"Personal Information": "Asmens informacija",
|
||||||
"Account Information": "Paskyros informacija",
|
"Account Information": "Paskyros informacija",
|
||||||
"Entity Details": "Subjekto informacija",
|
"Entity Details": "Subjekto informacija",
|
||||||
@@ -3651,6 +3657,7 @@
|
|||||||
"do not match": "nesutampa",
|
"do not match": "nesutampa",
|
||||||
"edit": "Redaguoti",
|
"edit": "Redaguoti",
|
||||||
"elimination of poverty": "kuriuo siekiama paspartinti skurdo panaikinimą, suteikiant organizacijoms galimybę veiksmingiau ir efektyviau teikti atsakingas finansines paslaugas pasaulio neturtingiesiems ir neturintiems bankų. Skamba įdomiai?",
|
"elimination of poverty": "kuriuo siekiama paspartinti skurdo panaikinimą, suteikiant organizacijoms galimybę veiksmingiau ir efektyviau teikti atsakingas finansines paslaugas pasaulio neturtingiesiems ir neturintiems bankų. Skamba įdomiai?",
|
||||||
|
"Sign in to continue": "Prisijunkite, kad tęstumėte į savo valdymo skydelį",
|
||||||
"global community": "pasaulinė bendruomenė",
|
"global community": "pasaulinė bendruomenė",
|
||||||
"is designed by the": "yra suprojektuotas",
|
"is designed by the": "yra suprojektuotas",
|
||||||
"per annum": "per metus",
|
"per annum": "per metus",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Noraidīt",
|
"Reject": "Noraidīt",
|
||||||
"Reject transfer": "Noraidīt pārsūtīšanu",
|
"Reject transfer": "Noraidīt pārsūtīšanu",
|
||||||
"Release Amount": "Izlaiduma summa",
|
"Release Amount": "Izlaiduma summa",
|
||||||
|
"Reload": "Pārlādēt",
|
||||||
"Remove": "Noņemt",
|
"Remove": "Noņemt",
|
||||||
"Request OTP": "Pieprasīt OTP",
|
"Request OTP": "Pieprasīt OTP",
|
||||||
"Reschedule": "Pārplānot",
|
"Reschedule": "Pārplānot",
|
||||||
@@ -1341,6 +1342,11 @@
|
|||||||
"Secure & Reliable": "Drošs un uzticams",
|
"Secure & Reliable": "Drošs un uzticams",
|
||||||
"Community Driven": "Kopienas vadīts",
|
"Community Driven": "Kopienas vadīts",
|
||||||
"Global Impact": "Globālā ietekme",
|
"Global Impact": "Globālā ietekme",
|
||||||
|
"Language": "Valoda",
|
||||||
|
"Server": "Serveris",
|
||||||
|
"Settings": "Iestatījumi",
|
||||||
|
"Theme": "Tēma",
|
||||||
|
"Welcome Back": "Laipni lūdzam atpakaļ",
|
||||||
"Personal Information": "Personīgā informācija",
|
"Personal Information": "Personīgā informācija",
|
||||||
"Account Information": "Konta informācija",
|
"Account Information": "Konta informācija",
|
||||||
"Entity Details": "Uzņēmuma detaļas",
|
"Entity Details": "Uzņēmuma detaļas",
|
||||||
@@ -3651,6 +3657,7 @@
|
|||||||
"do not match": "nesakrīt",
|
"do not match": "nesakrīt",
|
||||||
"edit": "rediģēt",
|
"edit": "rediģēt",
|
||||||
"elimination of poverty": "kuras mērķis ir paātrināt nabadzības izskaušanu, ļaujot organizācijām efektīvāk un produktīvāk sniegt atbildīgus finanšu pakalpojumus pasaules nabadzīgajiem un bez bankām. Izklausās interesanti?",
|
"elimination of poverty": "kuras mērķis ir paātrināt nabadzības izskaušanu, ļaujot organizācijām efektīvāk un produktīvāk sniegt atbildīgus finanšu pakalpojumus pasaules nabadzīgajiem un bez bankām. Izklausās interesanti?",
|
||||||
|
"Sign in to continue": "Piesakieties, lai turpinātu uz savu paneli",
|
||||||
"global community": "globālā kopiena",
|
"global community": "globālā kopiena",
|
||||||
"is designed by the": "ir izstrādājis",
|
"is designed by the": "ir izstrādājis",
|
||||||
"per annum": "gadā",
|
"per annum": "gadā",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "अस्वीकार गर्नुहोस्",
|
"Reject": "अस्वीकार गर्नुहोस्",
|
||||||
"Reject transfer": "स्थानान्तरण अस्वीकार गर्नुहोस्",
|
"Reject transfer": "स्थानान्तरण अस्वीकार गर्नुहोस्",
|
||||||
"Release Amount": "रिलिज रकम",
|
"Release Amount": "रिलिज रकम",
|
||||||
|
"Reload": "पुनः लोड",
|
||||||
"Remove": "हटाउनुहोस्",
|
"Remove": "हटाउनुहोस्",
|
||||||
"Request OTP": "OTP अनुरोध गर्नुहोस्",
|
"Request OTP": "OTP अनुरोध गर्नुहोस्",
|
||||||
"Reschedule": "पुन: तालिका",
|
"Reschedule": "पुन: तालिका",
|
||||||
@@ -1339,6 +1340,11 @@
|
|||||||
"Secure & Reliable": "सुरक्षित र भरपर्दो",
|
"Secure & Reliable": "सुरक्षित र भरपर्दो",
|
||||||
"Community Driven": "समुदाय संचालित",
|
"Community Driven": "समुदाय संचालित",
|
||||||
"Global Impact": "विश्वव्यापी प्रभाव",
|
"Global Impact": "विश्वव्यापी प्रभाव",
|
||||||
|
"Language": "भाषा",
|
||||||
|
"Server": "सर्भर",
|
||||||
|
"Settings": "सेटिङ्स",
|
||||||
|
"Theme": "थिम",
|
||||||
|
"Welcome Back": "फेरि स्वागत छ",
|
||||||
"Personal Information": "व्यक्तिगत जानकारी",
|
"Personal Information": "व्यक्तिगत जानकारी",
|
||||||
"Account Information": "खाता जानकारी",
|
"Account Information": "खाता जानकारी",
|
||||||
"Entity Details": "संस्था विवरण",
|
"Entity Details": "संस्था विवरण",
|
||||||
@@ -3649,6 +3655,7 @@
|
|||||||
"do not match": "मिल्दैन",
|
"do not match": "मिल्दैन",
|
||||||
"edit": "सम्पादन गर्नुहोस्",
|
"edit": "सम्पादन गर्नुहोस्",
|
||||||
"elimination of poverty": "जसले विश्वका गरिब र बैंकविहीनहरूलाई जिम्मेवार वित्तीय सेवाहरू अझ प्रभावकारी र कुशलतापूर्वक प्रदान गर्न संगठनहरूलाई सक्षम बनाएर गरिबी उन्मूलनको गति बढाउने लक्ष्य राख्छ। रोचक लाग्छ?",
|
"elimination of poverty": "जसले विश्वका गरिब र बैंकविहीनहरूलाई जिम्मेवार वित्तीय सेवाहरू अझ प्रभावकारी र कुशलतापूर्वक प्रदान गर्न संगठनहरूलाई सक्षम बनाएर गरिबी उन्मूलनको गति बढाउने लक्ष्य राख्छ। रोचक लाग्छ?",
|
||||||
|
"Sign in to continue": "आफ्नो ड्यासबोर्डमा जारी राख्न साइन इन गर्नुहोस्",
|
||||||
"global community": "विश्वव्यापी समुदाय",
|
"global community": "विश्वव्यापी समुदाय",
|
||||||
"is designed by the": "द्वारा डिजाइन गरिएको छ",
|
"is designed by the": "द्वारा डिजाइन गरिएको छ",
|
||||||
"per annum": "प्रति वर्ष",
|
"per annum": "प्रति वर्ष",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Rejeitar",
|
"Reject": "Rejeitar",
|
||||||
"Reject transfer": "Rejeitar transferência",
|
"Reject transfer": "Rejeitar transferência",
|
||||||
"Release Amount": "Valor de liberação",
|
"Release Amount": "Valor de liberação",
|
||||||
|
"Reload": "Recarregar",
|
||||||
"Remove": "Remover",
|
"Remove": "Remover",
|
||||||
"Request OTP": "Solicitar OTP",
|
"Request OTP": "Solicitar OTP",
|
||||||
"Reschedule": "Reprogramar",
|
"Reschedule": "Reprogramar",
|
||||||
@@ -1340,6 +1341,11 @@
|
|||||||
"Secure & Reliable": "Seguro e confiável",
|
"Secure & Reliable": "Seguro e confiável",
|
||||||
"Community Driven": "Impulsionado pela comunidade",
|
"Community Driven": "Impulsionado pela comunidade",
|
||||||
"Global Impact": "Impacto global",
|
"Global Impact": "Impacto global",
|
||||||
|
"Language": "Idioma",
|
||||||
|
"Server": "Servidor",
|
||||||
|
"Settings": "Configurações",
|
||||||
|
"Theme": "Tema",
|
||||||
|
"Welcome Back": "Bem-vindo de volta",
|
||||||
"Personal Information": "Informações Pessoais",
|
"Personal Information": "Informações Pessoais",
|
||||||
"Account Information": "Informações da Conta",
|
"Account Information": "Informações da Conta",
|
||||||
"Entity Details": "Detalhes da Entidade",
|
"Entity Details": "Detalhes da Entidade",
|
||||||
@@ -3650,6 +3656,7 @@
|
|||||||
"do not match": "não combina",
|
"do not match": "não combina",
|
||||||
"edit": "editar",
|
"edit": "editar",
|
||||||
"elimination of poverty": "que visa acelerar a eliminação da pobreza, permitindo que as organizações forneçam serviços financeiros responsáveis de forma mais eficaz e eficiente aos pobres e sem conta bancária do mundo.Parece interessante?",
|
"elimination of poverty": "que visa acelerar a eliminação da pobreza, permitindo que as organizações forneçam serviços financeiros responsáveis de forma mais eficaz e eficiente aos pobres e sem conta bancária do mundo.Parece interessante?",
|
||||||
|
"Sign in to continue": "Faça login para continuar ao seu painel",
|
||||||
"global community": "comunidade global",
|
"global community": "comunidade global",
|
||||||
"is designed by the": "é projetado pelo",
|
"is designed by the": "é projetado pelo",
|
||||||
"per annum": "por ano",
|
"per annum": "por ano",
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
"Reject": "Kataa",
|
"Reject": "Kataa",
|
||||||
"Reject transfer": "Kataa uhamisho",
|
"Reject transfer": "Kataa uhamisho",
|
||||||
"Release Amount": "Kiasi cha Kutolewa",
|
"Release Amount": "Kiasi cha Kutolewa",
|
||||||
|
"Reload": "Pakia upya",
|
||||||
"Remove": "Ondoa",
|
"Remove": "Ondoa",
|
||||||
"Request OTP": "Omba OTP",
|
"Request OTP": "Omba OTP",
|
||||||
"Reschedule": "Panga upya",
|
"Reschedule": "Panga upya",
|
||||||
@@ -1338,6 +1339,11 @@
|
|||||||
"Secure & Reliable": "Salama na ya Kuaminika",
|
"Secure & Reliable": "Salama na ya Kuaminika",
|
||||||
"Community Driven": "Inaendeshwa na Jumuiya",
|
"Community Driven": "Inaendeshwa na Jumuiya",
|
||||||
"Global Impact": "Athari ya Kimataifa",
|
"Global Impact": "Athari ya Kimataifa",
|
||||||
|
"Language": "Lugha",
|
||||||
|
"Server": "Seva",
|
||||||
|
"Settings": "Mipangilio",
|
||||||
|
"Theme": "Mandhari",
|
||||||
|
"Welcome Back": "Karibu tena",
|
||||||
"Personal Information": "Taarifa za Kibinafsi",
|
"Personal Information": "Taarifa za Kibinafsi",
|
||||||
"Account Information": "Taarifa za Akaunti",
|
"Account Information": "Taarifa za Akaunti",
|
||||||
"Entity Details": "Maelezo ya Huluki",
|
"Entity Details": "Maelezo ya Huluki",
|
||||||
@@ -3648,6 +3654,7 @@
|
|||||||
"do not match": "hailingani",
|
"do not match": "hailingani",
|
||||||
"edit": "hariri",
|
"edit": "hariri",
|
||||||
"elimination of poverty": "ambayo inalenga kuharakisha uondoaji wa umaskini kwa kuwezesha Mashirika kutoa huduma za kifedha kwa ufanisi na kwa ufanisi zaidi kwa watu maskini na wasio na benki duniani. Inapendeza?",
|
"elimination of poverty": "ambayo inalenga kuharakisha uondoaji wa umaskini kwa kuwezesha Mashirika kutoa huduma za kifedha kwa ufanisi na kwa ufanisi zaidi kwa watu maskini na wasio na benki duniani. Inapendeza?",
|
||||||
|
"Sign in to continue": "Ingia ili kuendelea kwenye dashibodi yako",
|
||||||
"global community": "jumuiya ya kimataifa",
|
"global community": "jumuiya ya kimataifa",
|
||||||
"is designed by the": "imeundwa na",
|
"is designed by the": "imeundwa na",
|
||||||
"per annum": "kwa mwaka",
|
"per annum": "kwa mwaka",
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright since 2025 Mifos Initiative
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN!
|
// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN!
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
export default {
|
export default {
|
||||||
'mifos_x': {
|
'mifos_x': {
|
||||||
'version': '260318',
|
'version': '260320',
|
||||||
'hash': 'g0a32d7135'
|
'hash': 'gb3a4cce0c'
|
||||||
},
|
},
|
||||||
'allow_switching_backend_instance': true
|
'allow_switching_backend_instance': true
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export const environment = {
|
|||||||
displayTenantSelector: loadedEnv['displayTenantSelector'] || 'true',
|
displayTenantSelector: loadedEnv['displayTenantSelector'] || 'true',
|
||||||
/** Production mode - when true, shows minimal hero with only branding at bottom */
|
/** Production mode - when true, shows minimal hero with only branding at bottom */
|
||||||
productionMode: loadedEnv['productionMode'] === 'true' || loadedEnv['productionMode'] === true || false,
|
productionMode: loadedEnv['productionMode'] === 'true' || loadedEnv['productionMode'] === true || false,
|
||||||
tenantLogoUrl: loadedEnv['tenantLogoUrl'] || 'assets/images/default_home.png',
|
tenantLogoUrl: loadedEnv['tenantLogoUrl'] || 'assets/images/cbsnexora-logo.png',
|
||||||
tenantLogoUrlDark: loadedEnv['tenantLogoUrlDark'] || 'assets/images/white-mifos.png',
|
tenantLogoUrlDark: loadedEnv['tenantLogoUrlDark'] || 'assets/images/white-mifos.png',
|
||||||
documentationBaseUrl: loadedEnv['documentationBaseUrl'] || 'https://mifosforge.jira.com/wiki',
|
documentationBaseUrl: loadedEnv['documentationBaseUrl'] || 'https://mifosforge.jira.com/wiki',
|
||||||
// Time in seconds, default 60 seconds
|
// Time in seconds, default 60 seconds
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export const environment = {
|
|||||||
displayTenantSelector: loadedEnv.displayTenantSelector || 'true',
|
displayTenantSelector: loadedEnv.displayTenantSelector || 'true',
|
||||||
/** Production mode - when true, shows minimal hero with only branding at bottom */
|
/** Production mode - when true, shows minimal hero with only branding at bottom */
|
||||||
productionMode: loadedEnv.productionMode === 'true' || loadedEnv.productionMode === true || false,
|
productionMode: loadedEnv.productionMode === 'true' || loadedEnv.productionMode === true || false,
|
||||||
tenantLogoUrl: loadedEnv.tenantLogoUrl || 'assets/images/default_home.png',
|
tenantLogoUrl: loadedEnv.tenantLogoUrl || 'assets/images/cbsnexora-logo.png',
|
||||||
tenantLogoUrlDark: loadedEnv.tenantLogoUrlDark || 'assets/images/white-mifos.png',
|
tenantLogoUrlDark: loadedEnv.tenantLogoUrlDark || 'assets/images/white-mifos.png',
|
||||||
documentationBaseUrl: loadedEnv.documentationBaseUrl || 'https://mifosforge.jira.com/wiki',
|
documentationBaseUrl: loadedEnv.documentationBaseUrl || 'https://mifosforge.jira.com/wiki',
|
||||||
// Time in seconds, default 60 seconds
|
// Time in seconds, default 60 seconds
|
||||||
|
|||||||
+2
-3
@@ -17,9 +17,8 @@
|
|||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
|
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
<link rel="icon" type="image/svg+xml" href="assets/images/cbsnexora-favicon.svg" />
|
||||||
<link rel="icon" type="image/png" href="assets/images/MifosX_logo.png" sizes="182x184" />
|
<link rel="apple-touch-icon" type="image/svg+xml" href="assets/images/cbsnexora-favicon.svg" />
|
||||||
<link rel="apple-touch-icon" type="image/png" href="apple-touch-icon.png" sizes="182x184" />
|
|
||||||
<link rel="manifest" href="manifest.json" />
|
<link rel="manifest" href="manifest.json" />
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||||
|
|||||||
@@ -938,3 +938,22 @@ mat-card {
|
|||||||
margin: 1.5cm;
|
margin: 1.5cm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ─── Ensure mat-menu overlays appear above header ─── */
|
||||||
|
.cdk-overlay-container {
|
||||||
|
z-index: 1001 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── CRR/SLR Dialog Panel ─── */
|
||||||
|
.crr-slr-dialog-panel {
|
||||||
|
.mat-mdc-dialog-container {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-dialog-surface {
|
||||||
|
padding: 0 !important;
|
||||||
|
border-radius: 16px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+6
-6
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"short_name": "Mifos® X",
|
"short_name": "CBS Nexora",
|
||||||
"name": "Mifos® X Web App",
|
"name": "Nexora Web App",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"scope": "/",
|
"scope": "/",
|
||||||
"theme_color": "#fff",
|
"theme_color": "#fff",
|
||||||
"background_color": "#fff",
|
"background_color": "#fff",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"description": "Mifos® X Web App is the default web application built on top of the Apache Fineract® platform for the Mifos® user community leveraging the popular Angular framework.",
|
"description": "Nexora CBS – Powering the Next Generation of Core Banking.",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "assets/images/MifosX_logo.png",
|
"src": "assets/images/cbsnexora-favicon.svg",
|
||||||
"sizes": "182x184",
|
"sizes": "any",
|
||||||
"type": "image/png"
|
"type": "image/svg+xml"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user