Pārlūkot izejas kodu

first reusable filter for numbers

tags/2.037
Patrick Sun pirms 4 gadiem
vecāks
revīzija
1367233b19
17 mainītis faili ar 752 papildinājumiem un 24 dzēšanām
  1. +17
    -2
      src/app/app.component.ts
  2. +2
    -0
      src/app/app.module.ts
  3. +5
    -3
      src/app/auth/auth-http-interceptor.service.ts
  4. +1
    -1
      src/app/auth/auth.component.ts
  5. +46
    -0
      src/app/grid-filter/number-range-filter/number-range-filter.component.html
  6. +63
    -0
      src/app/grid-filter/number-range-filter/number-range-filter.component.scss
  7. +25
    -0
      src/app/grid-filter/number-range-filter/number-range-filter.component.spec.ts
  8. +473
    -0
      src/app/grid-filter/number-range-filter/number-range-filter.component.ts
  9. +35
    -0
      src/app/models/grid.state.model.ts
  10. +2
    -0
      src/app/models/websocket/ws.login.event.model.ts
  11. +12
    -5
      src/app/pay-in/pay-in.component.html
  12. +33
    -4
      src/app/pay-in/pay-in.component.ts
  13. +2
    -2
      src/app/service/auth-guard.service.ts
  14. +5
    -0
      src/app/service/pay-in.service.ts
  15. +23
    -6
      src/app/service/session.service.ts
  16. +7
    -0
      src/app/websocket.ts
  17. +1
    -1
      tsconfig.json

+ 17
- 2
src/app/app.component.ts Parādīt failu

@@ -21,6 +21,7 @@ export class AppComponent implements OnInit , OnDestroy {
@ViewChild('loanEditComponent', {static: true}) loanEdit: LoanEditComponent;

webSocketSubscription: Subscription;
wsAssignSocketIdSub: Subscription;
wsLoginSub: Subscription;

constructor(private menuService: MenuService,
@@ -36,6 +37,10 @@ export class AppComponent implements OnInit , OnDestroy {
this.onWSLogin(m);
});

this.wsAssignSocketIdSub = this.wsService.assignSocketIdEvent.subscribe(m =>{
this.onWSAssignSocketId(m);
});

this.titleService.setTitle(this.title);
}

