Files
cbsnexora/src/app/deposits/recurring-deposits/recurring-deposits-account-stepper/recurring-deposits-account-preview-step/recurring-deposits-account-preview-step.component.ts
T
Jaanu423andClaude Sonnet 4.6 3370a95235 feat: account charges UI — current account, FD, RD stepper redesign
Redesigned create-account stepper UI for current accounts, fixed deposits,
and recurring deposits: updated layout, preview steps, interest rate chart
step, currency step, and detail step components. Savings preview styling
and currency step also updated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 12:47:25 +05:30

272 lines
8.9 KiB
TypeScript

/**
* 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/.
*/
/** Angular Imports */
import { Component, Input, Output, EventEmitter, OnChanges } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { MatDivider } from '@angular/material/divider';
import { NgIf, NgSwitch, TitleCasePipe } from '@angular/common';
import {
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow
} from '@angular/material/table';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { MatStepperPrevious } from '@angular/material/stepper';
import { FindPipe } from '../../../../pipes/find.pipe';
import { DateFormatPipe } from '../../../../pipes/date-format.pipe';
import { FormatNumberPipe } from '../../../../pipes/format-number.pipe';
import { YesnoPipe } from '../../../../pipes/yesno.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Recurring Deposit Preview Step
*/
@Component({
selector: 'mifosx-recurring-deposits-account-preview-step',
templateUrl: './recurring-deposits-account-preview-step.component.html',
styleUrls: ['./recurring-deposits-account-preview-step.component.scss'],
animations: [
trigger('expandChartSlab', [
state('collapsed', style({ height: '0px', minHeight: '0' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
])
],
imports: [
...STANDALONE_SHARED_IMPORTS,
MatDivider,
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
FaIconComponent,
NgSwitch,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow,
MatStepperPrevious,
TitleCasePipe,
FindPipe,
DateFormatPipe,
FormatNumberPipe,
YesnoPipe
]
})
export class RecurringDepositsAccountPreviewStepComponent implements OnChanges {
/** Input Data */
@Input() recurringDepositsAccountTemplate: any;
@Input() hideButtons = false;
@Input() recurringDepositsAccountProductTemplate: any;
@Input() recurringDepositAccountData: any;
@Input() rdNominees: any[] = [];
@Input() rdCurrencyFlags: any = null;
@Input() rdTenureDays: number | null = null;
@Input() rdApplicableSlab: any = null;
@Input() rdMaturityAmount: number | null = null;
@Input() rdInterestEarned: number | null = null;
@Input() rdDaysInYear: number | null = null;
@Input() rdAppliedRate: number | null = null;
@Input() rdIsSeniorCitizen = false;
get rdAppliedInterestRate(): number {
if (this.rdAppliedRate != null) return this.rdAppliedRate;
return this.rdApplicableSlab?.annualInterestRate ?? 0;
}
get rdSeniorCitizenBonus(): number {
if (!this.rdIsSeniorCitizen || this.rdAppliedRate == null) return 0;
const normalRate = this.rdApplicableSlab?.annualInterestRate ?? 0;
return this.rdAppliedRate - normalRate;
}
/** Output the submit action */
@Output() submitEvent = new EventEmitter();
get currencyName(): string {
return this.recurringDepositsAccountProductTemplate?.currency?.name || '—';
}
get decimalPlaces(): string | number {
return this.recurringDepositsAccountProductTemplate?.currency?.decimalPlaces ?? '—';
}
get inMultiplesOf(): string | number {
return this.recurringDepositsAccountProductTemplate?.currency?.inMultiplesOf ?? '—';
}
readonly rdSlabColumns = [
'srNo',
'description',
'fromPeriod',
'toPeriod',
'periodTypeLabel',
'annualInterestRate'
];
/** Charges Displayed Columns */
chargesDisplayedColumns: string[] = [
'name',
'chargeCalculationType',
'amount',
'chargeTimeType',
'date',
'repaymentsEvery'
];
get interestRateChartData(): any[] {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
if (!template) return [];
return (
template.accountChart?.chartSlabs ??
template.activeChart?.chartSlabs ??
template.interestRateCharts?.[0]?.chartSlabs ??
template.interestRateChart?.chartSlabs ??
template.chartSlabs ??
[]
);
}
/** Matched Slab Index for highlighting */
get matchedSlabIndex(): number {
if (!this.rdTenureDays || !this.interestRateChartData) return -1;
// Find index of the applicable slab in the chart data
return this.interestRateChartData.findIndex((slab) => {
const pTypeValue = slab.periodType?.value || 'Days';
const fromDays = this.slabPeriodToDays(slab.fromPeriod ?? 0, pTypeValue);
const toDays = slab.toPeriod != null ? this.slabPeriodToDays(slab.toPeriod, pTypeValue) : Infinity;
return this.rdTenureDays >= fromDays && this.rdTenureDays <= toDays;
});
}
/** Selected Tenure Label for banner */
get selectedTenureLabel(): string {
if (!this.rdTenureDays) return '';
if (this.rdTenureDays >= 365) {
const years = Math.floor(this.rdTenureDays / 365);
const rem = this.rdTenureDays % 365;
return years + (years === 1 ? ' Year' : ' Years') + (rem > 0 ? ` ${rem} Days` : '');
}
if (this.rdTenureDays >= 30) {
const months = Math.floor(this.rdTenureDays / 30);
const rem = this.rdTenureDays % 30;
return months + (months === 1 ? ' Month' : ' Months') + (rem > 0 ? ` ${rem} Days` : '');
}
return this.rdTenureDays + ' Days';
}
private slabPeriodToDays(period: number, periodTypeValue: string): number {
const p = (periodTypeValue || '').toLowerCase();
if (p.includes('day')) return period;
if (p.includes('week')) return period * 7;
if (p.includes('month')) return period * 30;
if (p.includes('year')) return period * 365;
return period;
}
/** Columns to be displayed in interest rate chart table. */
chartSlabsDisplayedColumns: any[] = [
'period',
'amountRange',
'interest',
'description',
'actions'
];
/** Columns to be displayed in incentives sub-table. */
incentivesDisplayedColumns: string[] = [
'entityType',
'attributeName',
'conditionType',
'attributeValue',
'incentiveType',
'amount'
];
/** Additional Column to disblac incentives table */
chartSlabsIncentivesDisplayedColumns: string[] = ['incentives'];
/** Expand Chart Slab Index used in the view */
expandChartSlabIndex: number;
constructor() {}
ngOnChanges() {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
if (template) {
// Logic for metadata getters is now handled by the dynamic template reference
}
}
// ── Header Getters ──────────────────────────────────────────────────────
get chartName(): string {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
return (
template?.accountChart?.name ||
template?.activeChart?.name ||
template?.interestRateCharts?.[0]?.name ||
template?.interestRateChart?.name ||
template?.name ||
''
);
}
get chartFromDate(): any {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
return (
template?.accountChart?.fromDate ||
template?.activeChart?.fromDate ||
template?.interestRateCharts?.[0]?.fromDate ||
template?.interestRateChart?.fromDate ||
template?.fromDate
);
}
get chartEndDate(): any {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
return (
template?.accountChart?.endDate ||
template?.activeChart?.endDate ||
template?.interestRateCharts?.[0]?.endDate ||
template?.interestRateChart?.endDate ||
template?.endDate
);
}
get chartDescription(): string {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
return (
template?.accountChart?.description ||
template?.activeChart?.description ||
template?.interestRateCharts?.[0]?.description ||
template?.interestRateChart?.description ||
template?.description ||
''
);
}
get isPrimaryGroupingByAmount(): boolean {
const template = this.recurringDepositsAccountProductTemplate || this.recurringDepositsAccountTemplate;
return !!(
template?.accountChart?.isPrimaryGroupingByAmount ||
template?.activeChart?.isPrimaryGroupingByAmount ||
template?.interestRateCharts?.[0]?.isPrimaryGroupingByAmount ||
template?.interestRateChart?.isPrimaryGroupingByAmount ||
template?.isPrimaryGroupingByAmount
);
}
}