Add new page for historical data

This commit is contained in:
k.struzhkin 2021-07-23 17:30:54 +03:00
parent 1d33837ec0
commit dd6231e84c
14 changed files with 1110 additions and 767 deletions

View File

@ -501,20 +501,8 @@
"operationId": "filterGroups",
"tags": ["group"],
"parameters": [
{
"$ref": "#/components/parameters/sortOrder"
},
{
"$ref": "#/components/parameters/searchValue"
},
{
"$ref": "#/components/parameters/sortBy"
},
{
"$ref": "#/components/parameters/sortFieldValue"
},
{
"$ref": "#/components/parameters/size"
}
],
"responses": {
@ -1935,7 +1923,7 @@
"WbListRecord": {
"type": "object",
"properties": {
"groupId": {
"id": {
"type": "string"
},
"insertTime": {
@ -1989,7 +1977,8 @@
"type": "string"
},
"lastUpdateDate": {
"type": "string"
"type": "string",
"format": "date-time"
},
"modifiedByUser": {
"type": "string"
@ -2209,7 +2198,7 @@
},
"PaymentResponse": {
"type": "object",
"required": ["result", "continuationId"],
"required": ["result"],
"properties": {
"continuationId": {
"type": "string"

1563
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@
"e2e": "ng e2e",
"postinstall": "ngcc",
"swagger-codegen": "ts-node --project tools/tsconfig.json tools/swagger-codegen.ts",
"openapi-codegen": "ts-node --project tools/tsconfig.json tools/openapi-codegen.ts",
"codegen": "run-p swagger-codegen"
},
"private": true,

View File

@ -0,0 +1,23 @@
<div fxLayout="column" [fxLayoutGap]="layoutGapM">
<div fxLayout fxLayoutAlign="space-between center">
<fb-template-references-search (valueChanges)="search($event)"></fb-template-references-search>
</div>
<div *ngIf="payments$ | async as references; else Empty" fxLayout="column" [fxLayoutGap]="layoutGapM">
<fb-payment-references-list
*ngIf="references.length > 0; else Empty"
[references]="references"
></fb-payment-references-list>
<fb-show-more-panel
*ngIf="hasMore$ | async"
[isLoading]="inProgress$ | async"
(showMore)="fetchMore(references[references.length - 1].id)"
></fb-show-more-panel>
</div>
</div>
<ng-template #Empty>
<div *ngIf="inProgress$ | async" fxLayout fxLayoutAlign="center">
<mat-progress-spinner color="primary" mode="indeterminate" diameter="128"></mat-progress-spinner>
</div>
<fb-empty-search-result *ngIf="!(inProgress$ | async)"></fb-empty-search-result>
</ng-template>

View File

@ -0,0 +1,40 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { LAYOUT_GAP_M } from '../../../../tokens';
import { OperationType } from '../../../../shared/constants/operation-type';
import { FetchPaymentsService } from '../../services/fetch-payments.service';
@Component({
templateUrl: 'historical-payments-data.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [],
})
export class HistoricalPaymentsDataComponent {
payments$ = this.fetchPaymentsService.searchResult$;
inProgress$ = this.fetchPaymentsService.inProgress$;
hasMore$ = this.fetchPaymentsService.hasMore$;
constructor(
private router: Router,
private fetchPaymentsService: FetchPaymentsService,
@Inject(LAYOUT_GAP_M) public layoutGapM: string
) {}
search(searchValue: string) {
this.fetchPaymentsService.search({
type: OperationType.Payment,
searchValue,
isGlobal: false,
isDefault: false,
});
}
fetchMore(sortFieldValue: string) {
this.fetchPaymentsService.fetchMore({
type: OperationType.Payment,
sortFieldValue,
isGlobal: false,
isDefault: false,
});
}
}

View File

@ -0,0 +1,47 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AuthGuard, Roles } from '../../auth';
import { HistoricalDataComponent } from './historical-data.component';
import { HistoricalPaymentsDataComponent } from './components/payments/historical-payments-data.component';
@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: HistoricalDataComponent,
canActivate: [AuthGuard],
data: { roles: [Roles.fraudOfficer] },
children: [
{
path: 'payments',
component: HistoricalPaymentsDataComponent,
canActivate: [AuthGuard],
data: { roles: [Roles.fraudOfficer] },
},
{
path: 'refunds',
component: HistoricalPaymentsDataComponent,
canActivate: [AuthGuard],
data: { roles: [Roles.fraudOfficer] },
},
{
path: 'fraud-results',
component: HistoricalPaymentsDataComponent,
canActivate: [AuthGuard],
data: { roles: [Roles.fraudOfficer] },
},
{
path: 'chargebacks',
component: HistoricalPaymentsDataComponent,
canActivate: [AuthGuard],
data: { roles: [Roles.fraudOfficer] },
},
],
},
]),
],
exports: [RouterModule],
})
export class HistoricalDataRoutingModule {}

View File

@ -0,0 +1,16 @@
<div class="mat-headline">Transactions history</div>
<div fxLayout="column" fxLayoutGap="8px">
<nav mat-tab-nav-bar>
<a
mat-tab-link
*ngFor="let link of links"
[routerLink]="link.path"
routerLinkActive
#rla="routerLinkActive"
[active]="rla.isActive || hasActiveFragments(link.otherActiveUrlFragments)"
>
{{ link.name }}
</a>
</nav>
<router-outlet></router-outlet>
</div>

View File

