update some logic show option

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nitesh Yadav
2026-04-21 17:38:07 +05:30
co-authored by Claude Sonnet 4.6
parent e212bf7d79
commit e9a9377148
39 changed files with 2215 additions and 287 deletions
@@ -0,0 +1,113 @@
<!--
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/.
-->
<form [formGroup]="savingsAccountSettingsForm">
<div class="sps-section">
<div class="sps-section__header">
<span class="sps-section__badge"><i class="fas fa-balance-scale"></i></span>
<span>Balance &amp; Minimum Balance</span>
</div>
<div class="sps-body">
<div class="sps-layout sps-layout--balance">
<div class="sps-row sps-row--three">
<mat-form-field appearance="outline" class="sps-field sps-field--compact">
<mat-label>{{ 'labels.inputs.Minimum Opening Balance' | translate }}</mat-label>
<input type="number" matInput formControlName="minRequiredOpeningBalance" min="0" step="0.01" />
</mat-form-field>
<div class="sps-toggle sps-toggle--inline">
<mat-checkbox labelPosition="before" formControlName="enforceMinRequiredBalance">
<span>Enforce Minimum Balance</span>
</mat-checkbox>
</div>
<mat-form-field appearance="outline" class="sps-field sps-field--compact">
<mat-label>Minimum Balance (&#8377;)</mat-label>
<input type="number" matInput formControlName="minRequiredBalance" min="0" step="0.01" />
<mat-hint>Penal charge applies on breach</mat-hint>
</mat-form-field>
</div>
<div class="sps-row sps-row--two">
<mat-form-field appearance="outline" class="sps-field sps-field--compact">
<mat-label>Balance Frequency</mat-label>
<mat-select formControlName="balanceFrequency">
@for (freq of periodFrequencyData; track freq.value) {
<mat-option [value]="freq.value">{{ freq.value }}</mat-option>
}
</mat-select>
</mat-form-field>
<div class="sps-toggle sps-toggle--inline sps-toggle--right">
<mat-checkbox labelPosition="before" formControlName="withdrawalFeeForTransfers">
<span>{{ 'labels.inputs.Apply Withdrawal Fee for Transfers' | translate }}</span>
</mat-checkbox>
</div>
</div>
</div>
</div>
</div>
<div class="sps-section">
<div class="sps-section__header">
<span class="sps-section__badge"><i class="fas fa-lock"></i></span>
<span>Lock-in Period</span>
</div>
<div class="sps-body">
<div class="sps-lockin-row">
<span>Enable Lock-in Period</span>
<mat-checkbox formControlName="enableLockinPeriod"></mat-checkbox>
</div>
@if (savingsAccountSettingsForm.value.enableLockinPeriod) {
<div class="sps-lockin-fields">
<mat-form-field appearance="outline" class="sps-field sps-field--compact">
<mat-label>{{ 'labels.inputs.Frequency' | translate }}*</mat-label>
<input type="number" matInput formControlName="lockinPeriodFrequency" min="1" step="1" />
</mat-form-field>
<mat-form-field appearance="outline" class="sps-field sps-field--compact">
<mat-label>{{ 'labels.inputs.Type' | translate }}*</mat-label>
<mat-select formControlName="lockinPeriodFrequencyType">
@for (type of lockinPeriodFrequencyTypeData; track type) {
<mat-option [value]="type.id">{{ type.value | translateKey: 'catalogs' }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
}
</div>
</div>
<div class="sps-section">
<div class="sps-section__header">
<span class="sps-section__badge"><i class="fas fa-cog"></i></span>
<span>Additional Rules</span>
</div>
<div class="sps-body">
<div class="sps-layout sps-layout--additional">
<div class="sps-toggle sps-toggle--full">
<mat-checkbox formControlName="accountClosedZeroBalanceInDayClosing">
<span>Account Closed with Zero balance in Day Closing</span>
</mat-checkbox>
</div>
@if (savingsAccountProductTemplate?.minBalanceForInterestCalculation != null) {
<mat-form-field appearance="outline" class="sps-field sps-field--compact">
<mat-label>{{ 'labels.inputs.Balance Required for Interest Calculation' | translate }}</mat-label>
<input
matInput
[value]="savingsAccountProductTemplate.minBalanceForInterestCalculation | formatNumber"
readonly
/>
</mat-form-field>
}
</div>
</div>
</div>
</form>
@@ -0,0 +1,169 @@
/**
* 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/.
*/
$accent: #0ea5e9;
$border: #e2e8f0;
$gray-50: #f8f9fa;
$gray-200: #e8eaed;
$gray-900: #202124;
.sps-section {
border: 1px solid $border;
border-radius: 10px;
overflow: hidden;
background: #fff;
& + & {
margin-top: 16px;
}
&__header {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 24px;
background: $gray-50;
border-bottom: 1px solid $gray-200;
i {
font-size: 14px;
color: $accent;
}
span {
font-size: 14px;
font-weight: 600;
color: $gray-900;
}
}
}
.sps-section__badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 6px;
background: #eff6ff;
font-size: 14px;
}
.sps-body {
background: #fff;
padding: 18px 24px 24px;
}
.sps-field {
width: 100%;
&--full {
grid-column: 1 / -1;
}
&--compact {
width: 100%;
}
}
.sps-layout {
display: grid;
gap: 16px;
}
.sps-layout--balance {
gap: 22px;
}
.sps-layout--additional {
grid-template-columns: repeat(2, minmax(0, 1fr));
align-items: start;
@media (width <= 1100px) {
grid-template-columns: 1fr;
}
}
.sps-row {
display: grid;
gap: 18px;
align-items: start;
}
.sps-row--three {
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
align-items: center;
.sps-field--compact:first-child {
min-width: 0;
}
.sps-toggle--inline {
align-self: center;
min-height: 56px;
}
}
.sps-row--two {
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
.sps-field--compact {
min-width: 0;
}
}
.sps-toggle {
display: flex;
align-items: center;
min-height: 56px;
mat-checkbox {
font-size: 14px;
color: $gray-900;
}
&--full {
min-height: auto;
margin-bottom: 8px;
}
&--inline {
padding-top: 0;
}
&--right {
justify-content: flex-start;
}
}
.sps-lockin-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid $gray-200;
font-size: 14px;
color: $gray-900;
}
.sps-lockin-row mat-checkbox {
margin-right: 2px;
}
.sps-lockin-fields {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
@media (width <= 640px) {
grid-template-columns: 1fr;
}
}
@@ -0,0 +1,152 @@
/**
* 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, Input, OnInit, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms';
import { MatCheckbox } from '@angular/material/checkbox';
import { FormatNumberPipe } from '../../../pipes/format-number.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@Component({
selector: 'mifosx-savings-account-settings-step',
templateUrl: './savings-account-settings-step.component.html',
styleUrls: ['./savings-account-settings-step.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
MatCheckbox,
FormatNumberPipe
]
})
export class SavingsAccountSettingsStepComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private _savingsAccountProductTemplate: any;
@Input()
set savingsAccountProductTemplate(value: any) {
this._savingsAccountProductTemplate = value;
if (value && this.savingsAccountSettingsForm) {
this.applyTemplate(value);
}
}
get savingsAccountProductTemplate(): any {
return this._savingsAccountProductTemplate;
}
savingsAccountSettingsForm: UntypedFormGroup;
lockinPeriodFrequencyTypeData: any[] = [];
periodFrequencyData: any[] = [
{ value: 'Daily' },
{ value: 'Weekly' },
{ value: 'Monthly' },
{ value: 'Quarterly' },
{ value: 'Half Yearly' },
{ value: 'Yearly' }];
constructor() {
this.createForm();
this.buildDependencies();
}
createForm() {
this.savingsAccountSettingsForm = this.formBuilder.group({
minRequiredOpeningBalance: [''],
withdrawalFeeForTransfers: [false],
enforceMinRequiredBalance: [false],
minRequiredBalance: [''],
balanceFrequency: ['Monthly'],
enableLockinPeriod: [false],
lockinPeriodFrequency: [''],
lockinPeriodFrequencyType: [''],
accountClosedZeroBalanceInDayClosing: [false],
allowOverdraft: [false]
});
}
ngOnInit() {
if (this._savingsAccountProductTemplate) {
this.applyTemplate(this._savingsAccountProductTemplate);
}
}
private applyTemplate(t: any) {
this.lockinPeriodFrequencyTypeData = t.lockinPeriodFrequencyTypeOptions || [];
const hasLockin = !!(t.lockinPeriodFrequency && t.lockinPeriodFrequency > 0);
this.savingsAccountSettingsForm.patchValue({
minRequiredOpeningBalance: t.minRequiredOpeningBalance,
withdrawalFeeForTransfers: t.withdrawalFeeForTransfers || false,
enforceMinRequiredBalance: t.enforceMinRequiredBalance || false,
minRequiredBalance: t.minRequiredBalance,
balanceFrequency: t.balanceFrequency || 'Monthly',
enableLockinPeriod: hasLockin,
lockinPeriodFrequency: hasLockin ? t.lockinPeriodFrequency : '',
lockinPeriodFrequencyType: hasLockin ? t.lockinPeriodFrequencyType?.id || '' : '',
accountClosedZeroBalanceInDayClosing: t.accountClosedZeroBalanceInDayClosing || false,
allowOverdraft: t.allowOverdraft || false
});
if (t.allowOverdraft) {
if (!this.savingsAccountSettingsForm.contains('minOverdraftForInterestCalculation')) {
this.savingsAccountSettingsForm.addControl('minOverdraftForInterestCalculation', new UntypedFormControl(''));
this.savingsAccountSettingsForm.addControl('nominalAnnualInterestRateOverdraft', new UntypedFormControl(''));
this.savingsAccountSettingsForm.addControl('overdraftLimit', new UntypedFormControl(''));
}
this.savingsAccountSettingsForm.patchValue({
minOverdraftForInterestCalculation: t.minOverdraftForInterestCalculation,
nominalAnnualInterestRateOverdraft: t.nominalAnnualInterestRateOverdraft,
overdraftLimit: t.overdraftLimit
});
}
}
buildDependencies() {
this.savingsAccountSettingsForm.get('enableLockinPeriod').valueChanges.subscribe((enabled: boolean) => {
if (enabled) {
this.savingsAccountSettingsForm.get('lockinPeriodFrequency').setValidators([
Validators.required,
Validators.min(1)
]);
this.savingsAccountSettingsForm.get('lockinPeriodFrequencyType').setValidators([Validators.required]);
} else {
this.savingsAccountSettingsForm.get('lockinPeriodFrequency').setValue('');
this.savingsAccountSettingsForm.get('lockinPeriodFrequencyType').setValue('');
this.savingsAccountSettingsForm.get('lockinPeriodFrequency').clearValidators();
this.savingsAccountSettingsForm.get('lockinPeriodFrequencyType').clearValidators();
}
this.savingsAccountSettingsForm.get('lockinPeriodFrequency').updateValueAndValidity();
this.savingsAccountSettingsForm.get('lockinPeriodFrequencyType').updateValueAndValidity();
});
this.savingsAccountSettingsForm.get('allowOverdraft').valueChanges.subscribe((allowed: boolean) => {
if (allowed) {
this.savingsAccountSettingsForm.addControl('minOverdraftForInterestCalculation', new UntypedFormControl(''));
this.savingsAccountSettingsForm.addControl('nominalAnnualInterestRateOverdraft', new UntypedFormControl(''));
this.savingsAccountSettingsForm.addControl('overdraftLimit', new UntypedFormControl(''));
} else {
this.savingsAccountSettingsForm.removeControl('minOverdraftForInterestCalculation');
this.savingsAccountSettingsForm.removeControl('nominalAnnualInterestRateOverdraft');
this.savingsAccountSettingsForm.removeControl('overdraftLimit');
}
});
}
get savingsAccountSettings() {
const value = { ...this.savingsAccountSettingsForm.getRawValue() };
if (!value.enableLockinPeriod) {
value.lockinPeriodFrequency = null;
value.lockinPeriodFrequencyType = null;
}
delete value.enableLockinPeriod;
delete value.balanceFrequency;
delete value.accountClosedZeroBalanceInDayClosing;
return value;
}
}