@@ -131,6 +155,560 @@
}
}
+
+ @if (currentAccountProductSelected) {
+
+
+
+
+ @if (clientDob) {
+
+
+ cake
+ Date of Birth: {{ formatTemplateDate(clientDob) }}
+
+
+ person_pin
+ Age: {{ clientAge }} years
+
+ @if (clientAge !== null && clientAge < 18) {
+
+ child_care Auto-detected: Minor
+
+ } @else if (clientAge !== null && clientAge >= 60) {
+
+ elderly Auto-detected: Senior Citizen
+
+ } @else {
+
check_circle Age Verified
+ }
+
+ }
+
+
+
+ @for (opt of accountStatusOptions; track opt.value) {
+
+ }
+
+
+
+ @if (selectedAccountStatus === 'JOINT') {
+
+
+
+
A
+
+ Joint Account Holders
+ Add all co-applicants linked to this joint current account
+
+
+
+
+
+
+
+
+
+ | Sr. |
+ Holder Name |
+ CIF No. |
+ Ownership % |
+ Signing Authority |
+ Role |
+ Action |
+
+
+
+
+
+ | 1 |
+
+
+
+ {{ primaryClientName ? primaryClientName[0].toUpperCase() : '?' }}
+
+
+ {{ primaryClientName || 'Primary Holder' }}
+ Primary Account Holder
+
+
+ |
+
+ {{ primaryClientCif || '—' }}
+ |
+
+
+ %
+ |
+
+
+ lock Mandatory
+
+ |
+ Primary Account Holder |
+ — |
+
+
+
+ @for (h of jointHolders; track h; let i = $index) {
+
+ | {{ i + 2 }} |
+
+
+
+ {{ h.clientName[0].toUpperCase() }}
+
+
+ {{ h.clientName }}
+ @if (h.isMandatory) {
+ Mandatory Signatory
+ }
+
+
+ |
+
+ {{ h.clientCif || '—' }}
+ |
+
+
+ {{ h.sharePercentage }}%
+
+ |
+
+
+ |
+ Co-Holder |
+
+
+ |
+
+ }
+
+
+
+ | Total Ownership |
+
+
+ {{ totalJointSharePercentage }}%
+
+ |
+
+
+ lock {{ mandatoryJointCount + 1 }} Mandatory
+
+ |
+ |
+ |
+
+
+
+
+
+ @if (jointHolders.length === 0) {
+
+ group_add
+ Click Add Holder to add joint account holders.
+
+ }
+
+ @if (totalJointSharePercentage !== 100) {
+
+ warning_amber
+ Total ownership is {{ totalJointSharePercentage }}%. It must equal 100%.
+
+ } @else {
+
+ check_circle
+ Ownership allocation is complete (100%).
+
+ }
+
+
+
+
+
+
+
B
+
+ Mode of Operation
+ Auto-set from mandatory holders — override manually if required
+
+
+ @if (modeOfOperation) {
+
auto_awesome Auto
+ }
+
+
+ @if (jointHolders.length === 0) {
+
+ how_to_vote
+ Add joint holders in Section A first.
+
+ } @else {
+
+ @for (opt of modeOfOperationOptions; track opt.value) {
+
+ }
+
+
+
+ @if (modeOfOperation) {
+ how_to_vote
+ Mode of Operation: {{ selectedModeLabel }}
+
+ ({{ mandatoryJointCount }} Mandatory + {{ jointHolders.length - mandatoryJointCount }} Optional)
+
+ } @else {
+ info
+ Set Mandatory/Optional for holders above to auto-select mode.
+ }
+
+ }
+
+ }
+
+
+ @if (selectedAccountStatus === 'MINOR') {
+
+
+
+
+ child_care
+
+
+ Minor Account Details
+ As per RBI — guardian must be an existing registered client
+
+
+
Guardian Required
+
+
+
+
+ Minor's Date of Birth
+
+
+
+ @if (clientDob) {
+ Auto-filled from client profile
+ }
+
+
+
+ Age
+
+ Must be below 18 years
+
+
+
+ Date of Majority (Auto)
+
+ Auto-calculated: DOB + 18 years
+
+
+
+ Guardian Relationship
+
+ @for (rel of guardianRelationshipOptions; track rel) {
+ {{ rel }}
+ }
+
+
+
+
+
+
+ manage_accounts
+ Search & Link Guardian (existing client)
+
+
+
+ @if (guardianName) {
+
+
verified_user
+
+
{{ guardianName }}
+
CIF: {{ guardianCif || 'N/A' }}
+
+
Guardian Linked
+
+ }
+
+
+
+
info
+
+ - Minor below 10 years — Guardian must operate the account.
+ - Minor above 10 years — Can operate independently (bank discretion).
+ - Account must be converted to regular savings on attaining majority.
+ - Fresh KYC of the minor must be done on majority.
+
+
+
+ }
+
+
+ @if (selectedAccountStatus === 'SENIOR_CITIZEN') {
+
+
+
+
+ elderly
+
+
+ Senior Citizen Account
+ Age ≥ 60 years — eligible for preferential banking services
+
+
+
Age ≥ 60
+
+
+
+
+ Date of Birth
+
+ From client profile
+
+
+
+ Age
+
+ Age ≥ 60 required for Senior Citizen
+
+
+
+
+
+
priority_high
+
+ Priority Service
+ Dedicated counters / assisted banking at branches
+
+
+
+
percent
+
+ Preferential Interest Rate
+ Additional 0.25%–0.50% on deposits (as per product)
+
+
+
+
health_and_safety
+
+ Doorstep Banking
+ Eligible for home banking services (RBI circular)
+
+
+
+
gavel
+
+ Nomination Mandatory
+ RBI mandate — ensure nomination is registered
+
+
+
+
+
+
info
+
+ - Age proof (DOB document) mandatory at time of account opening.
+ - Nomination registration is compulsory (Form DA-1).
+ - Bank must offer dedicated helpline and priority grievance redressal.
+ - Door-step banking services must be offered (RBI Master Direction 2023).
+
+
+
+ }
+
+
+ @if (selectedAccountStatus === 'INDIVIDUAL_MALE') {
+
+
+
+
+ person
+
+
+ Individual Account (Male)
+ Select special category if applicable — governs applicable schemes & benefits
+
+
+
Special Category
+
+
+
+ @for (opt of specialCategoryOptions; track opt.value) {
+
+ }
+
+
+
+
info
+
+ - Valid KYC documents required (Aadhaar / PAN / Passport).
+ - Nomination registration is mandatory (Form DA-1).
+ - Defence / Ex-Serviceman — eligible for special savings schemes (DSSP).
+ - NRI — FCNR / NRE / NRO account rules apply as per FEMA guidelines.
+
+
+
+ }
+
+
+ @if (selectedAccountStatus === 'INDIVIDUAL_FEMALE') {
+
+
+
+
+ person_outline
+
+
+ Individual Account (Female)
+ Select weaker section category if applicable — governs PMJDY & priority schemes
+
+
+
Weaker Section
+
+
+
+ @for (opt of weakerSectionOptions; track opt.value) {
+
+ }
+
+
+
+
info
+
+ - Valid KYC documents required (Aadhaar / PAN / Passport).
+ - Nomination registration is mandatory (Form DA-1).
+ - BPL / SC-ST / Minority — eligible for zero-balance accounts (RBI Priority Sector norms).
+ - PMJDY beneficiary — ₹10,000 overdraft facility & accident insurance cover applicable.
+ - SHG members — group linkage lending & special deposit rates applicable.
+
+
+
+ }
+
+ }
+
@if (isNonIndividualClient && currentAccountProductSelected) {
diff --git a/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.scss b/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.scss
index bcad57a8c..859832e06 100644
--- a/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.scss
+++ b/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.scss
@@ -712,6 +712,941 @@ $ni-bg: #f9fafb;
}
}
+// ── Status of Account (RBI) ───────────────────────────────────────────────
+
+.soa-card {
+ margin-top: 16px;
+ border: 1px solid #e2e8f0;
+ border-radius: 10px;
+ background: #fff;
+ overflow: visible;
+
+ &__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 24px;
+ background: #f8f9fa;
+ border-bottom: 1px solid #e8eaed;
+ border-radius: 10px 10px 0 0;
+ }
+
+ &__header-left {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ }
+
+ &__icon {
+ width: 36px;
+ height: 36px;
+ border-radius: 8px;
+ background: #ede9fe;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ i {
+ font-size: 16px;
+ color: #7c3aed;
+ }
+ }
+
+ &__title {
+ margin: 0;
+ font-size: 14px;
+ font-weight: 600;
+ color: #202124;
+ }
+
+ &__sub {
+ font-size: 11px;
+ color: #6b7280;
+ display: block;
+ }
+}
+
+.soa-pill {
+ display: inline-flex;
+ align-items: center;
+ padding: 3px 12px;
+ border-radius: 999px;
+ font-size: 11px;
+ font-weight: 700;
+ background: #ede9fe;
+ color: #7c3aed;
+ border: 1px solid #ddd6fe;
+
+ &--minor {
+ background: #fef3c7;
+ color: #b45309;
+ border-color: #fde68a;
+ }
+
+ &--senior {
+ background: #d1fae5;
+ color: #065f46;
+ border-color: #a7f3d0;
+ }
+
+ &--ok {
+ background: #dcfce7;
+ color: #15803d;
+ border-color: #bbf7d0;
+ }
+}
+
+.soa-client-info-bar {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ padding: 10px 24px;
+ background: #f0f9ff;
+ border-bottom: 1px solid #bae6fd;
+ flex-wrap: wrap;
+
+ &__item {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 13px;
+ color: #0369a1;
+
+ mat-icon {
+ font-size: 16px;
+ height: 16px;
+ width: 16px;
+ }
+
+ strong {
+ font-weight: 700;
+ }
+ }
+}
+
+.soa-auto-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 3px 10px;
+ border-radius: 999px;
+ font-size: 11px;
+ font-weight: 700;
+ margin-left: auto;
+
+ mat-icon {
+ font-size: 13px;
+ height: 13px;
+ width: 13px;
+ }
+
+ &--minor {
+ background: #fef3c7;
+ color: #b45309;
+ border: 1px solid #fde68a;
+ }
+
+ &--senior {
+ background: #d1fae5;
+ color: #065f46;
+ border: 1px solid #a7f3d0;
+ }
+
+ &--ok {
+ background: #dcfce7;
+ color: #15803d;
+ border: 1px solid #bbf7d0;
+ }
+}
+
+.soa-tiles {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 12px;
+ padding: 16px 24px;
+ border-bottom: 1px solid #f1f5f9;
+
+ @media (width <= 900px) {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ @media (width <= 600px) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+.soa-tile {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ padding: 14px 10px;
+ border: 2px solid #e2e8f0;
+ border-radius: 10px;
+ background: #fff;
+ cursor: pointer;
+ transition:
+ border-color 0.15s,
+ box-shadow 0.15s;
+ position: relative;
+
+ &:hover {
+ border-color: #a5b4fc;
+ box-shadow: 0 2px 8px rgb(99 102 241 / 12%);
+ }
+
+ &--selected {
+ border-color: #6366f1;
+ background: #eef2ff;
+ box-shadow: 0 2px 12px rgb(99 102 241 / 20%);
+ }
+
+ &__icon {
+ font-size: 28px;
+ height: 28px;
+ width: 28px;
+ }
+
+ &__label {
+ font-size: 12px;
+ font-weight: 600;
+ color: #374151;
+ text-align: center;
+ }
+
+ &__check {
+ position: absolute;
+ top: 6px;
+ right: 6px;
+ font-size: 16px;
+ height: 16px;
+ width: 16px;
+ color: #6366f1;
+ }
+
+ &__lock {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ display: flex;
+ align-items: center;
+
+ mat-icon {
+ font-size: 13px;
+ height: 13px;
+ width: 13px;
+ color: #94a3b8;
+ }
+ }
+
+ &--disabled {
+ opacity: 0.45;
+ cursor: not-allowed;
+ background: #f8fafc;
+ border-color: #e2e8f0;
+ box-shadow: none;
+
+ &:hover {
+ border-color: #e2e8f0;
+ box-shadow: none;
+ }
+ }
+}
+
+.soa-block {
+ padding: 16px 24px;
+
+ &--sep {
+ border-top: 1px dashed #e2e8f0;
+ }
+
+ &__head {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ margin-bottom: 14px;
+ }
+
+ &__head-left {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ }
+
+ &__letter {
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 13px;
+ font-weight: 700;
+ color: #fff;
+ flex-shrink: 0;
+ margin-top: 2px;
+ }
+
+ &__title {
+ font-size: 13px;
+ font-weight: 600;
+ color: #1f2937;
+ display: block;
+ }
+
+ &__hint {
+ font-size: 11px;
+ color: #6b7280;
+ display: block;
+ }
+}
+
+.soa-table-wrap {
+ overflow-x: auto;
+ border-radius: 8px;
+ border: 1px solid #e2e8f0;
+}
+
+.soa-tbl {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 13px;
+}
+
+.soa-th {
+ padding: 10px 14px;
+ background: #f8fafc;
+ text-align: left;
+ font-weight: 600;
+ font-size: 11px;
+ color: #64748b;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ border-bottom: 1px solid #e2e8f0;
+
+ &--sr {
+ width: 44px;
+ }
+
+ &--center {
+ text-align: center;
+ }
+}
+
+.soa-td {
+ padding: 10px 14px;
+ border-bottom: 1px solid #f1f5f9;
+ vertical-align: middle;
+
+ &--sr {
+ text-align: center;
+ font-size: 12px;
+ color: #94a3b8;
+ font-weight: 600;
+ }
+
+ &--center {
+ text-align: center;
+ }
+
+ &--total-label {
+ font-size: 12px;
+ font-weight: 600;
+ color: #475569;
+ text-align: right;
+ }
+}
+
+.soa-tr {
+ transition: background 0.1s;
+
+ &:hover {
+ background: #f8fafc;
+ }
+
+ &--mandatory {
+ background: #fdf4ff;
+ }
+
+ &--primary {
+ background: #f0f9ff;
+ border-left: 3px solid #0891b2;
+ }
+}
+
+.soa-avatar--primary {
+ background: #cffafe;
+ color: #0e7490;
+}
+
+.soa-primary-tag {
+ font-size: 10px;
+ color: #0e7490;
+ font-weight: 600;
+ background: #cffafe;
+ padding: 1px 7px;
+ border-radius: 999px;
+ display: inline-block;
+}
+
+.soa-pct-input {
+ width: 56px;
+ padding: 4px 6px;
+ border: 1px solid #cbd5e1;
+ border-radius: 6px;
+ font-size: 13px;
+ font-weight: 600;
+ text-align: center;
+ color: #1f2937;
+
+ &:focus {
+ outline: none;
+ border-color: #0891b2;
+ box-shadow: 0 0 0 2px rgb(8 145 178 / 15%);
+ }
+
+ &::-webkit-inner-spin-button,
+ &::-webkit-outer-spin-button {
+ opacity: 1;
+ }
+}
+
+.soa-pct-unit {
+ font-size: 13px;
+ font-weight: 600;
+ color: #64748b;
+ margin-left: 2px;
+}
+
+.soa-no-action {
+ color: #cbd5e1;
+ font-size: 16px;
+}
+
+.soa-tr-total {
+ background: #f8fafc;
+}
+
+.soa-client-cell {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.soa-avatar {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background: #dbeafe;
+ color: #1d4ed8;
+ font-weight: 700;
+ font-size: 14px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+
+ &--mandatory {
+ background: #ede9fe;
+ color: #7c3aed;
+ }
+}
+
+.soa-client-name {
+ font-weight: 600;
+ font-size: 13px;
+ color: #1f2937;
+ display: block;
+}
+
+.soa-mandatory-tag {
+ font-size: 10px;
+ color: #7c3aed;
+ font-weight: 600;
+ background: #ede9fe;
+ padding: 1px 7px;
+ border-radius: 999px;
+}
+
+.soa-mono {
+ font-family: 'Roboto Mono', monospace;
+ font-size: 12px;
+ color: #64748b;
+}
+
+.soa-pct-badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 2px 10px;
+ border-radius: 999px;
+ font-size: 12px;
+ font-weight: 700;
+ background: #f1f5f9;
+ color: #475569;
+
+ &--full,
+ &--ok {
+ background: #dcfce7;
+ color: #15803d;
+ }
+
+ &--warn {
+ background: #fef3c7;
+ color: #b45309;
+ }
+}
+
+.soa-sign-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 4px 10px;
+ border-radius: 6px;
+ font-size: 12px;
+ font-weight: 600;
+ border: 1px solid #e2e8f0;
+ cursor: pointer;
+ transition: all 0.15s;
+
+ mat-icon {
+ font-size: 14px;
+ height: 14px;
+ width: 14px;
+ }
+
+ &--mandatory {
+ background: #ede9fe;
+ color: #7c3aed;
+ border-color: #ddd6fe;
+ }
+
+ &--optional {
+ background: #f8fafc;
+ color: #94a3b8;
+ }
+}
+
+.soa-mandatory-count {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 12px;
+ font-weight: 600;
+ color: #7c3aed;
+
+ mat-icon {
+ font-size: 14px;
+ height: 14px;
+ width: 14px;
+ }
+}
+
+.soa-alert {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-top: 10px;
+ padding: 8px 14px;
+ border-radius: 8px;
+ font-size: 13px;
+ font-weight: 500;
+
+ mat-icon {
+ font-size: 18px;
+ height: 18px;
+ width: 18px;
+ }
+
+ &--warn {
+ background: #fef3c7;
+ color: #b45309;
+ }
+
+ &--ok {
+ background: #dcfce7;
+ color: #15803d;
+ }
+}
+
+.soa-empty {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 20px;
+ background: #f8fafc;
+ border-radius: 8px;
+ font-size: 13px;
+ color: #64748b;
+
+ mat-icon {
+ color: #94a3b8;
+ font-size: 22px;
+ height: 22px;
+ width: 22px;
+ }
+}
+
+.soa-add-btn {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 13px;
+}
+
+.soa-mode-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 10px;
+
+ @media (width <= 700px) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+.soa-mode-card {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+ padding: 12px 8px;
+ border: 2px solid #e2e8f0;
+ border-radius: 10px;
+ background: #fff;
+ cursor: pointer;
+ transition: all 0.15s;
+
+ &:hover {
+ border-color: #a5b4fc;
+ }
+
+ &--selected {
+ border-color: #7c3aed;
+ background: #faf5ff;
+ }
+
+ &__icon {
+ font-size: 24px;
+ height: 24px;
+ width: 24px;
+ color: #7c3aed;
+ }
+
+ &__code {
+ font-size: 13px;
+ font-weight: 700;
+ color: #1f2937;
+ }
+
+ &__desc {
+ font-size: 11px;
+ color: #6b7280;
+ text-align: center;
+ }
+
+ &__check {
+ position: absolute;
+ top: 6px;
+ right: 6px;
+ font-size: 16px;
+ height: 16px;
+ width: 16px;
+ color: #7c3aed;
+ }
+}
+
+.soa-mode-summary {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-top: 12px;
+ padding: 8px 14px;
+ border-radius: 8px;
+ font-size: 13px;
+ background: #f8fafc;
+ color: #64748b;
+
+ mat-icon {
+ font-size: 18px;
+ height: 18px;
+ width: 18px;
+ }
+
+ &--set {
+ background: #faf5ff;
+ color: #7c3aed;
+ }
+
+ &__from {
+ font-size: 11px;
+ color: #94a3b8;
+ }
+}
+
+.soa-auto-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 3px 10px;
+ border-radius: 999px;
+ font-size: 11px;
+ font-weight: 700;
+ background: #fef9c3;
+ color: #854d0e;
+ border: 1px solid #fde68a;
+
+ mat-icon {
+ font-size: 13px;
+ height: 13px;
+ width: 13px;
+ }
+}
+
+.soa-minor-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 4px 16px;
+ margin-bottom: 16px;
+
+ @media (width <= 700px) {
+ grid-template-columns: 1fr;
+ }
+}
+
+.soa-field {
+ width: 100%;
+}
+
+.soa-guardian-search {
+ margin-bottom: 12px;
+
+ &__label {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 13px;
+ font-weight: 600;
+ color: #374151;
+ margin-bottom: 8px;
+
+ mat-icon {
+ font-size: 18px;
+ height: 18px;
+ width: 18px;
+ color: #7c3aed;
+ }
+ }
+}
+
+.soa-guardian-selected {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 14px;
+ background: #f0fdf4;
+ border: 1px solid #bbf7d0;
+ border-radius: 8px;
+ margin-top: 10px;
+
+ &__icon {
+ font-size: 24px;
+ height: 24px;
+ width: 24px;
+ color: #16a34a;
+ }
+
+ &__name {
+ font-size: 13px;
+ font-weight: 600;
+ color: #1f2937;
+ }
+
+ &__cif {
+ font-size: 11px;
+ color: #6b7280;
+ }
+}
+
+.soa-sc-benefits {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 10px;
+ margin-bottom: 14px;
+
+ @media (width <= 600px) {
+ grid-template-columns: 1fr;
+ }
+}
+
+.soa-sc-benefit {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ padding: 12px;
+ background: #f0fdf4;
+ border: 1px solid #bbf7d0;
+ border-radius: 8px;
+
+ mat-icon {
+ color: #16a34a;
+ font-size: 20px;
+ height: 20px;
+ width: 20px;
+ flex-shrink: 0;
+ margin-top: 2px;
+ }
+
+ strong {
+ display: block;
+ font-size: 13px;
+ color: #1f2937;
+ font-weight: 600;
+ }
+
+ span {
+ font-size: 11px;
+ color: #6b7280;
+ }
+}
+
+.soa-category-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 10px;
+ margin-bottom: 16px;
+
+ @media (width <= 700px) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+.soa-cat-tile {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ padding: 14px 10px;
+ border: 2px solid #e2e8f0;
+ border-radius: 10px;
+ background: #fff;
+ cursor: pointer;
+ transition: all 0.15s;
+
+ &:hover {
+ border-color: #a5b4fc;
+ box-shadow: 0 2px 8px rgb(99 102 241 / 12%);
+ }
+
+ &--selected {
+ &.soa-cat-tile--male {
+ border-color: #3b82f6;
+ background: #eff6ff;
+ box-shadow: 0 2px 12px rgb(59 130 246 / 20%);
+ }
+
+ &.soa-cat-tile--female {
+ border-color: #ec4899;
+ background: #fdf2f8;
+ box-shadow: 0 2px 12px rgb(236 72 153 / 20%);
+ }
+ }
+
+ &__icon {
+ font-size: 26px;
+ height: 26px;
+ width: 26px;
+ color: #64748b;
+ }
+
+ &--selected.soa-cat-tile--male &__icon {
+ color: #3b82f6;
+ }
+
+ &--selected.soa-cat-tile--female &__icon {
+ color: #ec4899;
+ }
+
+ &__label {
+ font-size: 11px;
+ font-weight: 600;
+ color: #374151;
+ text-align: center;
+ line-height: 1.3;
+ }
+
+ &__check {
+ position: absolute;
+ top: 6px;
+ right: 6px;
+ font-size: 16px;
+ height: 16px;
+ width: 16px;
+
+ .soa-cat-tile--male & {
+ color: #3b82f6;
+ }
+
+ .soa-cat-tile--female & {
+ color: #ec4899;
+ }
+ }
+}
+
+.soa-info-banner {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ padding: 12px 14px;
+ border-radius: 8px;
+ font-size: 12px;
+ background: #eff6ff;
+ border: 1px solid #bfdbfe;
+ color: #1e40af;
+
+ mat-icon {
+ font-size: 18px;
+ height: 18px;
+ width: 18px;
+ flex-shrink: 0;
+ margin-top: 2px;
+ }
+
+ ul {
+ margin: 4px 0 0;
+ padding-left: 18px;
+
+ li {
+ margin-bottom: 3px;
+ }
+ }
+
+ &--minor {
+ background: #fefce8;
+ border-color: #fde68a;
+ color: #92400e;
+ }
+
+ &--senior {
+ background: #f0fdf4;
+ border-color: #bbf7d0;
+ color: #065f46;
+ }
+
+ &--male {
+ background: #eff6ff;
+ border-color: #bfdbfe;
+ color: #1e40af;
+ }
+
+ &--female {
+ background: #fdf2f8;
+ border-color: #f9a8d4;
+ color: #9d174d;
+ }
+}
+
// ── Account Feature Toggles ────────────────────────────────────────────────
.sad-toggles {
display: flex;
diff --git a/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.ts b/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.ts
index 8f1523d0e..cd2f8d1e4 100644
--- a/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.ts
+++ b/src/app/current-accounts/current-account-stepper/current-account-details-step/current-account-details-step.component.ts
@@ -8,7 +8,7 @@
/** Angular Imports */
import { Component, OnInit, Input, Output, EventEmitter, inject, ChangeDetectorRef } from '@angular/core';
-import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
+import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
@@ -17,20 +17,7 @@ import { SettingsService } from 'app/settings/settings.service';
import { ClientsService } from 'app/clients/clients.service';
import { MatDialog } from '@angular/material/dialog';
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
-import {
- MatTable,
- MatColumnDef,
- MatHeaderCellDef,
- MatHeaderCell,
- MatCellDef,
- MatCell,
- MatHeaderRowDef,
- MatHeaderRow,
- MatRowDef,
- MatRow
-} from '@angular/material/table';
import { MatIcon } from '@angular/material/icon';
-import { FormsModule } from '@angular/forms';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { IntroducerSearchComponent } from 'app/shared/introducer-search/introducer-search.component';
@@ -49,16 +36,6 @@ import { AddRelatedClientDialogComponent } from './add-related-client-dialog/add
FaIconComponent,
MatStepperNext,
IntroducerSearchComponent,
- MatTable,
- MatColumnDef,
- MatHeaderCellDef,
- MatHeaderCell,
- MatCellDef,
- MatCell,
- MatHeaderRowDef,
- MatHeaderRow,
- MatRowDef,
- MatRow,
MatIcon,
FormsModule
]
@@ -72,20 +49,13 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
private dateUtils = inject(Dates);
private cdr = inject(ChangeDetectorRef);
- /** Current Account Template */
@Input() currentAccountTemplate: any;
- /** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
- /** Maximum date allowed. */
maxDate = new Date();
- /** Product Data */
productData: any;
- /** Field Officer Data */
fieldOfficerData: any;
- /** For edit current account form */
isFieldOfficerPatched = false;
- /** Current Account Details Form */
currentAccountDetailsForm: UntypedFormGroup;
currentAccountProductSelected = false;
@@ -93,7 +63,7 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
introducerName: string | null = null;
introducerCif: string | null = null;
- /** Non-Individual section */
+ // ── Non-Individual (existing) ──────────────────────────────────────────
isNonIndividualClient = false;
relatedClients: Array<{
clientId: number;
@@ -111,11 +81,92 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
{ value: 'ONLY_ONE', label: 'Single', sublabel: 'Only 1 Person', icon: 'person' }
];
- /** Current Account Template with product data */
@Output() currentAccountProductTemplate = new EventEmitter();
- /** Local copy of product template for displaying classification info */
productTemplate: any = null;
+ accountTypeOptions: string[] = [];
+ customerSegmentOptions: string[] = [];
+ selectedAccountType: string | null = null;
+ selectedCustomerSegment: string | null = null;
+
+ // ── Client info (auto-fetched) ─────────────────────────────────────────
+ clientDob: Date | null = null;
+ clientAge: number | null = null;
+ clientGender: string | null = null;
+ primaryClientName = '';
+ primaryClientCif = '';
+ primaryClientId: number | null = null;
+ primaryHolderShare = 0;
+
+ // ── Status of Account (RBI) ────────────────────────────────────────────
+ readonly accountStatusOptions = [
+ { value: 'INDIVIDUAL_MALE', label: 'Individual (Male)', icon: 'person', color: '#3b82f6' },
+ { value: 'INDIVIDUAL_FEMALE', label: 'Individual (Female)', icon: 'person_outline', color: '#ec4899' },
+ { value: 'SINGLE', label: 'Single Account', icon: 'account_circle', color: '#0891b2' },
+ { value: 'JOINT', label: 'Joint Account', icon: 'group', color: '#8b5cf6' },
+ { value: 'MINOR', label: 'Minor Account', icon: 'child_care', color: '#f59e0b' },
+ { value: 'SENIOR_CITIZEN', label: 'Senior Citizen', icon: 'elderly', color: '#10b981' }
+ ];
+
+ selectedAccountStatus = '';
+
+ // ── Joint Account (Status of Account) ─────────────────────────────────
+ jointHolders: Array<{
+ clientId: number;
+ clientName: string;
+ clientCif: string;
+ sharePercentage: number;
+ isMandatory: boolean;
+ signingAuthority?: string;
+ role?: string;
+ }> = [];
+
+ modeOfOperation = '';
+
+ readonly modeOfOperationOptions = [
+ { value: 'EITHER_OR_SURVIVOR', label: 'E or S', sublabel: 'Either or Survivor', icon: 'how_to_vote' },
+ { value: 'FORMER_OR_SURVIVOR', label: 'F or S', sublabel: 'Former or Survivor', icon: 'person' },
+ { value: 'JOINTLY', label: 'Jointly', sublabel: 'All Must Sign', icon: 'groups' },
+ { value: 'ANYONE_OR_SURVIVOR', label: 'Anyone', sublabel: 'Anyone or Survivor', icon: 'group' }
+ ];
+
+ // ── Individual Male — Special Category ────────────────────────────────
+ selectedSpecialCategory = '';
+
+ readonly specialCategoryOptions = [
+ { value: 'DEFENCE', label: 'Defence Personnel', icon: 'military_tech' },
+ { value: 'EX_SERVICEMAN', label: 'Ex-Serviceman', icon: 'shield' },
+ { value: 'GOVT_EMPLOYEE', label: 'Government Employee', icon: 'account_balance' },
+ { value: 'PHYSICALLY_CHALLENGED', label: 'Physically Challenged', icon: 'accessible' },
+ { value: 'NRI', label: 'NRI (Non-Resident Indian)', icon: 'flight' },
+ { value: 'NONE', label: 'None / General', icon: 'person' }
+ ];
+
+ // ── Individual Female — Weaker Section ────────────────────────────────
+ selectedWeakerSection = '';
+
+ readonly weakerSectionOptions = [
+ { value: 'BPL', label: 'BPL (Below Poverty Line)', icon: 'volunteer_activism' },
+ { value: 'SC_ST', label: 'SC / ST Category', icon: 'groups' },
+ { value: 'MINORITY', label: 'Minority Community', icon: 'diversity_3' },
+ { value: 'SHG', label: 'Self Help Group Member', icon: 'handshake' },
+ { value: 'PMJDY', label: 'PMJDY Beneficiary', icon: 'savings' },
+ { value: 'NONE', label: 'None / General', icon: 'person_outline' }
+ ];
+
+ // ── Minor Account ──────────────────────────────────────────────────────
+ guardianClientId: number | null = null;
+ guardianName = '';
+ guardianCif = '';
+ guardianRelationship = '';
+ minorDob: Date | null = null;
+
+ readonly guardianRelationshipOptions = [
+ 'Father',
+ 'Mother',
+ 'Legal Guardian',
+ 'Court Appointed Guardian'
+ ];
constructor() {
this.createCurrentAccountDetailsForm();
@@ -124,9 +175,23 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.buildDependencies();
- if (this.currentAccountTemplate?.clientId) {
- this.clientsService.getClientData(String(this.currentAccountTemplate.clientId)).subscribe((client: any) => {
+
+ const clientId = this.currentAccountTemplate?.clientId;
+ if (clientId) {
+ this.primaryClientId = clientId;
+ this.clientsService.getClientData(String(clientId)).subscribe((client: any) => {
this.isNonIndividualClient = client?.legalForm?.id === 2;
+ this.primaryClientName = client?.displayName ?? client?.fullname ?? '';
+ this.primaryClientCif = client?.cifNumber ?? client?.cifNo ?? '';
+ if (client?.dateOfBirth) {
+ const dob = this.parseClientDob(client.dateOfBirth);
+ if (dob) {
+ this.clientDob = dob;
+ this.clientAge = this.calculateAge(dob);
+ this.clientGender = client.gender?.name?.toLowerCase() ?? null;
+ this.autoDetectAccountStatus();
+ }
+ }
this.cdr.detectChanges();
});
}
@@ -149,9 +214,6 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
}
}
- /**
- * Creates current account details form.
- */
createCurrentAccountDetailsForm() {
this.currentAccountDetailsForm = this.formBuilder.group({
productId: [
@@ -166,22 +228,19 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
externalId: [''],
balanceSwapOption: [false],
msme: [false],
- autoDebitFacility: [false]
+ autoDebitFacility: [false],
+ establishmentDate: [''],
+ startOperationDate: ['']
});
}
- /**
- * Fetches current account product template on productId value changes
- */
buildDependencies() {
const entityId = this.currentAccountTemplate.groupId || this.currentAccountTemplate.clientId;
this.currentAccountDetailsForm.get('productId').valueChanges.subscribe((productId: string) => {
this.currentAccountsService
.getCurrentAccountTemplate(entityId, productId, this.currentAccountTemplate.groupId ? true : false)
.subscribe((response: any) => {
- // Ensure currency is included in the product template
if (!response.currency) {
- // Try to get currency from the selected product
const selectedProduct = this.currentAccountTemplate.productOptions?.find(
(product: any) => product.id == productId
);
@@ -192,10 +251,13 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
}
}
this.productTemplate = response;
+ this.accountTypeOptions = this.extractOptions(response.accountTypeOptions, response.accountType);
+ this.customerSegmentOptions = this.extractOptions(response.customerSegmentOptions, response.customerSegment);
+ this.selectedAccountType = response.accountType ?? null;
+ this.selectedCustomerSegment = response.customerSegment ?? null;
this.currentAccountProductTemplate.emit(response);
this.fieldOfficerData = response.fieldOfficerOptions;
this.currentAccountProductSelected = true;
- // Pre-populate toggles from product defaults (user can override)
this.currentAccountDetailsForm.patchValue({
balanceSwapOption: !!response.balanceSwapOption,
msme: !!response.msme,
@@ -212,13 +274,15 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
});
}
- /**
- * Formats template dates into the current CBS date format.
- */
- formatTemplateDate(value: any): string {
- if (!value) {
- return '';
+ private extractOptions(options: any[], fallback?: string): string[] {
+ if (Array.isArray(options) && options.length > 0) {
+ return options.map((o: any) => o.value ?? o.name ?? o);
}
+ return fallback ? [fallback] : [];
+ }
+
+ formatTemplateDate(value: any): string {
+ if (!value) return '';
let dateValue: Date | null = null;
if (value instanceof Date) {
dateValue = value;
@@ -233,15 +297,125 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
return this.dateUtils.formatDate(dateValue, 'M/d/yyyy') || '';
}
- /**
- * Returns current account form value.
- */
+ // ── Client DOB helpers ─────────────────────────────────────────────────
+ private parseClientDob(dob: any): Date | null {
+ if (!dob) return null;
+ if (Array.isArray(dob) && dob.length >= 3) return new Date(dob[0], dob[1] - 1, dob[2]);
+ const d = new Date(dob);
+ return isNaN(d.getTime()) ? null : d;
+ }
+
+ private calculateAge(dob: Date): number {
+ const today = this.settingsService.businessDate ?? new Date();
+ let age = today.getFullYear() - dob.getFullYear();
+ const m = today.getMonth() - dob.getMonth();
+ if (m < 0 || (m === 0 && today.getDate() < dob.getDate())) age--;
+ return age;
+ }
+
+ private autoDetectAccountStatus(): void {
+ if (this.clientAge === null) return;
+ if (this.clientAge < 18) {
+ this.selectedAccountStatus = 'MINOR';
+ this.minorDob = this.clientDob;
+ } else if (this.clientAge >= 60) {
+ this.selectedAccountStatus = 'SENIOR_CITIZEN';
+ } else if (this.clientGender === 'female') {
+ this.selectedAccountStatus = 'INDIVIDUAL_FEMALE';
+ } else {
+ this.selectedAccountStatus = 'INDIVIDUAL_MALE';
+ }
+ }
+
+ isTileDisabled(value: string): boolean {
+ if (value === 'MINOR') return this.clientAge === null || this.clientAge >= 18;
+ if (value === 'SENIOR_CITIZEN') return this.clientAge === null || this.clientAge < 60;
+ return false;
+ }
+
+ getTileTooltip(value: string): string {
+ if (value === 'MINOR' && this.clientAge !== null && this.clientAge >= 18)
+ return `Age ${this.clientAge} yrs — Minor only allowed below 18 years`;
+ if (value === 'SENIOR_CITIZEN' && this.clientAge !== null && this.clientAge < 60)
+ return `Age ${this.clientAge} yrs — Senior Citizen only allowed at 60+ years`;
+ if (value === 'MINOR' && this.clientAge === null) return 'DOB not available — cannot verify age';
+ if (value === 'SENIOR_CITIZEN' && this.clientAge === null) return 'DOB not available — cannot verify age';
+ return '';
+ }
+
+ // ── Introducer ─────────────────────────────────────────────────────────
onIntroducerChange(event: { clientId: number; displayName: string; cifNumber?: string } | null): void {
this.introducerId = event?.clientId ?? null;
this.introducerName = event?.displayName ?? null;
this.introducerCif = event?.cifNumber ?? null;
}
+ onGuardianChange(event: { clientId: number; displayName: string; cifNumber?: string } | null): void {
+ this.guardianClientId = event?.clientId ?? null;
+ this.guardianName = event?.displayName ?? '';
+ this.guardianCif = event?.cifNumber ?? '';
+ }
+
+ // ── Joint Account (Status of Account) ─────────────────────────────────
+ openAddJointHolderDialog(): void {
+ const ref = this.dialog.open(AddRelatedClientDialogComponent, {
+ width: '500px',
+ panelClass: 'arc-dialog-panel',
+ disableClose: true
+ });
+ ref.afterClosed().subscribe((result) => {
+ if (result) {
+ const duplicate = this.jointHolders.some((h) => h.clientCif && h.clientCif === result.clientCif);
+ if (duplicate) {
+ alert(`Account holder with CIF ${result.clientCif} is already added.`);
+ return;
+ }
+ this.jointHolders = [
+ ...this.jointHolders,
+ { ...result, isMandatory: false }];
+ this.autoSetModeOfOperation();
+ }
+ });
+ }
+
+ removeJointHolder(index: number): void {
+ this.jointHolders = this.jointHolders.filter((_, i) => i !== index);
+ this.autoSetModeOfOperation();
+ }
+
+ toggleJointHolderMandatory(holder: any): void {
+ holder.isMandatory = !holder.isMandatory;
+ this.autoSetModeOfOperation();
+ }
+
+ autoSetModeOfOperation(): void {
+ const mandatory = this.jointHolders.filter((h) => h.isMandatory).length;
+ if (mandatory === 0) this.modeOfOperation = 'EITHER_OR_SURVIVOR';
+ else if (mandatory === 1) this.modeOfOperation = 'FORMER_OR_SURVIVOR';
+ else this.modeOfOperation = 'JOINTLY';
+ }
+
+ get totalJointSharePercentage(): number {
+ return (this.primaryHolderShare || 0) + this.jointHolders.reduce((sum, h) => sum + (h.sharePercentage || 0), 0);
+ }
+
+ get mandatoryJointCount(): number {
+ return this.jointHolders.filter((h) => h.isMandatory).length;
+ }
+
+ get selectedModeLabel(): string {
+ return this.modeOfOperationOptions.find((o) => o.value === this.modeOfOperation)?.sublabel ?? '';
+ }
+
+ get majorityDate(): string {
+ const dob = this.minorDob ?? this.clientDob;
+ if (!dob) return '';
+ const d = new Date(dob);
+ d.setFullYear(d.getFullYear() + 18);
+ return this.dateUtils.formatDate(d, 'M/d/yyyy') || '';
+ }
+
+ // ── Non-Individual (existing) helpers ──────────────────────────────────
openAddRelatedClientDialog(): void {
const ref = this.dialog.open(AddRelatedClientDialogComponent, {
width: '500px',
@@ -273,16 +447,11 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
this.autoSetSignatoryRights();
}
- /** Auto-compute Mode of Operation based on mandatory count */
autoSetSignatoryRights(): void {
const mandatory = this.relatedClients.filter((c) => c.isMandatory).length;
- if (mandatory === 0) {
- this.signatoryRights = 'ANYONE';
- } else if (mandatory === 1) {
- this.signatoryRights = 'ONE_MANDATORY';
- } else {
- this.signatoryRights = 'TWO_MANDATORY';
- }
+ if (mandatory === 0) this.signatoryRights = 'ANYONE';
+ else if (mandatory === 1) this.signatoryRights = 'ONE_MANDATORY';
+ else this.signatoryRights = 'TWO_MANDATORY';
}
get totalSharePercentage(): number {
@@ -305,6 +474,48 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
value.introducerName = this.introducerName;
value.introducerCif = this.introducerCif;
}
+ value.isNonIndividualClient = this.isNonIndividualClient;
+
+ // accountStatus applies to all client types
+ value.accountStatus = this.selectedAccountStatus || null;
+ if (this.selectedAccountStatus === 'INDIVIDUAL_MALE' && this.selectedSpecialCategory)
+ value.specialCategory = this.selectedSpecialCategory;
+ if (this.selectedAccountStatus === 'INDIVIDUAL_FEMALE' && this.selectedWeakerSection)
+ value.weakerSection = this.selectedWeakerSection;
+ if (this.selectedAccountStatus === 'JOINT') {
+ value.modeOfOperation = this.modeOfOperation || null;
+ value.jointHolders = [
+ {
+ clientId: this.primaryClientId,
+ clientName: this.primaryClientName,
+ clientCif: this.primaryClientCif,
+ sharePercentage: this.primaryHolderShare,
+ isMandatory: true,
+ isPrimary: true,
+ signingAuthority: 'Mandatory',
+ role: 'Primary Account Holder'
+ },
+ ...this.jointHolders.map((h) => ({
+ clientId: h.clientId,
+ clientName: h.clientName,
+ clientCif: h.clientCif,
+ sharePercentage: h.sharePercentage,
+ isMandatory: h.isMandatory,
+ isPrimary: false,
+ signingAuthority: h.signingAuthority || (h.isMandatory ? 'Mandatory' : 'Optional'),
+ role: h.role || 'Co-Holder'
+ }))
+ ];
+ }
+ if (this.selectedAccountStatus === 'MINOR') {
+ value.guardianClientId = this.guardianClientId;
+ value.guardianName = this.guardianName;
+ value.guardianCif = this.guardianCif;
+ value.guardianRelationship = this.guardianRelationship;
+ value.minorDob = this.minorDob ? this.dateUtils.formatDate(this.minorDob, 'yyyy-MM-dd') : null;
+ }
+
+ // non-individual: partners are a separate dataset
if (this.isNonIndividualClient) {
value.signatoryRights = this.signatoryRights || null;
value.partners = this.relatedClients.map((c) => ({
diff --git a/src/app/current-accounts/current-account-stepper/current-account-preview-step/current-account-preview-step.component.html b/src/app/current-accounts/current-account-stepper/current-account-preview-step/current-account-preview-step.component.html
index 222c0c142..04797de4c 100644
--- a/src/app/current-accounts/current-account-stepper/current-account-preview-step/current-account-preview-step.component.html
+++ b/src/app/current-accounts/current-account-stepper/current-account-preview-step/current-account-preview-step.component.html
@@ -42,6 +42,18 @@
Unassigned
}
+ @if (currentAccount?.establishmentDate) {
+
+ Establishment Date
+ {{ currentAccount.establishmentDate | dateFormat }}
+
+ }
+ @if (currentAccount?.startOperationDate) {
+
+ Start of Operation Date
+ {{ currentAccount.startOperationDate | dateFormat }}
+
+ }