@ -0,0 +1,39 @@
import { Component, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { hasActiveFragments } from 'src/app/shared/utils/has-active-fragments';
import { LAYOUT_GAP_S } from '../../tokens';
@Component({
templateUrl: 'historical-data.component.html',
})
export class HistoricalDataComponent {
links = [
{
path: 'payments',
name: 'Payments',
otherActiveUrlFragments: [],
},
{
path: 'refunds',
name: 'Refunds',
otherActiveUrlFragments: [],
},
{
path: 'fraud-results',
name: 'Fraud results',
otherActiveUrlFragments: [],
},
{
path: 'chargebacks',
name: 'Chargebacks',
otherActiveUrlFragments: [],
},
];
constructor(private router: Router, @Inject(LAYOUT_GAP_S) public layoutGapS: string) {}
hasActiveFragments(fragments: string[]): boolean {
const ulrFragments = this.router.url.split('/');
return hasActiveFragments(fragments, ulrFragments);
}
}

View File

@ -0,0 +1,65 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FlexModule } from '@angular/flex-layout';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatProgressBarModule } from '@angular/material/progress-bar';
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';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { ConfirmActionDialogModule } from '../../shared/components/confirm-action-dialog';
import { EmptySearchResultModule } from '../../shared/components/empty-search-result';
import { ShowMorePanelModule } from '../../shared/components/show-more-panel';
import { ReferencesRoutingModule } from '../references/references-routing.module';
import { HistoricalDataComponent } from './historical-data.component';
import { HistoricalPaymentsDataComponent } from './components/payments/historical-payments-data.component';
import { HistoricalDataRoutingModule } from './historical-data-routing.module';
import { TemplateReferencesModule } from '../../shared/components/template-references';
import { PaymentReferencesListModule } from '../../shared/components/payment-references-list';
import { FetchPaymentsService } from './services/fetch-payments.service';
import { PaymentReferencesService } from '../../api/payments/references';
@NgModule({
declarations: [HistoricalDataComponent, HistoricalPaymentsDataComponent],
imports: [
FlexModule,
MatButtonModule,
MatCardModule,
CommonModule,
MatProgressBarModule,
MatProgressSpinnerModule,
EmptySearchResultModule,
MatSelectModule,
ReactiveFormsModule,
HistoricalDataRoutingModule,
MatTabsModule,
CommonModule,
MatCardModule,
MatTableModule,
MatSortModule,
MatButtonModule,
MatIconModule,
MatToolbarModule,
MatMenuModule,
EmptySearchResultModule,
MatSnackBarModule,
MatFormFieldModule,
MatInputModule,
MatDividerModule,
ShowMorePanelModule,
TemplateReferencesModule,
PaymentReferencesListModule,
],
providers: [FetchPaymentsService, PaymentReferencesService],
})
export class HistoricalDataModule {}

View File

@ -0,0 +1 @@
export * from './historical-data.module';

View File

@ -0,0 +1,51 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
import { PaymentReference } from '../../../api/fb-management/swagger-codegen/model/paymentReference';
import { PaymentReferencesService } from '../../../api/payments/references';
import { ConfigService } from '../../../config';
import { OperationType } from '../../../shared/constants/operation-type';
import { SortOrder } from '../../../shared/constants/sort-order';
import { booleanDelay } from '../../../shared/operators';
import { FetchResult, PartialFetcher } from '../../../shared/utils/partial-fetcher';
import { Payment } from '../../../api/fb-management/swagger-codegen/model/payment';
export interface FetchPaymentParams {
type: OperationType;
isGlobal: boolean;
searchValue?: string;
sortOrder?: SortOrder;
size?: number;
isDefault?: boolean;
id?: string;
name?: string;
sortBy?: string;
sortFieldValue?: string;
}
@Injectable()
export class FetchPaymentsService extends PartialFetcher<Payment, FetchPaymentParams> {
inProgress$ = this.doAction$.pipe(booleanDelay(), shareReplay(1));
private SIZE = this.configService.pageSize;
constructor(private paymentReferencesService: PaymentReferencesService, private configService: ConfigService) {
super();
}
protected fetch(params: FetchPaymentParams, lastId?: string): Observable<FetchResult<PaymentReference>> {
const { searchValue, sortOrder, sortFieldValue, sortBy, id, isDefault, isGlobal, name, size } = params;
return this.paymentReferencesService.findReferences({
isDefault: isDefault || false,
searchValue: searchValue || '',
sortFieldValue: sortFieldValue || '',
sortOrder: sortOrder || SortOrder.ASC,
size: size ? size : this.SIZE,
isGlobal,
...(lastId ? { lastId } : {}),
...(sortBy ? { sortBy } : {}),
...(id ? { id } : {}),
...(name ? { name } : {}),
});
}
}

View File

@ -67,6 +67,10 @@ const routes: Routes = [
path: 'audit',
loadChildren: () => import('./audit').then((m) => m.AuditModule),
},
{
path: 'historical-data',
loadChildren: () => import('./historical-data').then((m) => m.HistoricalDataModule),
},
];
@NgModule({

View File

@ -33,7 +33,7 @@ export class RemoveRowListDialogComponent {
}
delete(): void {
this.listsService.deleteListRow(this.data.listRecord.groupId).subscribe(
this.listsService.deleteListRow(this.data.listRecord.id).subscribe(
(id) => {
this.snackBar.open(`Delete succeeded: ${id}`, 'OK', {
duration: 1500,

View File

@ -79,6 +79,12 @@ export class MenuModel {
route: 'emulation/template',
roles: [Roles.fraudOfficer, Roles.fraudMonitoring, Roles.fraudSupport],
},
{
displayName: 'Historical data',
iconName: 'history',
route: 'historical-data/payments',
roles: [Roles.fraudOfficer, Roles.fraudMonitoring],
},
{
displayName: 'Audit',
iconName: 'wysiwyg',