mirror of
https://github.com/valitydev/fraudbusters-ui.git
synced 2024-11-06 16:45:19 +00:00
Refactor lists
This commit is contained in:
parent
b5369f9a6f
commit
5bd6f87afe
@ -2,8 +2,6 @@ import { ListType } from '../../../shared/constants/list-type';
|
||||
import { SearchParams } from '../../../shared/model/search-params';
|
||||
|
||||
export interface SearchListsParams extends SearchParams {
|
||||
searchValue: string;
|
||||
sortFieldValue: string;
|
||||
listNames: string[];
|
||||
listNames?: string[];
|
||||
listType: ListType;
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
<fb-wb-list [listType]="listType" [isCounting]="true"></fb-wb-list>
|
||||
<fb-wb-list [listType]="listType"></fb-wb-list>
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { PaymentReference } from '../../../api/fb-management/swagger-codegen/model/paymentReference';
|
||||
import { SortOrder } from '../../constants/sort-order';
|
||||
|
||||
export enum ActionType {
|
||||
CreateReference = 'createReference',
|
||||
EditReference = 'editReference',
|
||||
RemoveReference = 'removeReference',
|
||||
SortReferences = 'sortReferences',
|
||||
GoToTemplate = 'goToTemplate',
|
||||
}
|
||||
|
||||
export interface Action {
|
||||
type: ActionType;
|
||||
reference?: PaymentReference;
|
||||
sortDirection?: SortOrder;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<table mat-table [dataSource]="references" class="fb-table" matSort (matSortChange)="sort($event)">
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header class="th">ID</th>
|
||||
<td mat-cell *matCellDef="let element" class="td">{{ element.id }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="updatedAt">
|
||||
<th mat-header-cell *matHeaderCellDef class="th updatedAt">Updated At</th>
|
||||
<td mat-cell *matCellDef="let element" class="td updatedAt">
|
||||
{{ element.lastUpdateDate | date: 'dd.MM.yyyy HH:mm:ss' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="templateID">
|
||||
<th mat-header-cell *matHeaderCellDef class="th">Template ID</th>
|
||||
<td mat-cell *matCellDef="let element" class="td">
|
||||
{{ element.templateId }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="partyID">
|
||||
<th mat-header-cell *matHeaderCellDef class="th">Party ID</th>
|
||||
<td mat-cell *matCellDef="let element" class="td">
|
||||
{{ element.partyId }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="shopID">
|
||||
<th mat-header-cell *matHeaderCellDef class="th">Shop ID</th>
|
||||
<td mat-cell *matCellDef="let element" class="td">
|
||||
{{ element.shopId }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="th"></th>
|
||||
<td mat-cell *matCellDef="let element" class="td">
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<!-- <button mat-menu-item (click)="editTemplate(element)">-->
|
||||
<!-- <span>Edit reference</span>-->
|
||||
<!-- </button>-->
|
||||
<button mat-menu-item (click)="removeReference(element)">
|
||||
<span>Remove reference</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="goToTempalte(element)">
|
||||
<span>Go to template</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
@ -1,16 +0,0 @@
|
||||
:host {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.th,
|
||||
.td {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.updatedAt {
|
||||
min-width: 130px;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
|
||||
import { PaymentReference } from '../../../../api/fb-management/swagger-codegen/model/paymentReference';
|
||||
import { SortOrder } from '../../../constants/sort-order';
|
||||
import { Action, ActionType } from '../action';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'payment-template-references-table.component.html',
|
||||
selector: 'fb-payment-template-references-table',
|
||||
styleUrls: ['payment-template-references-table.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PaymentTemplateReferencesTableComponent {
|
||||
@Output()
|
||||
action: EventEmitter<Action> = new EventEmitter();
|
||||
|
||||
@Input()
|
||||
references: PaymentReference[];
|
||||
|
||||
displayedColumns: string[] = ['id', 'templateID', 'partyID', 'shopID', 'updatedAt', 'actions'];
|
||||
|
||||
sort(sort: Sort): void {
|
||||
switch (sort.direction) {
|
||||
case 'asc':
|
||||
this.action.emit({ type: ActionType.SortReferences, sortDirection: SortOrder.Asc });
|
||||
break;
|
||||
case 'desc':
|
||||
this.action.emit({ type: ActionType.SortReferences, sortDirection: SortOrder.DESC });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
removeReference(reference: PaymentReference): void {
|
||||
this.action.emit({ type: ActionType.RemoveReference, reference });
|
||||
}
|
||||
|
||||
editReference(reference: PaymentReference) {
|
||||
this.action.emit({ type: ActionType.EditReference, reference });
|
||||
}
|
||||
|
||||
goToTempalte(reference: PaymentReference) {
|
||||
this.action.emit({ type: ActionType.GoToTemplate, reference });
|
||||
}
|
||||
}
|
@ -10,10 +10,7 @@ import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
import { PaymentTemplateReferencesTableComponent } from './payment-template-references-table/payment-template-references-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PaymentTemplateReferencesTableComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexModule,
|
||||
@ -26,6 +23,5 @@ import { PaymentTemplateReferencesTableComponent } from './payment-template-refe
|
||||
MatMenuModule,
|
||||
MatButtonModule,
|
||||
],
|
||||
exports: [PaymentTemplateReferencesTableComponent],
|
||||
})
|
||||
export class TemplateReferencesModule {}
|
||||
|
13
src/app/shared/components/wb-list/action.ts
Normal file
13
src/app/shared/components/wb-list/action.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { SortOrder } from '../../constants/sort-order';
|
||||
|
||||
export enum ActionType {
|
||||
CreateRow = 'createRow',
|
||||
RemoveRow = 'removeRow',
|
||||
SortRow = 'sortRow',
|
||||
}
|
||||
|
||||
export interface Action {
|
||||
type: ActionType;
|
||||
rowId?: string;
|
||||
sortDirection?: SortOrder;
|
||||
}
|
@ -4,12 +4,12 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { CountInfo } from '../../../../api/fb-management/swagger-codegen/model/countInfo';
|
||||
import { PaymentCountInfo } from '../../../../api/fb-management/swagger-codegen/model/paymentCountInfo';
|
||||
import { PaymentListRecord } from '../../../../api/fb-management/swagger-codegen/model/paymentListRecord';
|
||||
import { PaymentListsService } from '../../../../api/payments/lists/payment-lists.service';
|
||||
import { ListType } from '../../../constants/list-type';
|
||||
import { ErrorHandlerService } from '../../../services/utils/error-handler.service';
|
||||
import { CountInfo } from '../../../../../api/fb-management/swagger-codegen/model/countInfo';
|
||||
import { PaymentCountInfo } from '../../../../../api/fb-management/swagger-codegen/model/paymentCountInfo';
|
||||
import { PaymentListRecord } from '../../../../../api/fb-management/swagger-codegen/model/paymentListRecord';
|
||||
import { PaymentListsService } from '../../../../../api/payments/lists/payment-lists.service';
|
||||
import { ListType } from '../../../../constants/list-type';
|
||||
import { ErrorHandlerService } from '../../../../services/utils/error-handler.service';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-add-row-list',
|
@ -3,11 +3,11 @@ import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
import { WbListRecord } from '../../../../api/fb-management/swagger-codegen/model/wbListRecord';
|
||||
import { PaymentListsService } from '../../../../api/payments/lists/payment-lists.service';
|
||||
import { ListType } from '../../../constants/list-type';
|
||||
import { OperationType } from '../../../constants/operation-type';
|
||||
import { ErrorHandlerService } from '../../../services/utils/error-handler.service';
|
||||
import { WbListRecord } from '../../../../../api/fb-management/swagger-codegen/model/wbListRecord';
|
||||
import { PaymentListsService } from '../../../../../api/payments/lists/payment-lists.service';
|
||||
import { ListType } from '../../../../constants/list-type';
|
||||
import { OperationType } from '../../../../constants/operation-type';
|
||||
import { ErrorHandlerService } from '../../../../services/utils/error-handler.service';
|
||||
|
||||
export interface DialogData {
|
||||
listRecord: WbListRecord;
|
@ -0,0 +1,10 @@
|
||||
<form fxLayout fxLayoutGap="16px" [formGroup]="form">
|
||||
<mat-form-field class="multi-select" appearance="outline" *ngIf="listNames$ | async as listNames">
|
||||
<mat-select formControlName="types" multiple>
|
||||
<mat-option *ngFor="let name of listNames" value="{{ name }}">{{ name }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<input matInput placeholder="Search" formControlName="searchQuery" type="string" autocomplete="false" />
|
||||
</mat-form-field>
|
||||
</form>
|
@ -0,0 +1,40 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { debounceTime, map, take } from 'rxjs/operators';
|
||||
|
||||
import { removeEmptyProperties } from '../../../../utils/remove-empty-properties';
|
||||
import { Filter } from '../../model/filter';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-wb-list-search',
|
||||
templateUrl: 'wb-list-search.component.html',
|
||||
})
|
||||
export class WbListSearchComponent implements OnInit {
|
||||
@Output() valueChanges: EventEmitter<Filter> = new EventEmitter();
|
||||
|
||||
@Input() listNames$: Observable<string[]>;
|
||||
|
||||
form: FormGroup = this.fb.group({
|
||||
searchQuery: '',
|
||||
types: [],
|
||||
});
|
||||
|
||||
constructor(private route: ActivatedRoute, private router: Router, private fb: FormBuilder) {
|
||||
this.form.valueChanges.pipe(debounceTime(600), map(removeEmptyProperties)).subscribe((v) => {
|
||||
this.router.navigate([location.pathname], { queryParams: v });
|
||||
this.valueChanges.emit({ searchValue: v.searchQuery, typeChanges: v.types });
|
||||
});
|
||||
this.route.queryParams.pipe(take(1)).subscribe((v) => this.form.patchValue(v));
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.listNames$.subscribe((value) =>
|
||||
this.form.setValue({
|
||||
searchQuery: '',
|
||||
types: value,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<div fxLayout fxLayoutAlign="end" [fxLayoutGap]="layoutGapM">
|
||||
<button mat-button color="warn" (click)="deleteItem.emit(id)">Remove</button>
|
||||
</div>
|
@ -0,0 +1,18 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
||||
|
||||
import { LAYOUT_GAP_M } from '../../../../../../../tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-actions',
|
||||
templateUrl: 'actions.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ActionsComponent {
|
||||
@Input()
|
||||
id: string;
|
||||
|
||||
@Output()
|
||||
deleteItem = new EventEmitter<string>();
|
||||
|
||||
constructor(@Inject(LAYOUT_GAP_M) public layoutGapM: string) {}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<fb-list-header>
|
||||
<div class="fb-body-2" fxFlex>List name</div>
|
||||
<div class="fb-body-2" fxFlex>Party id</div>
|
||||
<div class="fb-body-2" fxFlex>Shop id</div>
|
||||
<div class="fb-body-2" fxFlex>Value</div>
|
||||
<div class="fb-body-2" fxFlex="168px">Inserted At</div>
|
||||
</fb-list-header>
|
@ -0,0 +1,12 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
|
||||
import { LAYOUT_GAP_M } from '../../../../../../../tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-wb-rows-header',
|
||||
templateUrl: 'wb-rows-header.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class WbRowsHeaderComponent {
|
||||
constructor(@Inject(LAYOUT_GAP_M) public layoutGapM: string) {}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<mat-card class="fb-list-item" fxLayout fxFlexFill fxLayoutAlign="center center" [fxLayoutGap]="layoutGapM">
|
||||
<div class="fb-body-2" fxFlex>{{ listRecord.listName }}</div>
|
||||
<div class="fb-body-2" fxFlex>{{ listRecord.partyId }}</div>
|
||||
<div class="fb-body-2" fxFlex>{{ listRecord.shopId }}</div>
|
||||
<div class="fb-body-2" fxFlex>{{ listRecord.value }}</div>
|
||||
<div class="fb-body-2" fxFlex="160px">{{ listRecord.insertTime | date: 'yyyy-MM-dd HH:mm:ss' }}</div>
|
||||
<ng-container>
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="deleteItem.emit(listRecord.id)">
|
||||
<span>Remove row</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
</mat-card>
|
@ -0,0 +1,7 @@
|
||||
.fb-list-item {
|
||||
height: 48px !important;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
word-wrap: anywhere;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
||||
|
||||
import { WbListRecord } from '../../../../../../../api/fb-management/swagger-codegen/model/wbListRecord';
|
||||
import { LAYOUT_GAP_M, LAYOUT_GAP_S } from '../../../../../../../tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-wb-rows-item',
|
||||
templateUrl: 'wb-rows-item.component.html',
|
||||
styleUrls: ['wb-rows-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class WbRowsItemComponent {
|
||||
@Input()
|
||||
listRecord: WbListRecord;
|
||||
|
||||
@Output()
|
||||
deleteItem = new EventEmitter<string>();
|
||||
|
||||
constructor(@Inject(LAYOUT_GAP_S) public layoutGapS: string, @Inject(LAYOUT_GAP_M) public layoutGapM: string) {}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export * from './wb-rows-list.module';
|
@ -0,0 +1,6 @@
|
||||
<div fxLayout="column" [fxLayoutGap]="layoutGapM">
|
||||
<fb-wb-rows-header></fb-wb-rows-header>
|
||||
<div *ngFor="let record of listRecords" fxLayout="column" [fxLayoutGap]="layoutGapM">
|
||||
<fb-wb-rows-item [listRecord]="record" (deleteItem)="deleteItem.emit($event)"></fb-wb-rows-item>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,19 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
||||
|
||||
import { WbListRecord } from '../../../../../api/fb-management/swagger-codegen/model/wbListRecord';
|
||||
import { LAYOUT_GAP_M } from '../../../../../tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-wb-rows-list',
|
||||
templateUrl: 'wb-rows-list.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class WbRowsListComponent {
|
||||
@Input()
|
||||
listRecords: WbListRecord[];
|
||||
|
||||
@Output()
|
||||
deleteItem = new EventEmitter<string>();
|
||||
|
||||
constructor(@Inject(LAYOUT_GAP_M) public layoutGapM: string) {}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexModule } from '@angular/flex-layout';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule, _MatMenuDirectivesModule } from '@angular/material/menu';
|
||||
|
||||
import { ListHeaderModule } from '../../../../../shared/components/list-header';
|
||||
import { SharedPipesModule } from '../../../../../shared/pipes';
|
||||
import { ActionsComponent } from './components/actions/actions.component';
|
||||
import { WbRowsHeaderComponent } from './components/wb-rows-header/wb-rows-header.component';
|
||||
import { WbRowsItemComponent } from './components/wb-rows-item/wb-rows-item.component';
|
||||
import { WbRowsListComponent } from './wb-rows-list.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexModule,
|
||||
MatExpansionModule,
|
||||
MatDividerModule,
|
||||
SharedPipesModule,
|
||||
MatButtonModule,
|
||||
ListHeaderModule,
|
||||
MatButtonModule,
|
||||
_MatMenuDirectivesModule,
|
||||
MatIconModule,
|
||||
MatMenuModule,
|
||||
ListHeaderModule,
|
||||
MatCardModule,
|
||||
MatDividerModule,
|
||||
],
|
||||
declarations: [
|
||||
WbRowsListComponent,
|
||||
WbRowsHeaderComponent,
|
||||
WbRowsItemComponent,
|
||||
ActionsComponent,
|
||||
WbRowsItemComponent,
|
||||
WbRowsHeaderComponent,
|
||||
],
|
||||
exports: [WbRowsListComponent],
|
||||
})
|
||||
export class WbRowsListModule {}
|
4
src/app/shared/components/wb-list/model/filter.ts
Normal file
4
src/app/shared/components/wb-list/model/filter.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface Filter {
|
||||
searchValue: string;
|
||||
typeChanges: string[];
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { WbListRecord } from '../../../../api/fb-management/swagger-codegen/model/wbListRecord';
|
||||
import { PaymentListsService } from '../../../../api/payments/lists';
|
||||
import { ConfigService } from '../../../../config';
|
||||
import { ListType } from '../../../constants/list-type';
|
||||
import { SortOrder } from '../../../constants/sort-order';
|
||||
import { booleanDebounceTime } from '../../../operators';
|
||||
import { FetchResult, PartialFetcher } from '../../../utils/partial-fetcher';
|
||||
|
||||
export interface FetchRowsParams {
|
||||
searchValue?: string;
|
||||
sortOrder?: SortOrder;
|
||||
pageSize?: number;
|
||||
listNames?: string[];
|
||||
listType: ListType;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class FetchWbListService extends PartialFetcher<WbListRecord, FetchRowsParams> {
|
||||
inProgress$ = this.doAction$.pipe(booleanDebounceTime(), shareReplay(1));
|
||||
private pageSize = this.configService.pageSize;
|
||||
|
||||
constructor(private paymentListsService: PaymentListsService, private configService: ConfigService) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected fetch(
|
||||
params: FetchRowsParams,
|
||||
lastId?: string,
|
||||
listTypeNew?: ListType,
|
||||
listNamesNew?: string[]
|
||||
): Observable<FetchResult<WbListRecord>> {
|
||||
const { searchValue, sortOrder, pageSize, listType, listNames } = params;
|
||||
return this.paymentListsService.findListRows({
|
||||
size: pageSize ? pageSize : this.pageSize,
|
||||
sortOrder: sortOrder || SortOrder.Asc,
|
||||
...(searchValue ? { searchValue } : {}),
|
||||
...(lastId ? { lastId } : {}),
|
||||
listType: listType ? listType : listTypeNew,
|
||||
listNames: listNames ? listNames : listNamesNew,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { combineLatest, merge, NEVER, of, Subject } from 'rxjs';
|
||||
import { catchError, filter, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { PaymentListsService } from '../../../../api/payments/lists';
|
||||
import { progress } from '../../../../shared/operators';
|
||||
import { ConfirmActionDialogComponent } from '../../confirm-action-dialog';
|
||||
|
||||
export interface RemoveListRowParams {
|
||||
rowId: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class RemoveWbListComponentService {
|
||||
private removeRow$ = new Subject<RemoveListRowParams>();
|
||||
private hasError$ = new Subject();
|
||||
|
||||
removed$ = this.removeRow$.pipe(
|
||||
switchMap((params) =>
|
||||
combineLatest([
|
||||
of(params),
|
||||
this.dialog
|
||||
.open(ConfirmActionDialogComponent, { data: { title: `Remove row ${params.rowId}?` } })
|
||||
.afterClosed()
|
||||
.pipe(filter((r) => r === 'confirm')),
|
||||
])
|
||||
),
|
||||
switchMap(([params]) =>
|
||||
this.paymentListsService.deleteListRow(params.rowId).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
this.snackBar.open(`${error.status}: ${error.message}`, 'OK', {
|
||||
duration: 1500,
|
||||
});
|
||||
this.hasError$.next();
|
||||
return NEVER;
|
||||
})
|
||||
)
|
||||
),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
inProgress$ = progress(this.removeRow$, merge(this.hasError$, this.removed$));
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private paymentListsService: PaymentListsService,
|
||||
private snackBar: MatSnackBar
|
||||
) {}
|
||||
|
||||
remove(params: RemoveListRowParams) {
|
||||
this.removeRow$.next(params);
|
||||
}
|
||||
}
|
@ -1,70 +1,24 @@
|
||||
<div fxLayout="column" [fxLayoutGap]="layoutGapM">
|
||||
<div fxLayout fxLayoutAlign="space-between center">
|
||||
<div fxLayoutGap="10px grid">
|
||||
<mat-form-field class="multi-select" appearance="outline">
|
||||
<mat-select [(value)]="this.selectedListNames" (selectionChange)="selectionChange()" multiple>
|
||||
<mat-option *ngFor="let name of listNames" value="{{ name }}">{{ name }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<input matInput placeholder="Search" [formControl]="searchValue" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<button mat-button color="primary" (click)="navigateToNew()">CREATE RECORD</button>
|
||||
<fb-wb-list-search (valueChanges)="search($event)" [listNames$]="listNames$"></fb-wb-list-search>
|
||||
<button mat-button color="primary" (click)="createRow()">CREATE RECORD</button>
|
||||
</div>
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<table mat-table [dataSource]="listsRows" class="fb-table" matSort (matSortChange)="sortData($event)">
|
||||
<ng-container matColumnDef="listName">
|
||||
<th mat-header-cell *matHeaderCellDef>List name</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.listName }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="partyId">
|
||||
<th mat-header-cell *matHeaderCellDef>PartyId</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.partyId }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="shopId">
|
||||
<th mat-header-cell *matHeaderCellDef>ShopId</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.shopId }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="identityId">
|
||||
<th mat-header-cell *matHeaderCellDef>IdentityId</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.identityId }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef>Value</th>
|
||||
<td mat-cell *matCellDef="let element">{{ element.value }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="insertTime">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Insert time</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
{{ element.insertTime | date: 'dd-MM-yyyy hh:mm:ss' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="info" *ngIf="isCounting">
|
||||
<th mat-header-cell *matHeaderCellDef>Info</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<mat-icon matTooltip="{{ element.rowInfo }}">info</mat-icon>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="edit">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button mat-icon-button color="warn" (click)="openDialog(element)">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns | async"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns | async"></tr>
|
||||
</table>
|
||||
<mat-toolbar *ngIf="isLoadMore">
|
||||
<mat-toolbar-row class="justify-content-center">
|
||||
<button mat-stroked-button color="primary" (click)="loadMore()">
|
||||
<span class="material-icons">more_horiz</span>
|
||||
</button>
|
||||
</mat-toolbar-row>
|
||||
</mat-toolbar>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<div *ngIf="rows$ | async as rows">
|
||||
<fb-wb-rows-list
|
||||
*ngIf="rows.length; else Empty"
|
||||
[listRecords]="rows"
|
||||
(deleteItem)="removeRow($event)"
|
||||
></fb-wb-rows-list>
|
||||
</div>
|
||||
<fb-show-more-panel
|
||||
*ngIf="hasMore$ | async"
|
||||
[isLoading]="inProgress$ | async"
|
||||
(showMore)="fetchMore()"
|
||||
></fb-show-more-panel>
|
||||
<div *ngIf="inProgress$ | async" fxLayout fxLayoutAlign="center">
|
||||
<mat-progress-spinner color="primary" mode="indeterminate" diameter="48"></mat-progress-spinner>
|
||||
</div>
|
||||
<ng-template #Empty>
|
||||
<fb-empty-search-result *ngIf="!(inProgress$ | async)"></fb-empty-search-result>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
@ -1,21 +1,16 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
import { Router } from '@angular/router';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { PaymentListsService } from '../../../api/payments/lists/payment-lists.service';
|
||||
import { ConfigService } from '../../../config';
|
||||
import { PaymentListsService } from '../../../api/payments/lists';
|
||||
import { LAYOUT_GAP_M } from '../../../tokens';
|
||||
import { ListType } from '../../constants/list-type';
|
||||
import { SortOrder } from '../../constants/sort-order';
|
||||
import { ErrorHandlerService } from '../../services/utils/error-handler.service';
|
||||
import { SearchFieldService } from '../../services/utils/search-field.service';
|
||||
import { RemoveRowListDialogComponent } from './remove-row-list/remove-row-list-dialog.component';
|
||||
import { Action, ActionType } from './action';
|
||||
import { Filter } from './model/filter';
|
||||
import { FetchWbListService } from './services/fetch-wb-list.service';
|
||||
import { RemoveWbListComponentService } from './services/remove-wb-list.service';
|
||||
|
||||
@Component({
|
||||
selector: 'fb-wb-list',
|
||||
@ -24,116 +19,68 @@ import { RemoveRowListDialogComponent } from './remove-row-list/remove-row-list-
|
||||
})
|
||||
export class WbListComponent implements OnInit {
|
||||
@Input() listType: ListType;
|
||||
@Input() isCounting = false;
|
||||
|
||||
listsRows = [];
|
||||
searchValue: FormControl = new FormControl('');
|
||||
listNames: string[] = [];
|
||||
selectedListNames: string[] = [];
|
||||
isLoadMore = false;
|
||||
displayedColumns = new ReplaySubject<string[]>();
|
||||
sortType = SortOrder.Desc;
|
||||
paymentColumns = ['listName', 'partyId', 'shopId', 'value', 'insertTime'];
|
||||
|
||||
private size = this.configService.pageSize;
|
||||
rows$ = this.fetchWbListService.searchResult$;
|
||||
listNames$: Observable<string[]>;
|
||||
inProgress$ = this.fetchWbListService.inProgress$;
|
||||
hasMore$ = this.fetchWbListService.hasMore$;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private errorHandlerService: ErrorHandlerService,
|
||||
private searchFieldService: SearchFieldService,
|
||||
private listService: PaymentListsService,
|
||||
private fetchWbListService: FetchWbListService,
|
||||
private removeWbListComponentService: RemoveWbListComponentService,
|
||||
private snackBar: MatSnackBar,
|
||||
private dialog: MatDialog,
|
||||
private configService: ConfigService,
|
||||
private errorHandlerService: ErrorHandlerService,
|
||||
private listService: PaymentListsService,
|
||||
@Inject(LAYOUT_GAP_M) public layoutGapM: string
|
||||
) {
|
||||
this.displayedColumns.next([]);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getListNames();
|
||||
this.searchValue.valueChanges.pipe(debounceTime(300)).subscribe(() => {
|
||||
this.search();
|
||||
this.removeWbListComponentService.removed$.subscribe((id) => {
|
||||
this.snackBar.open(`WbList ${id} has been deleted`, 'OK', {
|
||||
duration: 1500,
|
||||
});
|
||||
this.fetchWbListService.search({ listType: this.listType });
|
||||
});
|
||||
}
|
||||
|
||||
selectionChange(): void {
|
||||
this.displayedColumns.next(this.initColumns(this.paymentColumns));
|
||||
this.search();
|
||||
action(action: Action) {
|
||||
switch (action.type) {
|
||||
case ActionType.CreateRow:
|
||||
this.router.navigate([`/list/${this.listType}/new`]);
|
||||
break;
|
||||
case ActionType.RemoveRow:
|
||||
this.removeWbListComponentService.remove({
|
||||
rowId: action.rowId,
|
||||
});
|
||||
break;
|
||||
case ActionType.SortRow:
|
||||
this.fetchWbListService.search({ sortOrder: action.sortDirection, listType: this.listType });
|
||||
break;
|
||||
default:
|
||||
console.error('Wrong list row action.');
|
||||
}
|
||||
}
|
||||
|
||||
getListNames(): void {
|
||||
this.listService.getNames(this.listType).subscribe(
|
||||
(names) => {
|
||||
this.listNames = names;
|
||||
this.selectedListNames = this.listNames;
|
||||
this.selectionChange();
|
||||
},
|
||||
(error: HttpErrorResponse) => {
|
||||
this.errorHandlerService.handleError(error, this.snackBar);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
search(): void {
|
||||
this.searchWithSort(null, this.sortType, null);
|
||||
}
|
||||
|
||||
navigateToNew(): void {
|
||||
createRow() {
|
||||
this.router.navigate([`/list/${this.listType}/new`]);
|
||||
}
|
||||
|
||||
sortData(sort: Sort): void {
|
||||
this.sortType = sort.direction === 'asc' ? SortOrder.Asc : SortOrder.Desc;
|
||||
this.search();
|
||||
removeRow(rowId: string) {
|
||||
this.removeWbListComponentService.remove({ rowId });
|
||||
}
|
||||
|
||||
openDialog(listRecordRow): void {
|
||||
const dialogRef = this.dialog.open(RemoveRowListDialogComponent, {
|
||||
width: '350px',
|
||||
data: { listRecord: listRecordRow, listType: this.listType },
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
this.search();
|
||||
search(filter?: Filter) {
|
||||
this.fetchWbListService.search({
|
||||
searchValue: filter.searchValue,
|
||||
listType: this.listType,
|
||||
listNames: filter.typeChanges,
|
||||
});
|
||||
}
|
||||
|
||||
loadMore(): void {
|
||||
this.searchWithSort(
|
||||
this.listsRows[this.listsRows.length - 1].id,
|
||||
this.sortType,
|
||||
this.listsRows[this.listsRows.length - 1].insertTime
|
||||
);
|
||||
fetchMore() {
|
||||
this.fetchWbListService.fetchMore();
|
||||
}
|
||||
|
||||
private initColumns(columns: string[]): string[] {
|
||||
return this.isCounting ? columns.concat(['info', 'edit']) : columns.concat(['edit']);
|
||||
}
|
||||
|
||||
private searchWithSort(lastInListName, sortOrder: SortOrder, sortFieldValueNew): void {
|
||||
this.listService
|
||||
.findListRows({
|
||||
searchValue: this.searchFieldService.formatField(this.searchValue.value),
|
||||
lastId: lastInListName,
|
||||
size: this.size,
|
||||
sortOrder: sortOrder ? sortOrder : SortOrder.Asc,
|
||||
sortFieldValue: sortFieldValueNew,
|
||||
listNames: this.selectedListNames,
|
||||
listType: this.listType,
|
||||
})
|
||||
.subscribe(
|
||||
(response) => {
|
||||
if (!lastInListName) {
|
||||
this.listsRows = response.result;
|
||||
} else {
|
||||
this.listsRows = this.listsRows.concat(response.result);
|
||||
}
|
||||
this.isLoadMore = this.listsRows.length < response.count;
|
||||
},
|
||||
(error: HttpErrorResponse) => {
|
||||
this.errorHandlerService.handleError(error, this.snackBar);
|
||||
}
|
||||
);
|
||||
ngOnInit(): void {
|
||||
this.listNames$ = this.listService.getNames(this.listType);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
@ -27,12 +28,18 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { PaymentListsService } from '../../../api/payments/lists/payment-lists.service';
|
||||
import { ErrorHandlerService } from '../../services/utils/error-handler.service';
|
||||
import { SearchFieldService } from '../../services/utils/search-field.service';
|
||||
import { AddRowListComponent } from './add-row-list/add-row-list.component';
|
||||
import { RemoveRowListDialogComponent } from './remove-row-list/remove-row-list-dialog.component';
|
||||
import { EmptySearchResultModule } from '../empty-search-result';
|
||||
import { ShowMorePanelModule } from '../show-more-panel';
|
||||
import { AddRowListComponent } from './components/add-row-list/add-row-list.component';
|
||||
import { RemoveRowListDialogComponent } from './components/remove-row-list/remove-row-list-dialog.component';
|
||||
import { WbListSearchComponent } from './components/wb-list-search/wb-list-search.component';
|
||||
import { WbRowsListModule } from './components/wb-rows-list';
|
||||
import { FetchWbListService } from './services/fetch-wb-list.service';
|
||||
import { RemoveWbListComponentService } from './services/remove-wb-list.service';
|
||||
import { WbListComponent } from './wb-list.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [WbListComponent, RemoveRowListDialogComponent, AddRowListComponent],
|
||||
declarations: [WbListComponent, RemoveRowListDialogComponent, AddRowListComponent, WbListSearchComponent],
|
||||
exports: [WbListComponent, AddRowListComponent, RemoveRowListDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@ -58,7 +65,17 @@ import { WbListComponent } from './wb-list.component';
|
||||
ReactiveFormsModule,
|
||||
FlexLayoutModule,
|
||||
FormsModule,
|
||||
ShowMorePanelModule,
|
||||
EmptySearchResultModule,
|
||||
MatProgressSpinnerModule,
|
||||
WbRowsListModule,
|
||||
],
|
||||
providers: [
|
||||
SearchFieldService,
|
||||
PaymentListsService,
|
||||
ErrorHandlerService,
|
||||
FetchWbListService,
|
||||
RemoveWbListComponentService,
|
||||
],
|
||||
providers: [SearchFieldService, PaymentListsService, ErrorHandlerService],
|
||||
})
|
||||
export class WbListModule {}
|
||||
|
@ -26,7 +26,6 @@ export abstract class PartialFetcher<R, P> {
|
||||
readonly doAction$: Observable<boolean>;
|
||||
readonly doSearchAction$: Observable<boolean>;
|
||||
readonly errors$ = new Subject();
|
||||
|
||||
private action$ = new Subject<FetchAction<P>>();
|
||||
|
||||
constructor(debounceActionTime: number = 300) {
|
||||
|
Loading…
Reference in New Issue
Block a user