Refactor lists

This commit is contained in:
Kostya Struga 2022-06-24 12:38:02 +03:00
parent b5369f9a6f
commit 5bd6f87afe
33 changed files with 425 additions and 318 deletions

View File

@ -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;
}

View File

@ -1 +1 @@
<fb-wb-list [listType]="listType" [isCounting]="true"></fb-wb-list>
<fb-wb-list [listType]="listType"></fb-wb-list>

View File

@ -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;
}

View File

@ -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>

View File

@ -1,16 +0,0 @@
:host {
overflow-x: auto;
}
table {
width: 100%;
}
.th,
.td {
padding: 4px 8px;
}
.updatedAt {
min-width: 130px;
}

View File

@ -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 });
}
}

View File

@ -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 {}

View 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;
}

View File

@ -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',

View File

@ -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;

View File

@ -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>

View File

@ -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,
})
);
}
}

View File

@ -0,0 +1,3 @@
<div fxLayout fxLayoutAlign="end" [fxLayoutGap]="layoutGapM">
<button mat-button color="warn" (click)="deleteItem.emit(id)">Remove</button>
</div>

View File

@ -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) {}
}

View File

@ -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>

View File

@ -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) {}
}

View File

@ -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>

View File

@ -0,0 +1,7 @@
.fb-list-item {
height: 48px !important;
}
.wrap {
word-wrap: anywhere;
}

View File

@ -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) {}
}

View File

@ -0,0 +1 @@
export * from './wb-rows-list.module';

View File

@ -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>

View File

@ -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) {}
}

View File

@ -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 {}

View File

@ -0,0 +1,4 @@
export interface Filter {
searchValue: string;
typeChanges: string[];
}

View File

@ -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,
});
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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 {}

View File

@ -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) {