diff --git a/src/app/account-transfers/make-account-transfers/make-account-transfers.component.html b/src/app/account-transfers/make-account-transfers/make-account-transfers.component.html index 36856908d..e5462f6c3 100644 --- a/src/app/account-transfers/make-account-transfers/make-account-transfers.component.html +++ b/src/app/account-transfers/make-account-transfers/make-account-transfers.component.html @@ -5,6 +5,7 @@
+ @@ -53,7 +54,7 @@ {{ 'labels.inputs.Phone Number' | translate }} + - - + + + - -
+ +

{{ 'labels.heading.Transfer Details' | translate }}

@@ -180,6 +180,8 @@ formControlName="transferAmount" placeholder="Enter amount" title="Transfer amount" + min="0.01" + step="0.01" /> {{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }} @@ -207,20 +209,135 @@
- - - -
- + + +
+

{{ 'labels.heading.Transfer Details' | translate }}

+ +
+ + {{ 'labels.inputs.Transaction Date' | translate }} + + + + + {{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + + + + {{ 'labels.inputs.Bank' | translate }} + + + + + {{ 'labels.inputs.Client' | translate }} + + + + + {{ 'labels.inputs.Account Type' | translate }} + + + + + {{ 'labels.inputs.Account' | translate }} + + + + + {{ 'labels.inputs.Amount' | translate }} + + + {{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + + {{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.mustBeAtLeast' | translate }} 0.01 + + + + {{ 'errors.validation.msg.savingsproduct.insufficient.balance' | translate: { balance } }} + + + + + {{ 'labels.inputs.Description' | translate }} + + + {{ 'labels.inputs.Transfer Description' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + +
+
+ + + + + + + + + +
diff --git a/src/app/account-transfers/make-account-transfers/make-account-transfers.component.scss b/src/app/account-transfers/make-account-transfers/make-account-transfers.component.scss index 4b619b0d9..a3b5aff57 100644 --- a/src/app/account-transfers/make-account-transfers/make-account-transfers.component.scss +++ b/src/app/account-transfers/make-account-transfers/make-account-transfers.component.scss @@ -4,11 +4,7 @@ padding: 1rem; } -#search-button { - background-color: #1074b9; - color: white; -} - +// Card styling .transfer-card { border-radius: 8px; box-shadow: 0 2px 10px rgb(0 0 0 / 8%); @@ -26,7 +22,8 @@ font-weight: 600; color: #333; margin: 0 0 1rem; - padding-bottom: 0; + padding-bottom: 0.5rem; + border-bottom: 1px solid rgb(0 0 0 / 12%); &.transfer-heading { font-weight: 700; @@ -49,9 +46,7 @@ align-items: center; padding: 0.5rem; background-color: rgb(0 0 0 / 2%); - box-shadow: 0 0.5px 1px rgb(0 0 0 / 10%); - border: 1px solid var(--border-color, #ddd); - border-radius: 8px; + border-radius: 4px; &:hover { background-color: rgb(0 0 0 / 4%); @@ -90,29 +85,55 @@ mat-divider { gap: 1rem; @media (width >= 768px) { - grid-template-columns: repeat(2, 50%); + grid-template-columns: repeat(2, 1fr); /* stylelint-disable-line unit-allowed-list */ + gap: 1.5rem; } } +.form-row { + display: contents; +} + .form-field { width: 100%; + margin-bottom: 0.5rem; + + &:nth-child(odd) { + @media (width >= 768px) { + margin-right: 0.5rem; + } + } + + &:nth-child(even) { + @media (width >= 768px) { + margin-left: 0.5rem; + } + } &.description-field { grid-column: 1 / -1; + + textarea { + min-height: 80px; + resize: vertical; + } } } +::ng-deep .mat-form-field { + width: 100%; +} + // Button styling .action-buttons { display: flex; - justify-content: center; + justify-content: flex-end; gap: 1rem; padding: 1rem 1.5rem; - margin-top: 0; + margin-top: 1rem; @media (width <= 576px) { flex-direction: column; - align-items: center; } button { @@ -120,7 +141,6 @@ mat-divider { @media (width <= 576px) { width: 100%; - max-width: 300px; margin-bottom: 0.5rem; } } @@ -186,16 +206,12 @@ mat-divider { // Dark theme // Lower specificity selectors first .dark-theme { - .info-row { - color: #fff !important; - } - .info-label { - color: rgb(255 255 255 / 70%) !important; + color: rgb(255 255 255 / 70%); } .info-value { - color: rgb(255 255 255 / 87%) !important; + color: rgb(255 255 255 / 87%); } .section-title { @@ -233,18 +249,6 @@ mat-divider { } // Higher specificity selectors -:host-context(.dark-theme) .info-row { - color: #fff !important; -} - -:host-context(.dark-theme) .info-label { - color: rgb(255 255 255 / 70%) !important; -} - -:host-context(.dark-theme) .info-value { - color: rgb(255 255 255 / 87%) !important; -} - :host-context(.dark-theme) .transfer-heading { color: #fff; font-weight: 700; @@ -266,18 +270,6 @@ mat-divider { // Medium specificity selectors body.dark-theme { .container { - .info-row { - color: #fff !important; - } - - .info-label { - color: rgb(255 255 255 / 70%) !important; - } - - .info-value { - color: rgb(255 255 255 / 87%) !important; - } - .section-title { color: #fff; } @@ -320,3 +312,20 @@ body.dark-theme { ::ng-deep mat-form-field.error-warn.mat-form-field-invalid .mat-error { color: #0009 !important; } + +::ng-deep .mat-form-field-flex { + align-items: center; +} + +.transfer-form .form-field { + margin-bottom: 1rem; +} + +.readonly-field { + background-color: rgb(0 0 0 / 2%); + cursor: not-allowed; +} + +::ng-deep .mat-input-element { + font-size: 14px; +} diff --git a/src/app/account-transfers/make-account-transfers/make-account-transfers.component.ts b/src/app/account-transfers/make-account-transfers/make-account-transfers.component.ts index d66a000c6..47411809d 100644 --- a/src/app/account-transfers/make-account-transfers/make-account-transfers.component.ts +++ b/src/app/account-transfers/make-account-transfers/make-account-transfers.component.ts @@ -1,14 +1,12 @@ /** Angular Imports */ -import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { Component, OnInit, AfterViewInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { AbstractControl, - FormGroup, UntypedFormBuilder, UntypedFormGroup, ValidationErrors, Validators, - ReactiveFormsModule, FormsModule } from '@angular/forms'; @@ -21,11 +19,10 @@ import { Dates } from 'app/core/utils/dates'; /** Environment Configuration */ import { environment } from '../../../environments/environment'; import { MatDivider } from '@angular/material/divider'; -import { MatFormField, MatLabel, MatHint, MatSuffix, MatError } from '@angular/material/form-field'; -import { MatOption, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete'; +import { MatFormField, MatLabel, MatHint, MatError } from '@angular/material/form-field'; +import { MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { CdkTextareaAutosize } from '@angular/cdk/text-field'; -import { MakeAccountInterbankTransfersComponent } from '../make-account-interbank-transfers/make-account-interbank-transfers.component'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; /** @@ -43,8 +40,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; MatAutocompleteTrigger, MatAutocomplete, FaIconComponent, - CdkTextareaAutosize, - MakeAccountInterbankTransfersComponent + CdkTextareaAutosize ] }) export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { @@ -56,7 +52,6 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { maxDate = new Date(2100, 0, 1); /** Edit Standing Instructions form. */ makeAccountTransferForm: UntypedFormGroup; - //makeAccountInterbankTransferForm: FormGroup; /** To Office Type Data */ toOfficeTypeData: any; /** To Client Type Data */ @@ -77,6 +72,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { interbank: boolean = false; /** Reference of phoneAccount search */ phoneAccount = ''; + /** Interbank transfer form flag */ interbankTransferForm: boolean = false; balance: number = 0; isLoading: boolean = false; @@ -106,6 +102,8 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { this.setOptions(); }); } + + /** Sets the value from the URL */ /** Sets the value from the URL */ setParams() { this.accountType = this.route.snapshot.queryParams['accountType']; @@ -119,7 +117,13 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { this.accountTypeId = '2'; this.id = this.route.snapshot.queryParams['savingsId']; this.interbank = this.route.snapshot.queryParams['interbank'] === 'true'; - this.balance = this.router.getCurrentNavigation().extras.state.balance; + const navigationBalance = this.router.getCurrentNavigation()?.extras?.state?.balance; + const templateBalance = + this.accountTransferTemplateData?.fromAccount?.availableBalance ?? + this.accountTransferTemplateData?.fromAccount?.summary?.accountBalance ?? + this.accountTransferTemplateData?.fromAccount?.balance ?? + 0; + this.balance = typeof navigationBalance === 'number' ? navigationBalance : templateBalance; break; default: this.accountTypeId = '0'; @@ -133,9 +137,50 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { this.maxDate = this.settingsService.businessDate; if (!this.interbank) { this.createMakeAccountTransferForm(); + } else { + this.createEmptyInterbankForm(); } } + /** + * Crea un formulario vacĂ­o para interbank mientras se carga + */ + createEmptyInterbankForm() { + this.makeAccountTransferForm = this.formBuilder.group({ + toBank: [ + '', + Validators.required + ], + toClientId: [ + '', + Validators.required + ], + toAccountType: [ + '', + Validators.required + ], + toAccountId: [ + '', + Validators.required + ], + transferAmount: [ + 0, + [ + Validators.required, + Validators.min(0.01), + this.amountExceedsBalanceValidator.bind(this)] + ], + transferDate: [ + this.settingsService.businessDate, + Validators.required + ], + transferDescription: [ + '', + Validators.required + ] + }); + } + /** * Creates the standing instruction form. */ @@ -176,25 +221,34 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { } createMakeAccountInterbankTransferForm(account: any) { - /* --> */ this.makeAccountTransferForm = this.formBuilder.group({ + if (!account) { + console.error('Account data is undefined'); + this.isLoading = false; + return; + } + + const defaultAmount = + this.accountTransferTemplateData?.transferAmount > 0 ? this.accountTransferTemplateData.transferAmount : 1; + + this.makeAccountTransferForm = this.formBuilder.group({ toBank: [ - { value: account.sourceFspId, disabled: true }, + account.destinationFspId || '', Validators.required ], toClientId: [ - { value: account.firsName + ' ' + account.lastName, disabled: true }, + (account.firstName || account.firsName || '') + ' ' + (account.lastName || ''), Validators.required ], toAccountType: [ - { value: 'Saving Account', disabled: true }, + 'Saving Account', Validators.required ], toAccountId: [ - { value: account.partyId, disabled: true }, + account.partyId || '', Validators.required ], transferAmount: [ - this.accountTransferTemplateData.transferAmount, + defaultAmount, [ Validators.required, Validators.min(0.01), @@ -205,7 +259,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { Validators.required ], transferDescription: [ - '', + 'Transferencia interbancaria', Validators.required ] }); @@ -243,7 +297,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { delete dataObj.transferAmount; delete dataObj.transferDate; delete dataObj.transferDescription; - if (dataObj.toClientId) { + if (dataObj.toClientId && typeof dataObj.toClientId === 'object') { dataObj.toClientId = dataObj.toClientId.id; } const propNames = Object.getOwnPropertyNames(dataObj); @@ -260,9 +314,9 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { * Subscribes to Clients search filter: */ ngAfterViewInit() { - if (!this.interbank) { - this.makeAccountTransferForm.controls.toClientId.valueChanges.subscribe((value: string) => { - if (value.length >= 2) { + if (!this.interbank && this.makeAccountTransferForm) { + this.makeAccountTransferForm.controls.toClientId.valueChanges.subscribe((value: any) => { + if (typeof value === 'string' && value.length >= 2) { this.clientsService.getFilteredClients('displayName', 'ASC', true, value).subscribe((data: any) => { this.clientsData = data.pageItems; }); @@ -292,17 +346,26 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { this.isLoading = true; const dateFormat = this.settingsService.dateFormat; const locale = this.settingsService.language.code; + + let toClientIdValue: any; + if (typeof this.makeAccountTransferForm.controls.toClientId.value === 'object') { + toClientIdValue = this.makeAccountTransferForm.controls.toClientId.value.id; + } else { + toClientIdValue = this.makeAccountTransferForm.controls.toClientId.value; + } + const makeAccountTransferData = { ...this.makeAccountTransferForm.value, transferDate: this.dateUtils.formatDate(this.makeAccountTransferForm.value.transferDate, dateFormat), dateFormat, locale, - toClientId: this.makeAccountTransferForm.controls.toClientId.value.id, + toClientId: toClientIdValue, fromAccountId: this.id, fromAccountType: this.accountTypeId, fromClientId: this.accountTransferTemplateData.fromClient.id, fromOfficeId: this.accountTransferTemplateData.fromClient.officeId }; + this.accountTransfersService.createAccountTransfer(makeAccountTransferData).subscribe(() => { this.isLoading = false; this.router.navigate(['../../transactions'], { relativeTo: this.route }); @@ -311,12 +374,19 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { makeInterbankTransfer() { this.isLoading = true; + + if (!this.makeAccountTransferForm.valid) { + console.error('Interbank form is not valid'); + this.isLoading = false; + return; + } + const payload = { homeTransactionId: crypto.randomUUID(), from: { fspId: environment.fineractPlatformTenantId, idType: 'MSISDN', - idValue: this.accountTransferTemplateData.fromAccount.externalId.trim() + idValue: this.accountTransferTemplateData.fromAccount.externalId?.trim() || '' }, to: { fspId: this.makeAccountTransferForm.controls.toBank.value, @@ -336,6 +406,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { }, note: this.makeAccountTransferForm.controls.transferDescription.value }; + this.accountTransfersService.sendInterbankTransfer(JSON.stringify(payload)).subscribe( (trnsfr) => { if (trnsfr.systemMessage) { @@ -344,12 +415,17 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { } }, (error) => { + console.error('Interbank transfer error:', error); this.isLoading = false; } ); } searchAccountByNumber() { + if (!this.phoneAccount || this.phoneAccount.length !== 10) { + return; + } + this.isLoading = true; this.accountTransfersService .getAccountByNumber(this.phoneAccount, this.accountTransferTemplateData.currency.code) @@ -359,6 +435,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit { this.createMakeAccountInterbankTransferForm(acc); }, (error) => { + console.error('searching account error:', error); this.isLoading = false; } );