@@ -57,13 +62,18 @@ export class AppComponent implements OnInit , OnDestroy {
ngOnDestroy(): void {
this.webSocketSubscription.unsubscribe();
this.wsLoginSub.unsubscribe();
this.wsAssignSocketIdSub.unsubscribe();
}

onWSLogin(e: WsLoginEventModel): void {
if ( e.SocketId === this.ss.SocketId ) { // our own message
return;
}
console.log('on login out', this);
if ( e.T === 'logout' ) { // regardless where are they, logout means logout
if ( this.ss.isLoggedIn() && this.ss.isCurrentUser(e.Uid) ) {
if ( e.Sid === this.ss.SessionId ) {
this.ss.logoutAndClearLocalStorage();
if ( e.Mid === this.ss.MachineId ) {
this.ss.logoutWithoutPersistingStorage();
}else{
this.ss.logout();
}
@@ -76,5 +86,10 @@ export class AppComponent implements OnInit , OnDestroy {
}
}
}

onWSAssignSocketId(id: string): void{
console.log('get registration id', id);
this.ss.SocketId = id;
}
}


+ 2
- 0
src/app/app.module.ts Parādīt failu

@@ -112,6 +112,7 @@ import { RewardSelectComponent } from './reward-select/reward-select.component';
import { RewardsAllComponent } from './rewards-all/rewards-all.component';
import { SinglePayoutRewardsListComponent } from './single-payout-rewards-list/single-payout-rewards-list.component';
import {SessionService} from './service/session.service';
import { NumberRangeFilterComponent } from './grid-filter/number-range-filter/number-range-filter.component';



@@ -192,6 +193,7 @@ export function initializeApp(appConfig: AppConfig): () => Promise<void> {
RewardSelectComponent,
RewardsAllComponent,
SinglePayoutRewardsListComponent,
NumberRangeFilterComponent,
],
imports: [
BrowserModule,

+ 5
- 3
src/app/auth/auth-http-interceptor.service.ts Parādīt failu

@@ -20,6 +20,9 @@ export class AuthHttpInterceptor implements HttpInterceptor {
if (this.ss.MachineId !== '') {
h = h.set('Biukop-Mid', this.ss.MachineId);
}
if (this.ss.SocketId !== '') {
h = h.set('Biukop-Socket', this.ss.SocketId);
}

const authReq = req.clone({
headers: h,
@@ -43,9 +46,8 @@ export class AuthHttpInterceptor implements HttpInterceptor {
public setSession(bs: string): void {
// console.log('receive session:' , bs);
if (bs){
if ( this.ss.loggedIn.session !== bs ){
this.ss.loggedIn.session = bs;
this.ss.saveSessionInfo();
if ( this.ss.SessionId !== bs ){
this.ss.SessionId = bs;
console.log('switch session:' , bs);
}
}

+ 1
- 1
src/app/auth/auth.component.ts Parādīt failu

@@ -48,7 +48,7 @@ export class AuthComponent implements OnInit, OnDestroy{

public onLogin(rsp: ApiV1LoginResponse): void {
this.loading = false;
// console.log ('found login ' , rsp );
// console.log (' auth event login ' , rsp );
if (rsp.login) {
switch ( rsp.role ) {
case 'admin':

+ 46
- 0
src/app/grid-filter/number-range-filter/number-range-filter.component.html Parādīt failu

@@ -0,0 +1,46 @@
<div #anchor class="filter">
<div *ngIf="singleMode" class="single">
<kendo-dropdownbutton *ngIf="showOperatorChoice" class="thin"
[data]="availableOperators" textField="op" look="bare"
(itemClick)="onOperatorClick($event)">
{{operator.op}}
</kendo-dropdownbutton>
<kendo-textbox #single class="full" [ngClass]="{'with-padding': showOperatorChoice}"
[(ngModel)]="valueFrom" (valueChange)="onChangeFrom($event)"
[ngModelOptions]="{standalone: true}"
[showErrorIcon]="!valueFromValid"
[required]="required"
(inputFocus)="onFromTouched()"
></kendo-textbox>
</div>


<div *ngIf="!singleMode" class="multiple" >
<kendo-textbox #rangeFrom class="first-half"
[required]="required"
[showErrorIcon]="!valueFromValid"
[ngModelOptions]="{standalone: true}"
(inputFocus)="onFromTouched()"
[(ngModel)]="valueFrom" (valueChange)="onChangeFrom($event)">

</kendo-textbox>
<kendo-dropdownbutton class="minimum"
[data]="availableOperators" textField="op"
look="bare" (itemClick)="onOperatorClick($event)">
{{operator.op}}
</kendo-dropdownbutton>
<kendo-textbox #rangeTo class="second-half"
[required]="required"
[showErrorIcon]="!valueToValid"
[(ngModel)]="valueTo"
(inputFocus)="onToTouched()"
[ngModelOptions]="{standalone: true}"
(valueChange)="onChangeTo($event)"></kendo-textbox>
</div>
</div>

<kendo-popup [anchor]="anchor" (anchorViewportLeave)="showError = false" *ngIf="showError" >
<div class="content popup-content">
{{errorMessage}}
</div>
</kendo-popup>

+ 63
- 0
src/app/grid-filter/number-range-filter/number-range-filter.component.scss Parādīt failu

@@ -0,0 +1,63 @@
div.filter{
display:flex;
width: 100%;
background: white;

kendo-textbox{
display: flex;
width: 100%;
margin:1px;
background: transparent;
}

div.single{
display:flex;
flex-direction: row;
width: 100%;
.thin {
width: 1px;
z-index:1;
}
.full{
width: 100%;
border-left:0;
border-right:0;
border-top:0;
border-bottom:1px solid darkgrey;
}
.full.with-padding{
padding-left: 18px;
}
}

div.multiple{
display:flex;
width: 100%;
flex-direction: column;
align-items: center;
.minimum {
height: 10px;
}
.first-half{

border-left: 1px solid lightblue;
border-right: 1px solid lightblue;
border-top: 3px solid lightblue;
border-bottom: 1px dotted darkgray;
}

.second-half{
border-left: 1px solid lightblue;
border-right: 1px solid lightblue;
border-top: 1px dotted lightblue;
border-bottom: 3px solid darkgray;
}
}

}
.popup-content{
padding: 10px;
background: black;
opacity: 0.5;
color: white
}

+ 25
- 0
src/app/grid-filter/number-range-filter/number-range-filter.component.spec.ts Parādīt failu

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { NumberRangeFilterComponent } from './number-range-filter.component';

describe('NumberRangeFilterComponent', () => {
let component: NumberRangeFilterComponent;
let fixture: ComponentFixture<NumberRangeFilterComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NumberRangeFilterComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(NumberRangeFilterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 473
- 0
src/app/grid-filter/number-range-filter/number-range-filter.component.ts Parādīt failu

@@ -0,0 +1,473 @@
import {Component, Input, OnChanges, OnInit, ViewChild} from '@angular/core';
import {CompositeFilterDescriptor, FilterDescriptor} from '@progress/kendo-data-query';
import {BaseFilterCellComponent, FilterService} from '@progress/kendo-angular-grid';
import {trim} from '@progress/kendo-angular-editor/dist/es2015/util';
import {debounce} from 'ts-debounce';
import {TextBoxComponent} from '@progress/kendo-angular-inputs';



class Operator { op: string; value: string; }

@Component({
selector: 'app-number-range-filter',
templateUrl: './number-range-filter.component.html',
styleUrls: ['./number-range-filter.component.scss']
})
export class NumberRangeFilterComponent extends BaseFilterCellComponent implements OnInit, OnChanges {

constructor(filterService: FilterService) { super(filterService); }

@Input() public filter: CompositeFilterDescriptor;
@Input() public min = -1;
@Input() public max = -1;
@Input() public required = false;
@Input() public fieldName = '';
@Input() public options = ['=', '≠', '>', '≥', '<', '≤', '⇩'];
// ngModel control
@ViewChild('single') ctlSingle: TextBoxComponent;
@ViewChild('rangeFrom') ctlRangeFrom: TextBoxComponent;
@ViewChild('rangeTo') ctlRangeTo: TextBoxComponent;

public operator: Operator = {op: '=', value: 'eq'};
private defaultOperator: Operator = {op: '=', value: 'eq'};
public availableOperators: Operator[] = [];
private AllOperatorMap = [
{op: '=', value: 'eq'},
{op: '≠', value: 'neq'},
{op: '>', value: 'gt'},
{op: '≥', value: 'gte'},
{op: '<', value: 'lt'},
{op: '≤', value: 'lte'},
{op: '⇩', value: 'range'}
];

public singleMode = true;

public valueFrom = '';
public valueTo = '';
public valueFromValid = true;
public valueToValid = true;
public fromTouched = false;
public toTouched = false;
public currentFocus = '';

public showOperatorChoice = true;
public showError = false;

public validateResult = new Map<string, string>();
public errorMessage = '';

private debouncedSingleFrom = debounce(this.valueFromChanged, 500);
private debouncedRangeFrom = debounce(this.rangeFromChanged, 500);
private debouncedUpdateTo = debounce(this.rangeToChanged, 500);

private isEmpty(v: string): boolean{
return trim(v) === '';
}

private isNumber(v: string): boolean{
const vf = Number(v);
return v !== null && ! isNaN(vf) ;
}

ngOnInit(): void {
console.log(this);
this.initAvailableOperators();
this.showOperatorChoice = this.availableOperators.length > 1 ||
( this.availableOperators[0].op !== '=' && this.availableOperators[0].op !== ' ');
}

ngOnChanges(changes): void {
if ( changes.options ){
this.initAvailableOperators();
}
}

private initAvailableOperators(): void {
this.availableOperators = this.AllOperatorMap.filter( v => this.options.indexOf(v.value) !== -1 );
if ( this.availableOperators.length === 0) {
this.availableOperators = [this.defaultOperator];
this.operator = this.defaultOperator;
}else{
this.operator = this.availableOperators[0];
}
this.singleMode = this.operator.value !== 'range';
}


//
// Events handling
//

public onOperatorClick(op: Operator): void {
if ( this.operator === op ) { // same op
return;
}
this.operator = op;
this.singleMode = op.value !== 'range';

if (!this.toTouched && ! this.fromTouched) {
return ;
}

this.clearError(); // start validation
if ( this.singleMode ){
this.valueTo = ''; // clear to
if (this.fromTouched ){
this.onChangeFrom(this.valueFrom);
}
}else if (!this.singleMode) {
if (this.fromTouched ){
this.validateFromAsRange(this.valueFrom);
}
if (this.toTouched ){
this.validateTo(this.valueTo);
}
}

this.showError = this.buildErrorMessage();

if ( ! this.showError ){
this.buildFilter();
}
}

public onChangeFrom(v: string): void {
this.clearError();
this.valueFromValid = this.validateFrom(v);
if ( this.singleMode ){
this.debouncedSingleFrom(v).then();
}else{
this.debouncedRangeFrom(v).then();
}
this.showError = this.buildErrorMessage();
}

public onFromTouched(): void {
this.fromTouched = true;
this.currentFocus = 'from';
}

public onToTouched(): void {
this.toTouched = false;
this.currentFocus = 'to';
}

public onChangeTo(v: string): void {
this.clearError();
this.valueToValid = this.validateTo(v);
this.debouncedUpdateTo(v).then();
this.showError = this.buildErrorMessage();
}

//
// debounced function
//

private valueFromChanged(v: string): void{
if ( this.validateResult.size === 0 ) {
this.buildFilter();
return;
}
// remove filter
this.clearOurFilter();
}

private rangeFromChanged(v): void{
if ( this.validateResult.size === 0 ) {
this.buildFilter();
return;
}
// remove filter
this.clearOurFilter();
}

private rangeToChanged(v: string): void {
if ( this.validateResult.size === 0 ) {
this.buildFilter();
return;
}
// remove filter
this.clearOurFilter();

if ( this.valueFromValid && this.valueToValid) {
this.buildFilter();
}else{
if (this.fieldName && trim(this.fieldName) !== ''){
const f = this.removeFilter(this.fieldName);
this.applyFilter(f);
}
}
}


private clearOurFilter(): void {
if (this.fieldName && trim(this.fieldName) !== ''){
const f = this.removeFilter(this.fieldName);
this.applyFilter(f);
}
}


protected buildFilter(): void {
if (this.fieldName === '') {
console.warn('filed name is not specified, skip update filter', this);
return;
}

if (this.singleMode) {
this.buildSingleFilter();
} else {
this.buildRangeFilter();
}

}

private buildSingleFilter(): void {
if ( this.valueFrom === null ) { return; }
const filter: FilterDescriptor = {
field: this.fieldName,
operator: this.operator.value,
value: this.valueFrom,
};
this.applyFilter(this.updateFilter(filter));
}

private buildRangeFilter(): void {
const fs: FilterDescriptor[] = [];
this.valueFromValid = this.validateFromAsRange(this.valueFrom);
this.valueToValid = this.validateTo(this.valueTo);
if ( this.valueFromValid && this.valueFrom !== null && this.valueFrom !== '') {
fs.push({
field: this.fieldName,
operator: 'gte',
value: this.valueFrom
});
}

if ( this.valueToValid && this.valueTo !== null && this.valueTo !== '') {
fs.push({
field: this.fieldName,
operator: 'lte',
value: this.valueTo
});
}
this.removeFilter(this.fieldName);
const root: CompositeFilterDescriptor = this.filter || { logic: 'and',
filters: [],
};

if (fs.length) {
root.filters.push(...fs);
}
this.filterService.filter(root);
}

private validateCommon(v: string, field?: string ): boolean {
const f = field || '';
if ( v === null ){
this.validateResult.set(f + 'null', ' value is null');
return false;
}

if (! this.isNumber(v) ) {
this.validateResult.set(f + 'number', 'should be number');
return false;
}

return this.isWithinRange(v, field);

}

private validateFrom(v: string): boolean {
if ( this.singleMode ) {
return this.validateFromAsSingle(v);
} else {
return this.validateFromAsRange(v);
}
}

private validateFromAsSingle(v: string): boolean {
if ( ! this.validateCommon(v) ) {
return false;
}

if (this.required && this.isEmpty(v) ) {
this.validateResult.set('required', 'value is required');
return false;
}
return true;
}

private validateFromAsRange(v: string): boolean {
if ( ! this.validateCommon(v, 'from_') ){
return false;
}

if ( !this.isFromLessThanTo() ){
return false;
}
return true;
}

private validateTo(v: string): boolean{
if ( ! this.validateCommon(v, 'to_') ) {
return false;
}

if ( ! this.isFromLessThanTo() ) {
return false;
}

return true;
}

private isFromLessThanTo(): boolean{
if (this.isEmpty( this.valueFrom) || this.isEmpty(this.valueTo)){
return true; // if one of them is empty, we dont care about who is bigger
}

if ( ! (Number(this.valueFrom) <= Number(this.valueTo)) ){
this.validateResult.set('min>max', 'min must ≤ max');
return false;
}
return true;
}

private buildErrorMessage(): boolean {
if (this.singleMode) {
return this.buildSingleError();
} else {
return this.buildRangeError();
}
}

private clearError(): void {
this.showError = false;
this.validateResult.clear();
this.errorMessage = '' ;
}

private buildSingleError(): boolean {

if ( this.validateResult.has('null') ){
this.errorMessage = 'can not be null';
return true;
}

if (this.validateResult.has('required')){
this.errorMessage = 'value is required' + this.hint();
return true;
}

if (this.validateResult.has('number')){
this.errorMessage = 'should be a number';
return true;
}

if (this.validateResult.has('min')){
this.errorMessage = 'should ≥ ' + this.min;
return true;
}

if (this.validateResult.has('max')){

this.errorMessage = 'should ≤ ' + this.max;
return true;
}

const touched = this.fromTouched || this.toTouched; // this.ctlRangeFrom
this.showError = this.errorMessage !== '' && ! touched;
return this.showError;
}

private buildRangeError(): boolean {

if ( this.validateResult.has('from_null') && this.validateResult.has('to_null') ){
this.errorMessage = 'can not be null';
return true;
}

if (this.validateResult.has('from_number') || this.validateResult.has( 'to_number')) {
this.errorMessage = 'should be a number';
return true;
}

if (this.validateResult.has('from_min') || this.validateResult.has('to_min')) {
this.errorMessage = 'should ≥ ' + this.min;
return true;
}

if (this.validateResult.has('from_max') || this.validateResult.has('to_max')){
this.errorMessage = 'should ≤ ' + this.max;
return true;
}

if (this.validateResult.has('min>max')){
if (this.currentFocus === 'to'){
this.errorMessage = 'should ≥ ' + this.valueFrom;
}else{
this.errorMessage = 'should ≤ ' + this.valueTo;
}

return true;
}

return false;
}

private hint(): string{
let hint = '';

if ( this.min !== -1 && this.max === -1) {
hint = ' > ' + this.min + ' ';
}

if (this.max !== -1 && this.min === -1 ) {
hint = ' < ' + this.max + ' ';
}

if (this.min !== -1 && this.max !== -1) {
hint = this.min + ' - ' + this.max;
}

if ( hint !== '' ){
hint = ' (' + hint + ') ';
}
return hint;
}


private isWithinRange(v: string, field?: string): boolean{
const f = field || '';
if ( this.isEmpty(v) ){
if (this.singleMode && this.required){
this.validateResult.set(f + 'required', 'must input something');
return false;
}
return true;
}

const vf = Number(v);
if (! this.isNumber(v)) {
this.validateResult.set(f + 'number', 'must be a number');
return false;
}

if ( this.min !== -1 && vf < this.min ){
this.validateResult.set(f + 'min', 'cannot be lower than min');
return false;
}

if (this.max !== -1 && vf > this.max ) {
this.validateResult.set(f + 'max', 'cannot be greater than max');
return false;
}

// if we reached here
return true;
}


}

+ 35
- 0
src/app/models/grid.state.model.ts Parādīt failu

@@ -0,0 +1,35 @@
import {CompositeFilterDescriptor, GroupDescriptor, SortDescriptor} from '@progress/kendo-data-query';
import {DataStateChangeEvent} from '@progress/kendo-angular-grid';


export class GridStateModel implements DataStateChangeEvent {
/**
* The number of records to skip.
*/
skip: number;
/**
* The number of records to take.
*/
take: number;
/**
* The sort descriptors by which the data is sorted.
*/
sort?: Array<SortDescriptor>;
/**
* The group descriptors by which the data is grouped.
*/
group?: Array<GroupDescriptor>;
/**
* The filter descriptor by which the data is filtered.
*/
filter?: CompositeFilterDescriptor;

public constructor(payload?: Partial<GridStateModel>) {
if ( ! payload ) payload = {};
this.skip = payload.skip || 0;
this.take = payload.take || 0;
this.sort = payload.sort || [];
this.group = payload.group || [];
this.filter = payload.filter || { logic: 'and', filters: [] };
}
}

+ 2
- 0
src/app/models/websocket/ws.login.event.model.ts Parādīt failu

@@ -3,6 +3,7 @@ export class WsLoginEventModel{
T: string;
Mid: string;
Sid: string;
SocketId: string;
Uid: string;
Role: string;
constructor( payload: Partial<WsLoginEventModel>) {
@@ -11,5 +12,6 @@ export class WsLoginEventModel{
this.Sid = payload.Sid || '';
this.Uid = payload.Uid || '';
this.Role = payload.Uid || '';
this.SocketId = payload.SocketId || '';
}
}

+ 12
- 5
src/app/pay-in/pay-in.component.html Parādīt failu

@@ -1,13 +1,15 @@
<kendo-grid #grid [data]="gridData"
[pageable]="pageable"
[navigable]="true"
[resizable]="true"
[pageSize]="filter.Take"
[skip]="filter.Skip"
[sortable]="sortable"
[filterable]="false"
[filterable]="'row'"
[loading]="loading"

[sort]="filter.Sort"
[filter]="state.filter"

[selectable]="true"
kendoGridSelectBy
@@ -21,6 +23,8 @@
(edit)="editHandler($event)"
(remove)="removeHandler($event)"

(dataStateChange)="dataStateChange($event)"
(filterChange)="filterChange($event)"
(pageChange)="pageChange($event)"
(sortChange)="sortChange($event)"
[ngClass]="{ 'filterByUploadMeta': uploadMeta.Id > 0 }"
@@ -49,12 +53,15 @@
</ng-template>
</kendo-grid-command-column>

<kendo-grid-column field="Id" title="Id" width="50" editable="false" >
<kendo-grid-column field="Id" title="Id" width="100" editable="false">
<ng-template kendoGridFilterCellTemplate let-filter let-column="column">
<kendo-grid-numeric-filter-cell [column]="column" [filter]="filter" [showOperators]="false" >

</kendo-grid-numeric-filter-cell>
<app-number-range-filter [filter]="filter" [fieldName]="'Id'"
[options]="['eq', 'lt', 'gte', 'range' ]" [min]=1 [max]="20"
[required]="true"
>
</app-number-range-filter>
</ng-template>

</kendo-grid-column>

<kendo-grid-column field="Lender" title="Lender" width="150" >

+ 33
- 4
src/app/pay-in/pay-in.component.ts Parādīt failu

@@ -6,8 +6,8 @@ import {PayInService} from '../service/pay-in.service';
import {PayInListResult} from '../models/pay-in-list-result.model';
import {Router} from '@angular/router';
import {PopupIncomeFilterComponent} from '../popup-income-filter/popup-income-filter.component';
import {GridComponent, PageChangeEvent, RowClassArgs, SortSettings} from '@progress/kendo-angular-grid';
import {SortDescriptor} from '@progress/kendo-data-query';
import {GridComponent, PageChangeEvent, RowClassArgs, SortSettings, DataStateChangeEvent} from '@progress/kendo-angular-grid';
import {CompositeFilterDescriptor, FilterDescriptor, SortDescriptor} from '@progress/kendo-data-query';
import {UploadMetaModel} from '../models/uploadMetaModel';
import {debounce} from 'ts-debounce';
import {LoanModel} from '../models/loan.model';
@@ -15,6 +15,7 @@ import {LoanSingleService} from '../service/loan.single.service';
import {PayInModelEx} from '../models/pay-in-ex.model';
import {Observable} from 'rxjs';
import {LenderNameService} from '../service/lender-name.service';
import {GridStateModel} from '../models/grid.state.model';



@@ -32,6 +33,7 @@ export class PayInComponent implements OnInit {
private filterUploadMeta: UploadMetaModel = new UploadMetaModel({});
public filterLoan = new LoanModel({});
@Input() filter: PayInListFilterModel = new PayInListFilterModel({});
public state = new GridStateModel();
@Output() errorOccurred = new EventEmitter<string>();
@Output() Updated = new EventEmitter<PayInModel>();
@ViewChild('filterDialog', {static: true}) filterDialog: PopupIncomeFilterComponent;
@@ -98,6 +100,24 @@ export class PayInComponent implements OnInit {
);
}

public loadFilteredPayInList(): void {
this.loading = true;
this.pis.getFilteredPayInList(this.state).subscribe(
( resp: PayInListResult) => {
this.gridData.total = resp.total;
this.gridData.data = [];
resp.data.forEach(v => {
this.gridData.data.push(new PayInModelEx(v));
});
this.loading = false;
}, err => {
this.loading = false;
}, () => {
this.loading = false;
}
);
}

// Upload Filter
@Input() set uploadMeta(value: UploadMetaModel) {
this.filterUploadMeta = value;
@@ -316,12 +336,21 @@ export class PayInComponent implements OnInit {

public pageChange(event: PageChangeEvent): void {
this.filter.Skip = event.skip;
this.loadFilteredData();
// this.loadFilteredData();
}

public sortChange(sort: SortDescriptor[]): void {
this.filter.Sort = sort;
this.loadFilteredData();
// this.loadFilteredData();
}

public filterChange( filter: CompositeFilterDescriptor): void {
// console.log (filter, this.state.filter);
}
public dataStateChange(state: DataStateChangeEvent): void {
this.state = state;
this.loadFilteredPayInList();
console.log(state, this.state);
}

public onLoanChange(loan: LoanModel): void {

+ 2
- 2
src/app/service/auth-guard.service.ts Parādīt failu

@@ -15,7 +15,7 @@ export class AuthGuard implements CanActivate, CanActivateChild {
constructor(private authService: AuthService, private router: Router) { }

canActivate(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.authService.isAuthenticated()) {
return true;
} else {
@@ -24,7 +24,7 @@ export class AuthGuard implements CanActivate, CanActivateChild {
}

canActivateChild(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.canActivate(route, state);
}
}

+ 5
- 0
src/app/service/pay-in.service.ts Parādīt failu

@@ -4,6 +4,7 @@ import {PayInListFilterModel} from '../models/pay-in-list.filter.model';
import {HttpClient} from '@angular/common/http';
import {AuthService} from './auth.service';
import {PayInListResult} from '../models/pay-in-list-result.model';
import {DataStateChangeEvent} from '@progress/kendo-angular-grid';



@@ -14,4 +15,8 @@ export class PayInService {
public getPayInList(filter: PayInListFilterModel): Observable<PayInListResult> {
return this.http.post<PayInListResult>(this.auth.getUrl('pay-in-list/'), filter);
}

public getFilteredPayInList(state: DataStateChangeEvent): Observable<PayInListResult> {
return this.http.post<PayInListResult>(this.auth.getUrl('pay-in-filtered-list/'), state);
}
}

+ 23
- 6
src/app/service/session.service.ts Parādīt failu

@@ -15,6 +15,7 @@ export class SessionService {
loginResult = new EventEmitter <ApiV1LoginResponse>();
logoutEvent = new EventEmitter <ApiV1LoginResponse>();
private machineId = localStorage.getItem('mid') || '';
private socketId = ''; // only lives in memory
debouncedLocalStorageMonitor = debounce( this.localStorageChange, 1000); // to avoid to frequent local storage changes

constructor(private config: AppConfig, private http: HttpClient,
@@ -41,9 +42,10 @@ export class SessionService {


public login( resp: ApiV1LoginResponse): void{
// console.log( 'login in session', this);
this.loggedIn = new ApiV1LoginResponse(resp);

if ( this.MachineId !== '' && resp.machineId !== '' && this.MachineId !== resp.machineId ) {
if ( this.MachineId === '' || (resp.machineId !== '' && this.MachineId !== resp.machineId )) {
this.MachineId = resp.machineId; // update machine id
}

@@ -59,10 +61,12 @@ export class SessionService {

private localStorageChange(event: StorageEvent): void {
console.log('local storage change', event);
const sfm: ApiV1LoginResponse = JSON.parse(localStorage.getItem(this.config.storageKey));
if ( sfm && sfm.session && sfm.User && sfm.User.Id && this.loggedIn.User.Id) {
if ( sfm.session === this.loggedIn.session && sfm.User.Id !== this.loggedIn.User.Id){
this.logoutWithoutPersistingStorage(); // silently logout without touching any storage
if ( event.key === this.config.storageKey ){
const newSigin: ApiV1LoginResponse = JSON.parse(localStorage.getItem(this.config.storageKey));
if ( newSigin && newSigin.session && newSigin.User && newSigin.User.Id && this.loggedIn.User.Id) {
if ( newSigin.machineId === this.loggedIn.machineId && newSigin.User.Id !== this.loggedIn.User.Id){
this.logoutWithoutPersistingStorage(); // silently logout without touching any storage
}
}
}
}
@@ -71,7 +75,6 @@ export class SessionService {
localStorage.setItem(this.config.storageKey, JSON.stringify(this.loggedIn));
}


public isAdmin(): boolean {
return this.loggedIn.role === 'admin';
}
@@ -190,4 +193,18 @@ export class SessionService {
return this.loggedIn.session || '';
}

public set SessionId(sid: string){
if ( this.loggedIn.session === '' || this.loggedIn.session !== sid ){
this.loggedIn.session = sid;
this.saveSessionInfo();
this.ws.SessionId = sid;
}
}

public get SocketId(): string{
return this.socketId;
}
public set SocketId(socketId: string ) {
this.socketId = socketId;
}
}

+ 7
- 0
src/app/websocket.ts Parādīt failu

@@ -10,9 +10,11 @@ export class WebSocketService extends Subject<string>{

private connected = false;
private sessionId = '';
private socketId = '';
public ws: WebSocket;
private readonly url: string;
public LoginEvent: Subject<WsLoginEventModel>;
public assignSocketIdEvent: Subject<string>;

// cannot have session as service, as session use us as building block
constructor(private config: AppConfig) {
@@ -20,6 +22,7 @@ export class WebSocketService extends Subject<string>{
this.url = config.apiWsUrl;
this.startWebsocket();
this.LoginEvent = new Subject<WsLoginEventModel>();
this.assignSocketIdEvent = new Subject<string>();
}

private startWebsocket(): void {
@@ -72,6 +75,10 @@ export class WebSocketService extends Subject<string>{
if ( e.T === 'login' || e.T === 'logout' ){
this.LoginEvent.next(new WsLoginEventModel(e));
}
if (e.T === 'assign-socketId') {
this.socketId = e.socketId;
this.assignSocketIdEvent.next(e.socketId);
}
}catch (e) {
console.log(e);
}

+ 1
- 1
tsconfig.json Parādīt failu

@@ -10,7 +10,7 @@
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es5",
"target": "Es6",
"module": "es2020",
"lib": [
"es2018",

Notiek ielāde…
Atcelt
Saglabāt