| import { LoanSelectComponent } from './loan-select/loan-select.component'; | import { LoanSelectComponent } from './loan-select/loan-select.component'; | ||||
| import {PopupModule} from '@progress/kendo-angular-popup'; | import {PopupModule} from '@progress/kendo-angular-popup'; | ||||
| import { LoansAllComponent } from './loans-all/loans-all.component'; | import { LoansAllComponent } from './loans-all/loans-all.component'; | ||||
| import {FunderNameService} from './service/funder.name.service'; | |||||
| WebSocketService, | WebSocketService, | ||||
| LoanSummaryService, | LoanSummaryService, | ||||
| LoanSingleService, | LoanSingleService, | ||||
| FunderNameService, | |||||
| { | { | ||||
| provide: HTTP_INTERCEPTORS, | provide: HTTP_INTERCEPTORS, | ||||
| useClass: AuthHttpInterceptor, | useClass: AuthHttpInterceptor, |
| <span class="badge badge-info">{{MaxSelect}}</span> | <span class="badge badge-info">{{MaxSelect}}</span> | ||||
| </div> | </div> | ||||
| <button *ngIf="EnableSelectButton" kendoButton [primary]=true | <button *ngIf="EnableSelectButton" kendoButton [primary]=true | ||||
| class="select-loan" icon="close-circle" style="float:right;" | |||||
| class="select-loan" icon="save" style="float:right;" | |||||
| (click)="onFinishSelection()" | (click)="onFinishSelection()" | ||||
| > | |||||
| Finish Selection</button> | |||||
| >{{FinishButtonText}}</button> | |||||
| </ng-template> | </ng-template> | ||||
| .fullheight_grid { | |||||
| kendo-grid.fullheight_grid { | |||||
| height: 100% !important; | height: 100% !important; | ||||
| } | |||||
| .k-grid td:first-child{ | |||||
| vertical-align: top; | |||||
| } | |||||
| .k-grid td.topAlign{ | |||||
| vertical-align: top; | |||||
| } | |||||
| .k-grid td:first-child{ | |||||
| vertical-align: top; | |||||
| } | |||||
| .k-grid td.topAlign{ | |||||
| vertical-align: top; | |||||
| } | |||||
| .k-grid td.alignStatus{ | |||||
| vertical-align: top; | |||||
| text-align: left; | |||||
| } | |||||
| .k-grid td.alignStatus{ | |||||
| vertical-align: top; | |||||
| text-align: left; | |||||
| } | |||||
| .k-grid-header .k-header.colGroupPeople, | |||||
| .k-grid-header .k-header.colClient, | |||||
| .k-grid-header .k-header.colBroker, | |||||
| .k-grid-header .k-header.colOtherRewarder | |||||
| { | |||||
| text-align:center; | |||||
| } | |||||
| div.selected-loans{ | |||||
| position: relative; | |||||
| padding-right:200px; | |||||
| width: calc(100% - 150px); | |||||
| min-height: 60px; | |||||
| overflow: auto hidden; | |||||
| app-loan-card{ | |||||
| display: block; | |||||
| .k-grid-header .k-header.colGroupLoanDetails, | |||||
| .k-grid-header .k-header.colGroupLenderDetails, | |||||
| .k-grid-header .k-header.colGroupIncomeDistribution{ | |||||
| border-left: 5px solid #ffeabe !important; | |||||
| } | } | ||||
| } | |||||
| div.selection-percentage{ | |||||
| float:right; | |||||
| position:absolute; | |||||
| right: 10px; | |||||
| bottom: 1px; | |||||
| } | |||||
| div.selected-loans{ | |||||
| position: relative; | |||||
| padding-right:200px; | |||||
| width: calc(100% - 150px); | |||||
| min-height: 60px; | |||||
| overflow: auto hidden; | |||||
| app-loan-card{ | |||||
| display: block; | |||||
| } | |||||
| } | |||||
| div.selection-percentage{ | |||||
| float:right; | |||||
| position:absolute; | |||||
| right: 10px; | |||||
| bottom: 1px; | |||||
| } | |||||
| button.select-loan{ | |||||
| position: absolute; | |||||
| right: 10px; | |||||
| top: 10px; | |||||
| } | |||||
| .customer-photo{ | |||||
| display: inline-block; | |||||
| width: 32px; | |||||
| height: 32px; | |||||
| border-radius: 50%; | |||||
| background-size: 32px 35px; | |||||
| background-position: center center; | |||||
| vertical-align: middle; | |||||
| line-height: 32px; | |||||
| box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2); | |||||
| margin-left: 5px; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| button.select-loan{ | |||||
| position: absolute; | |||||
| right: 10px; | |||||
| top: 10px; | |||||
| } | |||||
| .customer-name { | |||||
| display: inline-block; | |||||
| vertical-align: middle; | |||||
| line-height: 32px; | |||||
| padding-left: 10px; | |||||
| } | |||||
| .customer-photo{ | |||||
| display: inline-block; | |||||
| width: 32px; | |||||
| height: 32px; | |||||
| border-radius: 50%; | |||||
| background-size: 32px 35px; | |||||
| background-position: center center; | |||||
| vertical-align: middle; | |||||
| line-height: 32px; | |||||
| box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2); | |||||
| margin-left: 5px; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .k-grid-header .k-header.colGroupPeople, | |||||
| .k-grid-header .k-header.colClient, | |||||
| .k-grid-header .k-header.colBroker, | |||||
| .k-grid-header .k-header.colOtherRewarder | |||||
| { | |||||
| text-align:center; | |||||
| } | |||||
| .customer-name { | |||||
| display: inline-block; | |||||
| vertical-align: middle; | |||||
| line-height: 32px; | |||||
| padding-left: 10px; | |||||
| } | |||||
| .k-grid-header .k-header.colGroupLoanDetails, | |||||
| .k-grid-header .k-header.colGroupLenderDetails, | |||||
| .k-grid-header .k-header.colGroupIncomeDistribution{ | |||||
| border-left: 5px solid #ffeabe !important; | |||||
| } | |||||
| .colRating, .colAmount, .colPayOut{ | |||||
| border-left: 5px solid #ffeabe !important; | |||||
| } | |||||
| .colRating, .colAmount, .colPayOut{ | |||||
| border-left: 5px solid #ffeabe !important; | |||||
| } | |||||
| .colTrail{ | |||||
| font-width: 300; | |||||
| color: green ; | |||||
| //border-left: 2px solid green !important; | |||||
| //border-right: 2px solid green !important; | |||||
| border-bottom: 2px solid green !important; | |||||
| } | |||||
| .colTrail{ | |||||
| font-width: 300; | |||||
| color: green ; | |||||
| //border-left: 2px solid green !important; | |||||
| //border-right: 2px solid green !important; | |||||
| border-bottom: 2px solid green !important; | |||||
| } | |||||
| .k-grid-header .k-header.colIncomeDistribution, | |||||
| .k-grid-header .k-header.colGroupLoanDetails{ | |||||
| background-color: #ffeabe; | |||||
| } | |||||
| .k-grid-header .k-header.colIncomeDistribution, | |||||
| .k-grid-header .k-header.colGroupLoanDetails{ | |||||
| background-color: #ffeabe; | |||||
| } | |||||
| .red { | |||||
| color: #d9534f; | |||||
| } | |||||
| .red { | |||||
| color: #d9534f; | |||||
| } | |||||
| .text-bold { | |||||
| font-weight: 600; | |||||
| .text-bold { | |||||
| font-weight: 600; | |||||
| } | |||||
| } | } | ||||
| selector: 'app-list-all-loans', | selector: 'app-list-all-loans', | ||||
| templateUrl: './list-all-loans.component.html', | templateUrl: './list-all-loans.component.html', | ||||
| styleUrls: ['./list-all-loans.component.scss'], | styleUrls: ['./list-all-loans.component.scss'], | ||||
| encapsulation: ViewEncapsulation.None, | |||||
| encapsulation: ViewEncapsulation.Emulated, | |||||
| animations: [ | animations: [ | ||||
| trigger('fadeIn', [ | trigger('fadeIn', [ | ||||
| transition(':enter', [ | transition(':enter', [ | ||||
| public pageSize = 10; | public pageSize = 10; | ||||
| public skip = 0; | public skip = 0; | ||||
| @Output() LoanSelected: EventEmitter<LoanModel[]|LoanModel> = new EventEmitter<LoanModel[]|LoanModel>(); | @Output() LoanSelected: EventEmitter<LoanModel[]|LoanModel> = new EventEmitter<LoanModel[]|LoanModel>(); | ||||
| @Output() Cancelled: EventEmitter<LoanModel[]|LoanModel> = new EventEmitter<LoanModel[]|LoanModel>(); | |||||
| @Output() LoanClicked: EventEmitter<LoanModel> = new EventEmitter<LoanModel>(); | @Output() LoanClicked: EventEmitter<LoanModel> = new EventEmitter<LoanModel>(); | ||||
| @Input() EnableExportExcel = false; | @Input() EnableExportExcel = false; | ||||
| @Input() EnableExportPdf = false; | @Input() EnableExportPdf = false; | ||||
| @Input() EnableSelectButton = false; | @Input() EnableSelectButton = false; | ||||
| @Input() FinishButtonText = 'Finish Select'; | |||||
| @Input() MaxSelect = 1; | @Input() MaxSelect = 1; | ||||
| @Input() Preselect: LoanModel[] = []; | @Input() Preselect: LoanModel[] = []; | ||||
| public SelectedLoans: LoanModel[] = []; | public SelectedLoans: LoanModel[] = []; | ||||
| this.LoanSelected.emit(this.SelectedLoans); | this.LoanSelected.emit(this.SelectedLoans); | ||||
| } | } | ||||
| console.log('loan selected', this); | |||||
| this.notifyUser('ended'); | |||||
| this.notifyUser('try to save'); | |||||
| } | |||||
| public onCancelSelection(): void{ | |||||
| if ( this.MaxSelect === 1 ){ | |||||
| this.Cancelled.emit(this.SelectedLoans[0]); | |||||
| }else{ | |||||
| this.Cancelled.emit(this.SelectedLoans); | |||||
| } | |||||
| this.notifyUser('cancel saving'); | |||||
| } | } | ||||
| public RemoveFromSelection(l: LoanModel): void{ | public RemoveFromSelection(l: LoanModel): void{ |
| <div class="card loan" (click)="onClick()" *ngIf="Loan!==undefined"> | <div class="card loan" (click)="onClick()" *ngIf="Loan!==undefined"> | ||||
| <span class="badge badge-success">{{Loan.Item}}</span> | <span class="badge badge-success">{{Loan.Item}}</span> | ||||
| <span> Amount: {{Loan.Amount | currency }}</span> | <span> Amount: {{Loan.Amount | currency }}</span> | ||||
| <span> Settlement: {{Loan.Settlement | date:'yyyy-mm-dd' }}</span> | |||||
| <span> Settlement: {{Loan.Settlement | date:'yyyy-MM-dd' }}</span> | |||||
| <span *ngIf="ShowCloseButton" class="k-icon k-i-close-circle close" (click)="onClose()" size="large"></span> | <span *ngIf="ShowCloseButton" class="k-icon k-i-close-circle close" (click)="onClose()" size="large"></span> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <kendo-popup [offset]="Offset" (anchorViewportLeave)="showPopup = false" *ngIf="showPopup"> | <kendo-popup [offset]="Offset" (anchorViewportLeave)="showPopup = false" *ngIf="showPopup"> | ||||
| <button kendoButton look="flat" | |||||
| class="close-popup" icon="close-circle" style="float:right;" | |||||
| (click)="onToggle()" | |||||
| ></button> | |||||
| <div class='popup-content'> | <div class='popup-content'> | ||||
| <app-list-all-loans #list | <app-list-all-loans #list | ||||
| (LoanSelected)="onLoanSelected($event)" | |||||
| [EnableSelectButton]="true" | [EnableSelectButton]="true" | ||||
| [SingleSelection]="true" | [SingleSelection]="true" | ||||
| [MaxSelect]="Max" | [MaxSelect]="Max" | ||||
| [Preselect]="[Loan]" | [Preselect]="[Loan]" | ||||
| [FinishButtonText]="FinishButtonText" | |||||
| (LoanClicked)="onClickLoan($event)" | |||||
| (LoanSelected)="onLoanSelected($event)" | |||||
| > | > | ||||
| </app-list-all-loans> | </app-list-all-loans> | ||||
| </div> | </div> |
| z-index: 1; | z-index: 1; | ||||
| } | } | ||||
| } | } | ||||
| button.close-popup{ | |||||
| float: right; | |||||
| position: absolute; | |||||
| right: 0px; | |||||
| border-radius: 100%; | |||||
| z-index: 1; | |||||
| } |
| @Output() valueChange: EventEmitter<LoanModel> = new EventEmitter<LoanModel>(); | @Output() valueChange: EventEmitter<LoanModel> = new EventEmitter<LoanModel>(); | ||||
| public Loan: LoanModel; // for multiple selection ,it has to be array; we don't support it now. | public Loan: LoanModel; // for multiple selection ,it has to be array; we don't support it now. | ||||
| public FinishButtonText = 'Save'; | |||||
| // popup | // popup | ||||
| public showPopup = false; | public showPopup = false; | ||||
| public Offset = { left: 10, top: 48 }; | public Offset = { left: 10, top: 48 }; | ||||
| if (!this.touched) { | if (!this.touched) { | ||||
| this.onTouched(); | this.onTouched(); | ||||
| this.touched = true; | this.touched = true; | ||||
| this.FinishButtonText = 'Save & Close'; | |||||
| } | } | ||||
| } | } | ||||
| onLoanSelected(loan: LoanModel): void { | onLoanSelected(loan: LoanModel): void { | ||||
| if (this.Loan.Id !== loan.Id){ | |||||
| if (loan !== undefined && this.Loan !== undefined && this.Loan.Id !== loan.Id){ | |||||
| this.valueChange.emit(loan); | this.valueChange.emit(loan); | ||||
| this.onChange(loan); | this.onChange(loan); | ||||
| this.Loan = loan; | this.Loan = loan; | ||||
| } | } | ||||
| this.Loan = loan; | |||||
| if (loan === undefined || loan == null ){ | |||||
| this.Loan = new LoanModel({}); | |||||
| }else{ | |||||
| this.Loan = loan; | |||||
| } | |||||
| this.markAsTouched(); | this.markAsTouched(); | ||||
| this.onTouched(); | this.onTouched(); | ||||
| this.showPopup = false; | this.showPopup = false; | ||||
| } | } | ||||
| onClickLoan(loan: LoanModel): void { | |||||
| this.markAsTouched(); | |||||
| } | |||||
| public onToggle(): void { | public onToggle(): void { | ||||
| this.showPopup = !this.showPopup; | this.showPopup = !this.showPopup; |
| </ng-template> | </ng-template> | ||||
| </kendo-grid-column> | </kendo-grid-column> | ||||
| <kendo-grid-column field="Lender" title="Lender" width="150" editor="string"> | |||||
| <kendo-grid-column field="Lender" title="Lender" width="150" > | |||||
| <ng-template kendoGridEditTemplate let-dataItem> | |||||
| <kendo-combobox | |||||
| [formControl]="incomeFormGroup.get('Lender')" | |||||
| [data]="funderListView | async" | |||||
| [loading]="funderListService.loading"> | |||||
| </kendo-combobox> | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="LoanNumber" title="Lender Loan Id" width="150" editor="string"> | |||||
| </kendo-grid-column> | </kendo-grid-column> | ||||
| <kendo-grid-column field="IncomeAmount" title="Income" width="150" format="{0:c}" editor="numeric"> | <kendo-grid-column field="IncomeAmount" title="Income" width="150" format="{0:c}" editor="numeric"> | ||||
| </ng-template> | </ng-template> | ||||
| <ng-template kendoGridEditTemplate let-dataItem> | <ng-template kendoGridEditTemplate let-dataItem> | ||||
| <app-loan-select [formControl]="incomeFormGroup.get('Loan')" (valueChange)="onLoanChange($event)" | <app-loan-select [formControl]="incomeFormGroup.get('Loan')" (valueChange)="onLoanChange($event)" | ||||
| [readOnly]="this.filterLoan !== undefined && this.filterLoan.Id !==''" | |||||
| [Max]="1" [readOnly]="this.filterLoan !== undefined && this.filterLoan.Id !==''" | |||||
| ></app-loan-select> | ></app-loan-select> | ||||
| </ng-template> | </ng-template> | ||||
| </kendo-grid-column> | </kendo-grid-column> |
| import {LoanModel} from '../models/loan.model'; | import {LoanModel} from '../models/loan.model'; | ||||
| import {LoanSingleService} from '../service/loan.single.service'; | import {LoanSingleService} from '../service/loan.single.service'; | ||||
| import {PayInModelEx} from '../models/pay-in-ex.model'; | import {PayInModelEx} from '../models/pay-in-ex.model'; | ||||
| import {Observable} from 'rxjs'; | |||||
| import {FunderNameService} from '../service/funder.name.service'; | |||||
| }; | }; | ||||
| public loading = false; | public loading = false; | ||||
| public funderListView: Observable<string[]>; | |||||
| private debouncedLoadFilteredData = () => {}; | private debouncedLoadFilteredData = () => {}; | ||||
| constructor(private pis: PayInService, private lss: LoanSingleService, private router: Router) { } | |||||
| constructor(private pis: PayInService, | |||||
| private lss: LoanSingleService, | |||||
| private router: Router, | |||||
| private funderListService: FunderNameService) { | |||||
| this.funderListView = this.funderListService; | |||||
| this.funderListService.query(); | |||||
| } | |||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| this.debouncedLoadFilteredData = debounce(this.loadFilteredData, 500); | this.debouncedLoadFilteredData = debounce(this.loadFilteredData, 500); | ||||
| Id: new FormControl({value: dataItem.Id, disabled: true}, Validators.required), | Id: new FormControl({value: dataItem.Id, disabled: true}, Validators.required), | ||||
| Lender: new FormControl({value: dataItem.Lender, disabled: Loan.Id !== '' }, Validators.required), | Lender: new FormControl({value: dataItem.Lender, disabled: Loan.Id !== '' }, Validators.required), | ||||
| Amount: new FormControl(dataItem.Amount), | Amount: new FormControl(dataItem.Amount), | ||||
| LoanNumber: new FormControl(dataItem.LoanNumber, Validators.required), | |||||
| LoanNumber: new FormControl({value: dataItem.LoanNumber, disabled: Loan.Id !== ''}, Validators.required), | |||||
| IncomeAmount: new FormControl(dataItem.IncomeAmount, Validators.required), | IncomeAmount: new FormControl(dataItem.IncomeAmount, Validators.required), | ||||
| IncomeType: new FormControl(dataItem.IncomeType, Validators.required), | IncomeType: new FormControl(dataItem.IncomeType, Validators.required), | ||||
| Ts: new FormControl(dataItem.Ts, Validators.required), | Ts: new FormControl(dataItem.Ts, Validators.required), | ||||
| pi.Balance = v.Balance; | pi.Balance = v.Balance; | ||||
| pi.Lender = loan.Id === '' ? v.Lender : loan.Lender; | pi.Lender = loan.Id === '' ? v.Lender : loan.Lender; | ||||
| pi.LoanId = loan.Id; | pi.LoanId = loan.Id; | ||||
| pi.LoanNumber = loan.LenderLoanNumber; | |||||
| pi.LoanNumber = loan.Id === '' ? v.LoanNumber : loan.LenderLoanNumber; | |||||
| pi.OffsetBalance = v.OffsetBalance; | pi.OffsetBalance = v.OffsetBalance; | ||||
| pi.Settlement = loan.Settlement; | pi.Settlement = loan.Settlement; | ||||
| pi.IncomeAmount = v.IncomeAmount; | pi.IncomeAmount = v.IncomeAmount; | ||||
| if ( loan.Id !== '' ) { | if ( loan.Id !== '' ) { | ||||
| this.incomeFormGroup.get('Lender').setValue(loan.Lender); | this.incomeFormGroup.get('Lender').setValue(loan.Lender); | ||||
| this.incomeFormGroup.get('Lender').disable({onlySelf: true, emitEvent: false}); | this.incomeFormGroup.get('Lender').disable({onlySelf: true, emitEvent: false}); | ||||
| this.incomeFormGroup.get('LoanNumber').setValue(loan.LenderLoanNumber); | |||||
| this.incomeFormGroup.get('LoanNumber').disable({onlySelf: true, emitEvent: false}); | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| public getUrl(key: string): string{ | public getUrl(key: string): string{ | ||||
| const s = this.apiUrl + key; | |||||
| const kvPair: {key: string, value: string}[] = [ | |||||
| {key: 'login', value: this.apiUrl + 'login'}, | |||||
| {key: 'logout', value: this.apiUrl + 'logout'} | |||||
| ]; | |||||
| kvPair.forEach( item => { | |||||
| if ( item.key === key) { | |||||
| return item.value; | |||||
| } | |||||
| }); | |||||
| // not found if arrive here | |||||
| return s; | |||||
| return this.config.getUrl(key); | |||||
| // const s = this.apiUrl + key; | |||||
| // const kvPair: {key: string, value: string}[] = [ | |||||
| // {key: 'login', value: this.apiUrl + 'login'}, | |||||
| // {key: 'logout', value: this.apiUrl + 'logout'} | |||||
| // ]; | |||||
| // | |||||
| // kvPair.forEach( item => { | |||||
| // if ( item.key === key) { | |||||
| // return item.value; | |||||
| // } | |||||
| // }); | |||||
| // | |||||
| // // not found if arrive here | |||||
| // return s; | |||||
| } | } | ||||
| public UpdatePeopleInfo(people: PeopleModel): void{ | public UpdatePeopleInfo(people: PeopleModel): void{ |
| import {Injectable} from '@angular/core'; | |||||
| import {HttpClient} from '@angular/common/http'; | |||||
| import {AppConfig} from '../app.config'; | |||||
| import {BehaviorSubject, Observable} from 'rxjs'; | |||||
| import {tap} from 'rxjs/operators'; | |||||
| @Injectable() | |||||
| export class FunderNameService extends BehaviorSubject<string[]> { | |||||
| public loading = false; | |||||
| constructor( private http: HttpClient, private config: AppConfig) { | |||||
| super(null); | |||||
| } | |||||
| public query(): void { | |||||
| this.fetch().subscribe( x => super.next(x)); | |||||
| } | |||||
| private fetch(): Observable<string[]>{ | |||||
| this.loading = true; | |||||
| return this.http.get<string[]>(this.config.getUrl('funder-list/')).pipe( | |||||
| tap(() => this.loading = false) | |||||
| ); | |||||
| } | |||||
| } |