merging code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nitesh Yadav
2026-04-20 14:26:25 +05:30
co-authored by Claude Sonnet 4.6
322 changed files with 28779 additions and 4976 deletions
@@ -12,7 +12,12 @@
<h2>{{ 'labels.heading.Create Client' | translate }}</h2>
</div>
<mat-tab-group class="client-tabs" animationDuration="200ms" [preserveContent]="true" [(selectedIndex)]="selectedTabIndex">
<mat-tab-group
class="client-tabs"
animationDuration="200ms"
[preserveContent]="true"
[(selectedIndex)]="selectedTabIndex"
>
<!-- Tab 1: General Details -->
<mat-tab>
<ng-template mat-tab-label>
@@ -62,7 +67,8 @@
</div>
}
<div class="tab-section">
<mifosx-client-kyc-step #clientKyc
<mifosx-client-kyc-step
#clientKyc
[isNonIndividual]="legalFormType === 2"
[clientId]="createdClientId"
[constitutionMeta]="clientGeneralStep?.selectedConstitution"
@@ -127,13 +133,18 @@
<mat-icon>edit</mat-icon> Edit
</button>
} @else {
<button mat-stroked-button class="tab-mode-btn tab-mode-btn--cancel" (click)="cancelTabEdit(addressTabIdx)">
<button
mat-stroked-button
class="tab-mode-btn tab-mode-btn--cancel"
(click)="cancelTabEdit(addressTabIdx)"
>
<mat-icon>close</mat-icon> Cancel
</button>
}
</div>
}
<mifosx-client-india-address-step #clientIndiaAddress
<mifosx-client-india-address-step
#clientIndiaAddress
[readOnly]="isTabReadOnly(addressTabIdx)"
></mifosx-client-india-address-step>
</div>
@@ -155,13 +166,18 @@
<mat-icon>edit</mat-icon> Edit
</button>
} @else {
<button mat-stroked-button class="tab-mode-btn tab-mode-btn--cancel" (click)="cancelTabEdit(familyTabIdx)">
<button
mat-stroked-button
class="tab-mode-btn tab-mode-btn--cancel"
(click)="cancelTabEdit(familyTabIdx)"
>
<mat-icon>close</mat-icon> Cancel
</button>
}
</div>
}
<mifosx-client-family-members-step #clientFamilyMembers
<mifosx-client-family-members-step
#clientFamilyMembers
[clientTemplate]="clientTemplate"
[clientId]="createdClientId"
[maritalStatusId]="clientGeneralStep?.createClientForm?.get('maritalStatusId')?.value"
@@ -220,9 +236,19 @@
}
@if (selectedTabIndex < totalTabs - 1) {
<div class="save-next-wrapper">
<button mat-raised-button color="primary" class="save-next-btn" (click)="onNext()" [disabled]="savingClient || (selectedTabIndex === 0 && clientGeneralStep?.sanctionsBlocked)">
<button
mat-raised-button
color="primary"
class="save-next-btn"
(click)="onNext()"
[disabled]="savingClient || (selectedTabIndex === 0 && clientGeneralStep?.sanctionsBlocked)"
>
@if (savingClient) {
<mat-progress-spinner diameter="18" mode="indeterminate" class="m-r-10 save-spinner"></mat-progress-spinner>
<mat-progress-spinner
diameter="18"
mode="indeterminate"
class="m-r-10 save-spinner"
></mat-progress-spinner>
Saving...
} @else {
<mat-icon class="m-r-6">save</mat-icon>
@@ -48,11 +48,11 @@
.client-tabs {
background: var(--md-sys-color-surface, #fff);
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
::ng-deep {
.mat-mdc-tab-header {
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
border-bottom: 1px solid rgb(0 0 0 / 8%);
}
.mat-mdc-tab {
@@ -96,11 +96,11 @@
align-items: center;
gap: 8px;
padding: 32px 16px;
color: rgba(0, 0, 0, 0.54);
color: rgb(0 0 0 / 54%);
font-size: 14px;
mat-icon {
color: rgba(0, 0, 0, 0.38);
color: rgb(0 0 0 / 38%);
}
}
@@ -110,7 +110,7 @@
align-items: center;
margin-top: 20px;
padding: 16px 0;
border-top: 1px solid rgba(0, 0, 0, 0.08);
border-top: 1px solid rgb(0 0 0 / 8%);
}
.action-bar-right {
@@ -119,7 +119,7 @@
}
.cancel-btn {
color: rgba(0, 0, 0, 0.6);
color: rgb(0 0 0 / 60%);
}
/* ─── Read-only tab state ─── */
@@ -196,8 +196,9 @@
::ng-deep .mdc-linear-progress__bar-inner {
border-color: #fff !important;
}
::ng-deep .mdc-linear-progress__buffer-bar {
background-color: rgba(255, 255, 255, 0.3) !important;
background-color: rgb(255 255 255 / 30%) !important;
}
}
@@ -222,7 +223,9 @@
flex-shrink: 0;
}
span { flex: 1; }
span {
flex: 1;
}
button {
flex-shrink: 0;
@@ -236,10 +236,14 @@ export class CreateClientComponent {
}
// Upload photo & signature
if (this.clientKycStep?.photographFile) {
this.clientsService.uploadClientProfileImage(clientId, this.clientKycStep.photographFile).subscribe({ error: () => {} });
this.clientsService
.uploadClientProfileImage(clientId, this.clientKycStep.photographFile)
.subscribe({ error: () => {} });
}
if (this.clientKycStep?.signatureFile) {
this.clientsService.uploadClientSignatureImage(clientId, this.clientKycStep.signatureFile).subscribe({ error: () => {} });
this.clientsService
.uploadClientSignatureImage(clientId, this.clientKycStep.signatureFile)
.subscribe({ error: () => {} });
}
return;
}
@@ -368,16 +372,27 @@ export class CreateClientComponent {
* Finalize: upload photo/signature, save KYC, save addresses, then navigate.
*/
private finalizeClient(clientId: string) {
const navigateToClient = () => this.router.navigate(['../', clientId], { relativeTo: this.route });
const navigateToClient = () =>
this.router.navigate(
[
'../',
clientId
],
{ relativeTo: this.route }
);
// Upload photo if selected
if (this.clientKycStep?.photographFile) {
this.clientsService.uploadClientProfileImage(clientId, this.clientKycStep.photographFile).subscribe({ error: () => {} });
this.clientsService
.uploadClientProfileImage(clientId, this.clientKycStep.photographFile)
.subscribe({ error: () => {} });
}
// Upload signature if selected
if (this.clientKycStep?.signatureFile) {
this.clientsService.uploadClientSignatureImage(clientId, this.clientKycStep.signatureFile).subscribe({ error: () => {} });
this.clientsService
.uploadClientSignatureImage(clientId, this.clientKycStep.signatureFile)
.subscribe({ error: () => {} });
}
// Save addresses from India address step
@@ -409,16 +424,36 @@ export class CreateClientComponent {
const addressData = this.clientIndiaAddressStep.addressData;
// Map tab names to Fineract address type names (as defined in address template)
const typeNameMap: Record<string, string[]> = {
permanent: ['Permanent', 'Permanent Address'],
current: ['Residential', 'Current', 'Current / Residential', 'Communication'],
office: ['Office', 'Office / Work', 'Business', 'Work'],
correspondence: ['Correspondence', 'Mailing', 'Postal']
permanent: [
'Permanent',
'Permanent Address'
],
current: [
'Residential',
'Current',
'Current / Residential',
'Communication'
],
office: [
'Office',
'Office / Work',
'Business',
'Work'
],
correspondence: [
'Correspondence',
'Mailing',
'Postal'
]
};
this.clientsService.getClientAddressTemplate().subscribe({
next: (template: any) => {
const typeOptions = template?.addressTypeIdOptions || [];
for (const [tab, addr] of Object.entries(addressData)) {
for (const [
tab,
addr
] of Object.entries(addressData)) {
if (!addr || !(addr as any).addressLine1) continue;
// Find matching address type ID
@@ -448,8 +483,8 @@ export class CreateClientComponent {
// Try to resolve state to stateProvinceId
if ((addr as any).state && template?.stateProvinceIdOptions?.length) {
const stateMatch = template.stateProvinceIdOptions.find((s: any) =>
s.name?.toLowerCase() === (addr as any).state?.toLowerCase()
const stateMatch = template.stateProvinceIdOptions.find(
(s: any) => s.name?.toLowerCase() === (addr as any).state?.toLowerCase()
);
if (stateMatch) payload.stateProvinceId = stateMatch.id;
}
@@ -535,34 +570,98 @@ export class CreateClientComponent {
</div>
</div>
`,
styles: [`
.scd { background: #fff; border-radius: 12px; overflow: hidden; }
.scd-header {
display: flex; align-items: center; gap: 14px;
padding: 20px 24px 16px;
}
.scd-header__icon-wrap {
width: 44px; height: 44px; border-radius: 12px;
background: #eff6ff; display: flex; align-items: center; justify-content: center;
}
.scd-header__icon { color: #1074b9; font-size: 24px; width: 24px; height: 24px; }
.scd-header__title { margin: 0; font-size: 17px; font-weight: 700; color: #0f172a; }
.scd-header__sub { margin: 2px 0 0; font-size: 12px; color: #64748b; }
.scd-body { padding: 0 24px 20px; }
.scd-body p { margin: 0 0 14px; font-size: 14px; color: #374151; line-height: 1.5; }
.scd-info {
display: flex; align-items: flex-start; gap: 8px;
padding: 10px 14px; background: #f0f9ff; border: 1px solid #bae6fd;
border-radius: 8px; font-size: 12px; color: #0c4a6e;
}
.scd-info__icon { font-size: 16px !important; width: 16px !important; height: 16px !important; color: #0284c7; flex-shrink: 0; margin-top: 1px; }
.scd-actions {
display: flex; justify-content: flex-end; gap: 10px;
padding: 14px 24px; border-top: 1px solid #f1f5f9; background: #f8fafc;
}
.scd-cancel, .scd-confirm { display: flex !important; align-items: center; gap: 6px; font-size: 13px !important; height: 38px !important; border-radius: 8px !important; }
.scd-confirm { font-weight: 600 !important; }
`],
imports: [MatIcon, MatDialogClose]
styles: [
`
.scd {
background: #fff;
border-radius: 12px;
overflow: hidden;
}
.scd-header {
display: flex;
align-items: center;
gap: 14px;
padding: 20px 24px 16px;
}
.scd-header__icon-wrap {
width: 44px;
height: 44px;
border-radius: 12px;
background: #eff6ff;
display: flex;
align-items: center;
justify-content: center;
}
.scd-header__icon {
color: #1074b9;
font-size: 24px;
width: 24px;
height: 24px;
}
.scd-header__title {
margin: 0;
font-size: 17px;
font-weight: 700;
color: #0f172a;
}
.scd-header__sub {
margin: 2px 0 0;
font-size: 12px;
color: #64748b;
}
.scd-body {
padding: 0 24px 20px;
}
.scd-body p {
margin: 0 0 14px;
font-size: 14px;
color: #374151;
line-height: 1.5;
}
.scd-info {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 10px 14px;
background: #f0f9ff;
border: 1px solid #bae6fd;
border-radius: 8px;
font-size: 12px;
color: #0c4a6e;
}
.scd-info__icon {
font-size: 16px !important;
width: 16px !important;
height: 16px !important;
color: #0284c7;
flex-shrink: 0;
margin-top: 1px;
}
.scd-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 14px 24px;
border-top: 1px solid #f1f5f9;
background: #f8fafc;
}
.scd-cancel,
.scd-confirm {
display: flex !important;
align-items: center;
gap: 6px;
font-size: 13px !important;
height: 38px !important;
border-radius: 8px !important;
}
.scd-confirm {
font-weight: 600 !important;
}
`
],
imports: [
MatIcon,
MatDialogClose
]
})
export class SaveConfirmDialogComponent {}