WEB-573: refactor password preferences UI to card-based layout

- Convert horizontal radio layout to vertical card-based blocks
- Add heading labels (Basic, Standard, Strong) for each policy option
- Position radio buttons and headings on same row with space-between
- Increase padding and spacing for improved visual clarity
- Maintain full-width blocks with consistent vertical stacking
- Preserve all existing text content and functionality
- Add trackBy function to *ngFor for performance optimization
- Use translation keys for password labels instead of hardcoded array
- Map labels based on preference ID for robustness
This commit is contained in:
Anvay
2026-01-15 01:32:18 +05:30
parent 56a965e87d
commit ed1b281127
3 changed files with 80 additions and 15 deletions
@@ -1,6 +1,5 @@
<!-- <!--
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/.
@@ -10,14 +9,25 @@
<mat-card> <mat-card>
<form [formGroup]="passwordPreferencesForm" (ngSubmit)="submit()"> <form [formGroup]="passwordPreferencesForm" (ngSubmit)="submit()">
<mat-card-content> <mat-card-content>
<mat-radio-group class="layout-column gap-10px radio-group-spacing" formControlName="validationPolicyId"> <mat-radio-group class="password-cards-container" formControlName="validationPolicyId">
@for (passwordPreference of passwordPreferencesData; track passwordPreference) { <div
<mat-radio-button [value]="passwordPreference.id"> *ngFor="let passwordPreference of passwordPreferencesData; trackBy: trackByPasswordPreference"
<span class="description-wrap">{{ class="password-card"
passwordPreference.description | translateKey: 'passwordPreferences' [class.selected]="passwordPreferencesForm.get('validationPolicyId')?.value === passwordPreference.id"
}}</span> >
</mat-radio-button> <div class="card-header">
} <div class="card-heading">
{{ getPasswordLabel(passwordPreference) | translate }}
</div>
<mat-radio-button [value]="passwordPreference.id"></mat-radio-button>
</div>
<div class="card-description">
<span class="description-wrap">
{{ passwordPreference.description | translateKey: 'passwordPreferences' }}
</span>
</div>
</div>
</mat-radio-group> </mat-radio-group>
</mat-card-content> </mat-card-content>
@@ -10,14 +10,44 @@
white-space: normal; white-space: normal;
} }
.radio-group-spacing { .password-cards-container {
display: flex; display: flex;
gap: 2rem; flex-direction: column;
flex-direction: row; gap: 1.5rem;
width: 100%;
} }
@media (width <= 768px) { .password-card {
.radio-group-spacing { width: 100%;
flex-direction: column; border: 1px solid rgb(0 0 0 / 12%);
border-radius: 4px;
padding: 1.5rem;
box-sizing: border-box;
&.selected {
border-color: currentcolor;
border-width: 2px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.card-heading {
font-weight: 500;
font-size: 1rem;
}
.card-description {
padding-left: 0;
.description-wrap {
white-space: normal;
display: block;
line-height: 1.5;
}
} }
} }
@@ -81,6 +81,31 @@ export class PasswordPreferencesComponent implements OnInit {
} }
} }
/**
* TrackBy function for ngFor optimization.
* @param index Index of the item.
* @param item Password preference item.
* @returns Unique identifier for the item.
*/
trackByPasswordPreference(index: number, item: any): any {
return item.id || index;
}
/**
* Gets the password preference label based on ID.
* @param preference Password preference object.
* @returns Translation key for the password preference label.
*/
getPasswordLabel(preference: any): string {
// Map based on ID to ensure robustness
const labelMap: { [key: number]: string } = {
1: 'labels.inputs.Basic',
2: 'labels.inputs.Standard',
3: 'labels.inputs.Strong'
};
return labelMap[preference.id] || 'labels.inputs.Unknown';
}
/** /**
* Submits the password preferences form and updates password preferences, * Submits the password preferences form and updates password preferences,
* if successful redirects to organization view. * if successful redirects to organization view.