| @@ -5,7 +5,7 @@ | |||
| <div class="vertical-spacer"></div> | |||
| <bkp-divider-shadow-bottom></bkp-divider-shadow-bottom> | |||
| <kendo-grid [data]="gridData" | |||
| <kendo-grid [data]="pendingReward" | |||
| [height]="410" | |||
| (add)="addHandler($event)" | |||
| (cancel)="cancelHandler($event)" | |||
| @@ -38,14 +38,77 @@ | |||
| </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> | |||
| <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> | |||
| <div class="vertical-spacer"></div> | |||
| </fieldset> | |||
| </ng-container> | |||
| @@ -1,23 +1,23 @@ | |||
| import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core'; | |||
| import {FormControl, FormGroup, Validators} from '@angular/forms'; | |||
| import {LoanSummaryService} from '../../service/loan_summary.service'; | |||
| import {AuthService} from '../../service/auth.service'; | |||
| import {LoanModel} from '../../models/loan.model'; | |||
| import {Observable} from 'rxjs'; | |||
| import {RewardModel} from '../../models/reward.model'; | |||
| import {PeopleModel} from '../../models/people.model'; | |||
| import {debounce} from 'ts-debounce'; | |||
| import {LoanSingleService} from '../../service/loan.single.service'; | |||
| import {ClonerService} from '../../service/clone.service'; | |||
| const createFormGroup = dataItem => new FormGroup({ | |||
| 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), | |||
| 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({ | |||
| @@ -34,59 +34,9 @@ export class PeopleRewardComponent implements OnInit { | |||
| public contacts: PeopleModel[] = []; | |||
| 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; | |||
| private editedRowIndex: number; | |||
| @@ -97,15 +47,25 @@ export class PeopleRewardComponent implements OnInit { | |||
| 'Admin' | |||
| ]; | |||
| public existingPayDescription: string[] = [ | |||
| 'Upfront', | |||
| 'Broker Fee', | |||
| 'SFM Incentive', | |||
| 'Special Reward', | |||
| 'Discount', | |||
| 'Fringe Cost', | |||
| 'Unknown', | |||
| ]; | |||
| private debounceFilter: any ; | |||
| constructor(private ls: LoanSummaryService, private auth: AuthService) { | |||
| constructor(private ls: LoanSingleService, private auth: AuthService, private dcs: ClonerService) { | |||
| } | |||
| 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.auth.getPeopleList(filter).subscribe( | |||
| @@ -118,6 +78,16 @@ export class PeopleRewardComponent implements OnInit { | |||
| }, 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 { | |||
| this.closeEditor(sender); | |||
| @@ -155,11 +125,21 @@ export class PeopleRewardComponent implements OnInit { | |||
| } | |||
| 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); | |||
| } | |||
| @@ -174,13 +154,6 @@ export class PeopleRewardComponent implements OnInit { | |||
| 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 { | |||
| const url = this.auth.getUrl('avatar/') + peopleId; | |||
| return 'url("' + url + '")'; | |||
| @@ -198,38 +171,4 @@ export class PeopleRewardComponent implements OnInit { | |||
| 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'); | |||
| } | |||
| } | |||
| @@ -1,7 +1,6 @@ | |||
| <kendo-multicolumncombobox | |||
| #list | |||
| [data]="searchResult" | |||
| [(ngModel)]="value" | |||
| [textField]="'Display'" | |||
| [valueField]="getEffectiveField()" | |||
| [valuePrimitive]="true" | |||
| @@ -14,6 +13,7 @@ | |||
| [allowCustom]="false" | |||
| [formControl]="formControl" | |||
| (filterChange)="filterChange($event)" | |||
| (valueChange)="valueChange($event)" | |||
| > | |||
| @@ -30,7 +30,7 @@ export class PeopleSelectComponent implements OnInit, ControlValueAccessor { | |||
| @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent; | |||
| 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; | |||
| private debounceFilter: any ; | |||
| @@ -78,6 +78,7 @@ export class PeopleSelectComponent implements OnInit, ControlValueAccessor { | |||
| // ComboBox emit event on value change | |||
| public valueChange(str: string): void { | |||
| return; | |||
| console.log('value change', str); | |||
| this.onChange(this.value); | |||
| } | |||
| @@ -111,14 +112,15 @@ export class PeopleSelectComponent implements OnInit, ControlValueAccessor { | |||
| // Allows Angular to update the model (name or ID). | |||
| // Update the model and changes needed for the view here. | |||
| writeValue(nameOrId: string): void { | |||
| return; | |||
| if ( nameOrId === undefined ){ | |||
| console.log('who called me for write', this); | |||
| return; | |||
| } | |||
| const changed = nameOrId !== this.value; | |||
| if (this.needSearch() ){ | |||
| if (this.needSearch(nameOrId) ){ | |||
| 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( | |||
| ppl => { | |||
| const person = new PeopleModel( | |||
| @@ -145,7 +147,10 @@ export class PeopleSelectComponent implements OnInit, ControlValueAccessor { | |||
| } | |||
| } | |||
| needSearch(): boolean { | |||
| needSearch(incoming: string ): boolean { | |||
| if ( incoming === undefined || incoming === '' || incoming === this.value ) { | |||
| return false; | |||
| } | |||
| this.searchResult.forEach((person) => { | |||
| if ( this.translateId) { | |||
| if ( person.Id === this.value ) { | |||
| @@ -1,4 +1,4 @@ | |||
| import { PeopleModel } from "./people.model"; | |||
| import { PeopleModel } from './people.model'; | |||
| import {PeopleMapModel} from './people-map.model'; | |||
| import {BrokerModel} from './broker.model'; | |||
| import {PayInModel} from './pay-in.model'; | |||
| @@ -55,7 +55,7 @@ export class LoanModel { | |||
| private setReward(v: any[]): void{ | |||
| this.Reward = []; | |||
| v.forEach((reward) => { | |||
| const r = new RewardModel( | |||
| this.addReward( | |||
| reward.Amount, | |||
| reward.Description, | |||
| reward.Id, | |||
| @@ -63,14 +63,28 @@ export class LoanModel { | |||
| reward.PayOutId, | |||
| reward.To, | |||
| reward.From, | |||
| reward.Ts, | |||
| this.callBacks() | |||
| ); | |||
| this.Reward.push(r); | |||
| reward.Ts); | |||
| }); | |||
| 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 { | |||
| return new RewardModel( | |||
| 0, '', 0, this.Id, | |||
| @@ -115,7 +129,12 @@ export class LoanModel { | |||
| } | |||
| public getUserRole(id: string): string { | |||
| return 'role' + id; | |||
| this.PeopleMap.forEach((row) =>{ | |||
| if ( row.PeopleId === id ){ | |||
| return row.Role; | |||
| } | |||
| }); | |||
| return 'R:'; | |||
| } | |||
| } | |||
| @@ -1,3 +1,7 @@ | |||
| export class PeopleMapModel { | |||
| constructor( | |||
| public LoanId: string, | |||
| public Role: string, | |||
| public PeopleId: string | |||
| ){} | |||
| } | |||
| @@ -9,3 +9,9 @@ span { | |||
| .yellow { | |||
| color: #ffa600; | |||
| } | |||
| :host .ng-dirty { | |||
| border-style: solid; | |||
| border-color: red; | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| import {Injectable} from '@angular/core'; | |||
| import * as clone from 'clone'; | |||
| @Injectable({providedIn: 'root'}) | |||
| export class ClonerService { | |||
| deepClone<T>(value): T { | |||
| return clone<T>(value); | |||
| } | |||
| } | |||
| @@ -3,6 +3,7 @@ import {ApiUrL, AuthService} from './auth.service'; | |||
| import {Observable} from 'rxjs'; | |||
| import {LoanModel} from '../models/loan.model'; | |||
| import {Injectable} from '@angular/core'; | |||
| import {RewardModel} from '../models/reward.model'; | |||
| @Injectable() | |||
| export class LoanSingleService { | |||
| @@ -25,4 +26,8 @@ export class LoanSingleService { | |||
| public apiUrlFunc(): ApiUrL { | |||
| return this.auth.apiUrlFunc(); | |||
| } | |||
| public saveReward(reward: RewardModel, isNew : boolean ): void { | |||
| console.log('saving', reward, isNew, this); | |||
| } | |||
| } | |||
| @@ -54,34 +54,6 @@ export abstract class LoanQueryService extends BehaviorSubject<GridDataResult> { | |||
| } | |||
| } | |||
| @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() | |||
| export class LoanSummaryService extends LoanQueryService { | |||
| constructor(http: HttpClient, auth: AuthService) { super(http, auth, 'full-loan-overview'); } | |||