| <div class="vertical-spacer"></div> | <div class="vertical-spacer"></div> | ||||
| <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | ||||
| <kendo-grid [data]="gridData" | |||||
| <kendo-grid [data]="pendingReward" | |||||
| [height]="410" | [height]="410" | ||||
| (add)="addHandler($event)" | (add)="addHandler($event)" | ||||
| (cancel)="cancelHandler($event)" | (cancel)="cancelHandler($event)" | ||||
| </kendo-grid-column> | </kendo-grid-column> | ||||
| <kendo-grid-column field="Description" title="Description" width="200"></kendo-grid-column> | |||||
| <kendo-grid-column field="Role" title="Role" width="200"> | |||||
| <ng-template | |||||
| kendoGridEditTemplate let-fg="formGroup" let-column="column" let-dataItem="dataItem"> | |||||
| <kendo-combobox | |||||
| name="existingRoles" | |||||
| [data]="existingRoles" | |||||
| [valuePrimitive]="true" | |||||
| [formControl]="formGroup.get(column.field)" | |||||
| > | |||||
| </kendo-combobox> | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="Amount" title="Amount" width="200" editor="numeric" format="{0:c}"></kendo-grid-column> | |||||
| <kendo-grid-column field="Description" title="Description" width="200"> | |||||
| <ng-template | |||||
| kendoGridEditTemplate let-fg="formGroup" let-column="column" let-dataItem="dataItem"> | |||||
| <kendo-combobox | |||||
| name="existingPayDescription" | |||||
| [data]="existingPayDescription" | |||||
| [valuePrimitive]="true" | |||||
| [formControl]="formGroup.get(column.field)" | |||||
| > | |||||
| </kendo-combobox> | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| </kendo-grid> | </kendo-grid> | ||||
| <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | |||||
| <div class="vertical-spacer"></div> | |||||
| Paid Reward (casted into stone, cannot be undone ) | |||||
| <kendo-grid [data]="paidReward" | |||||
| [height]="410" | |||||
| (add)="addHandler($event)" | |||||
| (cancel)="cancelHandler($event)" | |||||
| (save)="saveHandler($event)" | |||||
| (edit)="editHandler($event)" | |||||
| (remove)="removeHandler($event)" | |||||
| > | |||||
| <kendo-grid-column field="Id" title="Id" width="80"> </kendo-grid-column> | |||||
| <kendo-grid-column field="To" title="Name" width="300"> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | |||||
| <div class="customer-photo" [ngStyle]="{'background-image' : photoURL(dataItem.To) }"></div> | |||||
| <div class="customer-name"> {{ UserName(dataItem) }}</div> | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="Role" title="Role" width="200"> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="Amount" title="Amount" width="200" format="{0:c}"></kendo-grid-column> | |||||
| <kendo-grid-column field="Description" title="Description" width="200"> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="Ts" title="Date" width="200"> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | |||||
| {{dataItem.Ts | date: 'yyyy-MM-dd'}} | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="PayOutId" title="Payment Info" width="180"> </kendo-grid-column> | |||||
| </kendo-grid> | |||||
| <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | ||||
| <div class="vertical-spacer"></div> | <div class="vertical-spacer"></div> | ||||
| </fieldset> | </fieldset> | ||||
| </ng-container> | </ng-container> | ||||
| import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core'; | import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core'; | ||||
| import {FormControl, FormGroup, Validators} from '@angular/forms'; | import {FormControl, FormGroup, Validators} from '@angular/forms'; | ||||
| import {LoanSummaryService} from '../../service/loan_summary.service'; | |||||
| import {AuthService} from '../../service/auth.service'; | import {AuthService} from '../../service/auth.service'; | ||||
| import {LoanModel} from '../../models/loan.model'; | import {LoanModel} from '../../models/loan.model'; | ||||
| import {Observable} from 'rxjs'; | |||||
| import {RewardModel} from '../../models/reward.model'; | import {RewardModel} from '../../models/reward.model'; | ||||
| import {PeopleModel} from '../../models/people.model'; | import {PeopleModel} from '../../models/people.model'; | ||||
| import {debounce} from 'ts-debounce'; | import {debounce} from 'ts-debounce'; | ||||
| import {LoanSingleService} from '../../service/loan.single.service'; | |||||
| import {ClonerService} from '../../service/clone.service'; | |||||
| const createFormGroup = dataItem => new FormGroup({ | const createFormGroup = dataItem => new FormGroup({ | ||||
| Id: new FormControl(dataItem.Id), | Id: new FormControl(dataItem.Id), | ||||
| To: new FormControl(dataItem.To, Validators.required), | |||||
| To: new FormControl(dataItem.To, [Validators.required, Validators.maxLength(128), Validators.minLength(1)]), | |||||
| From: new FormControl(dataItem.From), | From: new FormControl(dataItem.From), | ||||
| Role: new FormControl(dataItem.Role), | |||||
| Amount: new FormControl(dataItem.Amount, Validators.compose([Validators.required, Validators.pattern('^[0-9]{1,3}')])), | |||||
| Description: new FormControl(dataItem.Description), | |||||
| PayOutId: new FormControl({value: dataItem.PaidOutId, disabled: dataItem.PayOutId > 0 }) | |||||
| Role: new FormControl(dataItem.Role, [Validators.required, Validators.minLength(2), Validators.maxLength(40)]), | |||||
| Amount: new FormControl(dataItem.Amount, Validators.compose([Validators.required, Validators.min(0), Validators.max(1000000)])), | |||||
| Description: new FormControl(dataItem.Description, [Validators.required, Validators.maxLength(128)]), | |||||
| PayOutId: new FormControl({value: dataItem.PayOutId, disabled: dataItem.PayOutId > 0 }) | |||||
| }); | }); | ||||
| @Component({ | @Component({ | ||||
| public contacts: PeopleModel[] = []; | public contacts: PeopleModel[] = []; | ||||
| public total = 0; | public total = 0; | ||||
| public gridData: RewardModel[] = []; | |||||
| public data = [ | |||||
| { | |||||
| RewardId: 14, | |||||
| UserName: 'Alina Cox', | |||||
| PeopleId: 'df743325-810d-4d25-bb52-91a1a0c3ba22', | |||||
| Role: 'broker', | |||||
| RewardDescription: 'Trail', | |||||
| RewardAmount: 100, | |||||
| Paid: false, | |||||
| }, | |||||
| { | |||||
| RewardId: 13, | |||||
| UserName: 'Alina Cox', | |||||
| PeopleId: 'df743325-810d-4d25-bb52-91a1a0c3ba22', | |||||
| Role: 'broker', | |||||
| RewardDescription: 'Trail', | |||||
| RewardAmount: 100, | |||||
| Paid: false, | |||||
| }, | |||||
| { | |||||
| RewardId: 12, | |||||
| UserName: 'Alina Cox', | |||||
| PeopleId: 'df743325-810d-4d25-bb52-91a1a0c3ba22', | |||||
| Role: 'broker', | |||||
| RewardDescription: 'broker fee', | |||||
| RewardAmount: 100, | |||||
| Paid: true, | |||||
| }, | |||||
| { | |||||
| RewardId: 11, | |||||
| UserName: 'Helen Morgan', | |||||
| PeopleId: '92dd6e14-10da-47ae-89ac-3a52d6567e61', | |||||
| Role: 'Referral', | |||||
| RewardDescription: 'no fee', | |||||
| RewardAmount: 500, | |||||
| Paid: true, | |||||
| }, | |||||
| { | |||||
| RewardId: 10, | |||||
| UserName: 'Oscar Coudors', | |||||
| PeopleId: '09aa4151-7744-422e-9f2c-90b4871018f3', | |||||
| Role: 'Upfront', | |||||
| RewardDescription: 'no fee', | |||||
| RewardAmount: 3000, | |||||
| Paid: true, | |||||
| } | |||||
| public pendingReward: RewardModel[] = []; | |||||
| public paidReward: RewardModel[] = []; | |||||
| ]; | |||||
| public formGroup: FormGroup; | public formGroup: FormGroup; | ||||
| private editedRowIndex: number; | private editedRowIndex: number; | ||||
| 'Admin' | 'Admin' | ||||
| ]; | ]; | ||||
| public existingPayDescription: string[] = [ | |||||
| 'Upfront', | |||||
| 'Broker Fee', | |||||
| 'SFM Incentive', | |||||
| 'Special Reward', | |||||
| 'Discount', | |||||
| 'Fringe Cost', | |||||
| 'Unknown', | |||||
| ]; | |||||
| private debounceFilter: any ; | private debounceFilter: any ; | ||||
| constructor(private ls: LoanSummaryService, private auth: AuthService) { | |||||
| constructor(private ls: LoanSingleService, private auth: AuthService, private dcs: ClonerService) { | |||||
| } | } | ||||
| public ngOnInit(): void { | public ngOnInit(): void { | ||||
| // this.gridData = this.service.products(); | |||||
| Object.assign(this.gridData, this.Loan.Reward); | |||||
| console.log(this.Loan, this.gridData); | |||||
| this.initReward(); | |||||
| console.log(this.Loan, this.pendingReward); | |||||
| this.debounceFilter = debounce( (filter: string): void => { | this.debounceFilter = debounce( (filter: string): void => { | ||||
| this.auth.getPeopleList(filter).subscribe( | this.auth.getPeopleList(filter).subscribe( | ||||
| }, 500) ; | }, 500) ; | ||||
| } | } | ||||
| public initReward(): void { | |||||
| this.Loan.Reward.forEach((r) => { | |||||
| const o = this.dcs.deepClone<RewardModel>(r); | |||||
| if ( r.PayOutId > 0 ){ | |||||
| this.paidReward.push(o); | |||||
| }else{ | |||||
| this.pendingReward.push(o); | |||||
| } | |||||
| }); | |||||
| } | |||||
| public addHandler({ sender }): void { | public addHandler({ sender }): void { | ||||
| this.closeEditor(sender); | this.closeEditor(sender); | ||||
| } | } | ||||
| public saveHandler({ sender, rowIndex, formGroup, isNew }): void { | public saveHandler({ sender, rowIndex, formGroup, isNew }): void { | ||||
| const product = formGroup.value; | |||||
| console.log('"saving', product, formGroup); | |||||
| // this.service.save(product, isNew); | |||||
| const reward = formGroup.value; | |||||
| reward.From = '0'; // Admin | |||||
| reward.Ts = new Date(); // Now | |||||
| reward.PayOutId = 0; // make sure it is not paid | |||||
| this.ls.saveReward(reward, isNew); | |||||
| this.pendingReward.push( this.Loan.addReward( | |||||
| reward.Amount, | |||||
| reward.Description, | |||||
| reward.Id, | |||||
| reward.LoanId, | |||||
| reward.PayOutId, | |||||
| reward.To, | |||||
| reward.From, | |||||
| reward.Ts | |||||
| )); | |||||
| sender.closeRow(rowIndex); | sender.closeRow(rowIndex); | ||||
| } | } | ||||
| this.formGroup = undefined; | this.formGroup = undefined; | ||||
| } | } | ||||
| public onUserNameChanged(event: any, dataItem: any): void { | |||||
| console.log(event, dataItem); | |||||
| dataItem.UserId = 'fuck this user id'; | |||||
| // debounce | |||||
| // console.log(event); | |||||
| } | |||||
| private photoURL(peopleId: string): string { | private photoURL(peopleId: string): string { | ||||
| const url = this.auth.getUrl('avatar/') + peopleId; | const url = this.auth.getUrl('avatar/') + peopleId; | ||||
| return 'url("' + url + '")'; | return 'url("' + url + '")'; | ||||
| this.NotifyPrev.emit(true); | this.NotifyPrev.emit(true); | ||||
| } | } | ||||
| filterChange(filter: string): void { | |||||
| if (filter.length > 1 ) { | |||||
| this.debounceFilter(filter); | |||||
| } | |||||
| } | |||||
| public getContactImageUrl(contactId: string): string { | |||||
| return this.auth.getUrl('avatar/' + contactId); | |||||
| } | |||||
| public valueChange(value: any): void { | |||||
| console.log('valueChange', value); | |||||
| } | |||||
| public selectionChange(value: any): void { | |||||
| console.log('selectionChange', value); | |||||
| } | |||||
| public open(): void { | |||||
| console.log('open'); | |||||
| } | |||||
| public close(): void { | |||||
| console.log('close'); | |||||
| } | |||||
| public focus(): void { | |||||
| console.log('focus'); | |||||
| } | |||||
| public blur(): void { | |||||
| console.log('blur'); | |||||
| } | |||||
| } | } |
| <kendo-multicolumncombobox | <kendo-multicolumncombobox | ||||
| #list | #list | ||||
| [data]="searchResult" | [data]="searchResult" | ||||
| [(ngModel)]="value" | |||||
| [textField]="'Display'" | [textField]="'Display'" | ||||
| [valueField]="getEffectiveField()" | [valueField]="getEffectiveField()" | ||||
| [valuePrimitive]="true" | [valuePrimitive]="true" | ||||
| [allowCustom]="false" | [allowCustom]="false" | ||||
| [formControl]="formControl" | |||||
| (filterChange)="filterChange($event)" | (filterChange)="filterChange($event)" | ||||
| (valueChange)="valueChange($event)" | (valueChange)="valueChange($event)" | ||||
| > | > |
| @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent; | @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent; | ||||
| public searchResult: PeopleModel[] = []; | public searchResult: PeopleModel[] = []; | ||||
| public value = ''; // selecting the default and only empty contact element | |||||
| public value = ''; // selecting the default and only empty contact element // TODO: remove ngModel | |||||
| public total = 0; | public total = 0; | ||||
| private debounceFilter: any ; | private debounceFilter: any ; | ||||
| // ComboBox emit event on value change | // ComboBox emit event on value change | ||||
| public valueChange(str: string): void { | public valueChange(str: string): void { | ||||
| return; | |||||
| console.log('value change', str); | console.log('value change', str); | ||||
| this.onChange(this.value); | this.onChange(this.value); | ||||
| } | } | ||||
| // Allows Angular to update the model (name or ID). | // Allows Angular to update the model (name or ID). | ||||
| // Update the model and changes needed for the view here. | // Update the model and changes needed for the view here. | ||||
| writeValue(nameOrId: string): void { | writeValue(nameOrId: string): void { | ||||
| return; | |||||
| if ( nameOrId === undefined ){ | if ( nameOrId === undefined ){ | ||||
| console.log('who called me for write', this); | console.log('who called me for write', this); | ||||
| return; | return; | ||||
| } | } | ||||
| const changed = nameOrId !== this.value; | const changed = nameOrId !== this.value; | ||||
| if (this.needSearch() ){ | |||||
| if (this.needSearch(nameOrId) ){ | |||||
| this.text.loading = true; | this.text.loading = true; | ||||
| console.log('searching ... ', nameOrId, this.translateId? 'by id' : 'by name'); | |||||
| console.log('searching ... ', nameOrId, this.translateId ? 'by id' : 'by name'); | |||||
| this.searchUser(nameOrId, this.translateId).subscribe( | this.searchUser(nameOrId, this.translateId).subscribe( | ||||
| ppl => { | ppl => { | ||||
| const person = new PeopleModel( | const person = new PeopleModel( | ||||
| } | } | ||||
| } | } | ||||
| needSearch(): boolean { | |||||
| needSearch(incoming: string ): boolean { | |||||
| if ( incoming === undefined || incoming === '' || incoming === this.value ) { | |||||
| return false; | |||||
| } | |||||
| this.searchResult.forEach((person) => { | this.searchResult.forEach((person) => { | ||||
| if ( this.translateId) { | if ( this.translateId) { | ||||
| if ( person.Id === this.value ) { | if ( person.Id === this.value ) { |
| import { PeopleModel } from "./people.model"; | |||||
| import { PeopleModel } from './people.model'; | |||||
| import {PeopleMapModel} from './people-map.model'; | import {PeopleMapModel} from './people-map.model'; | ||||
| import {BrokerModel} from './broker.model'; | import {BrokerModel} from './broker.model'; | ||||
| import {PayInModel} from './pay-in.model'; | import {PayInModel} from './pay-in.model'; | ||||
| private setReward(v: any[]): void{ | private setReward(v: any[]): void{ | ||||
| this.Reward = []; | this.Reward = []; | ||||
| v.forEach((reward) => { | v.forEach((reward) => { | ||||
| const r = new RewardModel( | |||||
| this.addReward( | |||||
| reward.Amount, | reward.Amount, | ||||
| reward.Description, | reward.Description, | ||||
| reward.Id, | reward.Id, | ||||
| reward.PayOutId, | reward.PayOutId, | ||||
| reward.To, | reward.To, | ||||
| reward.From, | reward.From, | ||||
| reward.Ts, | |||||
| this.callBacks() | |||||
| ); | |||||
| this.Reward.push(r); | |||||
| reward.Ts); | |||||
| }); | }); | ||||
| return; | return; | ||||
| } | } | ||||
| public addReward(Amount: number, Description: string, Id: number, | |||||
| LoanId: string, PayOutId: number, To: string , From: string, Ts: Date): RewardModel { | |||||
| const r = new RewardModel( | |||||
| Amount, | |||||
| Description, | |||||
| Id, | |||||
| LoanId, | |||||
| PayOutId, | |||||
| To, | |||||
| From, | |||||
| Ts, | |||||
| this.callBacks() | |||||
| ); | |||||
| this.Reward.push(r); | |||||
| return r; | |||||
| } | |||||
| public emptyReward(): RewardModel { | public emptyReward(): RewardModel { | ||||
| return new RewardModel( | return new RewardModel( | ||||
| 0, '', 0, this.Id, | 0, '', 0, this.Id, | ||||
| } | } | ||||
| public getUserRole(id: string): string { | public getUserRole(id: string): string { | ||||
| return 'role' + id; | |||||
| this.PeopleMap.forEach((row) =>{ | |||||
| if ( row.PeopleId === id ){ | |||||
| return row.Role; | |||||
| } | |||||
| }); | |||||
| return 'R:'; | |||||
| } | } | ||||
| } | } |
| export class PeopleMapModel { | export class PeopleMapModel { | ||||
| constructor( | |||||
| public LoanId: string, | |||||
| public Role: string, | |||||
| public PeopleId: string | |||||
| ){} | |||||
| } | } |
| .yellow { | .yellow { | ||||
| color: #ffa600; | color: #ffa600; | ||||
| } | } | ||||
| :host .ng-dirty { | |||||
| border-style: solid; | |||||
| border-color: red; | |||||
| } |
| import {Injectable} from '@angular/core'; | |||||
| import * as clone from 'clone'; | |||||
| @Injectable({providedIn: 'root'}) | |||||
| export class ClonerService { | |||||
| deepClone<T>(value): T { | |||||
| return clone<T>(value); | |||||
| } | |||||
| } |
| import {Observable} from 'rxjs'; | import {Observable} from 'rxjs'; | ||||
| import {LoanModel} from '../models/loan.model'; | import {LoanModel} from '../models/loan.model'; | ||||
| import {Injectable} from '@angular/core'; | import {Injectable} from '@angular/core'; | ||||
| import {RewardModel} from '../models/reward.model'; | |||||
| @Injectable() | @Injectable() | ||||
| export class LoanSingleService { | export class LoanSingleService { | ||||
| public apiUrlFunc(): ApiUrL { | public apiUrlFunc(): ApiUrL { | ||||
| return this.auth.apiUrlFunc(); | return this.auth.apiUrlFunc(); | ||||
| } | } | ||||
| public saveReward(reward: RewardModel, isNew : boolean ): void { | |||||
| console.log('saving', reward, isNew, this); | |||||
| } | |||||
| } | } |
| } | } | ||||
| } | } | ||||
| @Injectable() | |||||
| export class ProductsService extends LoanQueryService { | |||||
| constructor(http: HttpClient, auth: AuthService) { super(http, auth, 'Products'); } | |||||
| public queryForCategory({ CategoryID }: { CategoryID: number }, state?: any): void { | |||||
| this.query(Object.assign({}, state, { | |||||
| filter: { | |||||
| filters: [{ | |||||
| field: 'CategoryID', operator: 'eq', value: CategoryID | |||||
| }], | |||||
| logic: 'and' | |||||
| } | |||||
| })); | |||||
| } | |||||
| public queryForProductName(ProductName: string, state?: any): void { | |||||
| this.query(Object.assign({}, state, { | |||||
| filter: { | |||||
| filters: [{ | |||||
| field: 'ProductName', operator: 'contains', value: ProductName | |||||
| }], | |||||
| logic: 'and' | |||||
| } | |||||
| })); | |||||
| } | |||||
| } | |||||
| @Injectable() | @Injectable() | ||||
| export class LoanSummaryService extends LoanQueryService { | export class LoanSummaryService extends LoanQueryService { | ||||
| constructor(http: HttpClient, auth: AuthService) { super(http, auth, 'full-loan-overview'); } | constructor(http: HttpClient, auth: AuthService) { super(http, auth, 'full-loan-overview'); } |