mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 02:25:17 +00:00
TD-905: Fix loading delay, fix repeat loading, default period 1 day (#354)
This commit is contained in:
parent
9145b78845
commit
7ea5d9a403
8
package-lock.json
generated
8
package-lock.json
generated
@ -25,7 +25,7 @@
|
||||
"@vality/fistful-proto": "2.0.1-6600be9.0",
|
||||
"@vality/machinegun-proto": "1.0.0",
|
||||
"@vality/magista-proto": "2.0.2-28d11b9.0",
|
||||
"@vality/ng-core": "17.2.1-pr-60-8d151ad.0",
|
||||
"@vality/ng-core": "17.2.1-pr-61-d842667.0",
|
||||
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
||||
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
||||
"@vality/scrooge-proto": "0.1.1-9ce7fc6.0",
|
||||
@ -6455,9 +6455,9 @@
|
||||
"integrity": "sha512-BsDy5ejotfTtUlwuoX3kz+PYJ5NSTW6m5ZRGv+p5HaKXSjR7tserPdv0q133Wp4T+sg0ED0Qr9Peqsrn+9XlDQ=="
|
||||
},
|
||||
"node_modules/@vality/ng-core": {
|
||||
"version": "17.2.1-pr-60-8d151ad.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.2.1-pr-60-8d151ad.0.tgz",
|
||||
"integrity": "sha512-CTPRbj/W7hNBd4yYKM4u5BJK00Q93F8xrc4xJ8QusNlaJM0FGF0eqtZMAOJ4r9ViPeAbwU0c8B6gkvgwrXrvJw==",
|
||||
"version": "17.2.1-pr-61-d842667.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-17.2.1-pr-61-d842667.0.tgz",
|
||||
"integrity": "sha512-QquwzzrFUHfc9vixSsX1ZkjQ+lkYbtEgT0tlqp1BnJ2N/kSR9eWZSV3N488j0ZPnDoJmktnwmUjDituQN855QA==",
|
||||
"dependencies": {
|
||||
"@angular/material-date-fns-adapter": "^17.2.0",
|
||||
"@ng-matero/extensions": "^17.1.0",
|
||||
|
@ -33,7 +33,7 @@
|
||||
"@vality/fistful-proto": "2.0.1-6600be9.0",
|
||||
"@vality/machinegun-proto": "1.0.0",
|
||||
"@vality/magista-proto": "2.0.2-28d11b9.0",
|
||||
"@vality/ng-core": "17.2.1-pr-60-8d151ad.0",
|
||||
"@vality/ng-core": "17.2.1-pr-61-d842667.0",
|
||||
"@vality/payout-manager-proto": "2.0.1-eb4091a.0",
|
||||
"@vality/repairer-proto": "2.0.2-07b73e9.0",
|
||||
"@vality/scrooge-proto": "0.1.1-9ce7fc6.0",
|
||||
|
@ -2,14 +2,13 @@ import { Injectable, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Domain, DomainObject, Reference } from '@vality/domain-proto/domain';
|
||||
import { Commit, Snapshot, Version } from '@vality/domain-proto/domain_config';
|
||||
import { NotifyLogService } from '@vality/ng-core';
|
||||
import { NotifyLogService, handleError, inProgressFrom, progressTo } from '@vality/ng-core';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
import { BehaviorSubject, defer, Observable, of, ReplaySubject, filter, combineLatest } from 'rxjs';
|
||||
import { map, shareReplay, startWith, switchMap, take, tap } from 'rxjs/operators';
|
||||
|
||||
import { inProgressFrom, progressTo, getUnionKey } from '../../../../utils';
|
||||
import { getUnionKey } from '../../../../utils';
|
||||
import { DomainSecretService } from '../../../shared/services';
|
||||
import { handleError } from '../../../shared/services/notification-error';
|
||||
import { RepositoryService } from '../repository.service';
|
||||
|
||||
@Injectable({
|
||||
|
@ -36,8 +36,6 @@ import { DomainObjectCardComponent } from './shared/components/thrift-api-crud';
|
||||
import {
|
||||
DEFAULT_MAT_DATE_FORMATS,
|
||||
DEFAULT_QUERY_PARAMS_SERIALIZERS,
|
||||
DEFAULT_SMALL_SEARCH_LIMIT,
|
||||
SMALL_SEARCH_LIMIT,
|
||||
DATE_RANGE_DAYS,
|
||||
DEFAULT_DATE_RANGE_DAYS,
|
||||
DEBOUNCE_TIME_MS,
|
||||
@ -83,7 +81,6 @@ export let AppInjector: Injector;
|
||||
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_MAT_DATE_FORMATS },
|
||||
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
|
||||
{ provide: LOCALE_ID, useValue: 'ru' },
|
||||
{ provide: SMALL_SEARCH_LIMIT, useValue: DEFAULT_SMALL_SEARCH_LIMIT },
|
||||
{ provide: QUERY_PARAMS_SERIALIZERS, useValue: DEFAULT_QUERY_PARAMS_SERIALIZERS },
|
||||
{ provide: DATE_RANGE_DAYS, useValue: DEFAULT_DATE_RANGE_DAYS },
|
||||
{ provide: DEBOUNCE_TIME_MS, useValue: DEFAULT_DEBOUNCE_TIME_MS },
|
||||
|
@ -2,7 +2,7 @@
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
<v-filters #filters [active]="active" merge (clear)="filtersForm.reset()">
|
||||
<v-filters #filters [active]="active$ | async" merge (clear)="filtersForm.reset()">
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<v-date-range-field formControlName="dateRange"></v-date-range-field>
|
||||
<v-list-field formControlName="chargeback_ids" label="Chargeback Ids"></v-list-field>
|
||||
@ -45,7 +45,7 @@
|
||||
[hasMore]="hasMore$ | async"
|
||||
[isLoading]="isLoading$ | async"
|
||||
(more)="more()"
|
||||
(update)="load($event)"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<button
|
||||
[disabled]="!selected.length"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component, OnInit, Inject, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { NonNullableFormBuilder } from '@angular/forms';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { ChargebackSearchQuery, StatChargeback } from '@vality/magista-proto/magista';
|
||||
import {
|
||||
DateRange,
|
||||
@ -10,14 +10,17 @@ import {
|
||||
getNoTimeZoneIsoString,
|
||||
createDateRangeToToday,
|
||||
isEqualDateRange,
|
||||
countProps,
|
||||
DialogService,
|
||||
DialogResponseStatus,
|
||||
getValueChanges,
|
||||
createControls,
|
||||
debounceTimeWithFirst,
|
||||
countChanged,
|
||||
} from '@vality/ng-core';
|
||||
import { endOfDay } from 'date-fns';
|
||||
import merge from 'lodash-es/merge';
|
||||
import { debounceTime, filter } from 'rxjs';
|
||||
import { startWith } from 'rxjs/operators';
|
||||
import { filter } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
import { Overwrite } from 'utility-types';
|
||||
|
||||
import {
|
||||
CHARGEBACK_STATUSES,
|
||||
@ -27,28 +30,37 @@ import {
|
||||
|
||||
import { createUnion } from '../../../utils';
|
||||
import { ChangeChargebacksStatusDialogComponent } from '../../shared/components/change-chargebacks-status-dialog';
|
||||
import { DATE_RANGE_DAYS } from '../../tokens';
|
||||
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../tokens';
|
||||
|
||||
import { CreateChargebacksByFileDialogComponent } from './components/create-chargebacks-by-file-dialog/create-chargebacks-by-file-dialog.component';
|
||||
import { FetchChargebacksService } from './fetch-chargebacks.service';
|
||||
|
||||
type FormValue = {
|
||||
dateRange: DateRange;
|
||||
} & Overwrite<
|
||||
Omit<ChargebackSearchQuery, 'common_search_query_params'>,
|
||||
Record<'chargeback_stages' | 'chargeback_categories' | 'chargeback_statuses', string[]>
|
||||
> &
|
||||
Pick<ChargebackSearchQuery['common_search_query_params'], 'party_id' | 'shop_ids'>;
|
||||
|
||||
@Component({
|
||||
selector: 'cc-chargebacks',
|
||||
templateUrl: './chargebacks.component.html',
|
||||
styles: [],
|
||||
})
|
||||
export class ChargebacksComponent implements OnInit {
|
||||
active = 0;
|
||||
filtersForm = this.fb.group({
|
||||
dateRange: createDateRangeToToday(this.dateRangeDays),
|
||||
party_id: undefined as ChargebackSearchQuery['common_search_query_params']['party_id'],
|
||||
shop_ids: [undefined as ChargebackSearchQuery['common_search_query_params']['shop_ids']],
|
||||
invoice_ids: [undefined as ChargebackSearchQuery['invoice_ids']],
|
||||
chargeback_ids: [undefined as ChargebackSearchQuery['chargeback_ids']],
|
||||
chargeback_statuses: [undefined as string[]],
|
||||
chargeback_stages: [undefined as string[]],
|
||||
chargeback_categories: [undefined as string[]],
|
||||
});
|
||||
filtersForm = new FormGroup(
|
||||
createControls<FormValue>({
|
||||
dateRange: createDateRangeToToday(this.dateRangeDays),
|
||||
party_id: undefined,
|
||||
shop_ids: undefined,
|
||||
invoice_ids: undefined,
|
||||
chargeback_ids: undefined,
|
||||
chargeback_statuses: undefined,
|
||||
chargeback_stages: undefined,
|
||||
chargeback_categories: undefined,
|
||||
}),
|
||||
);
|
||||
chargebacks$ = this.fetchChargebacksService.result$;
|
||||
isLoading$ = this.fetchChargebacksService.isLoading$;
|
||||
hasMore$ = this.fetchChargebacksService.hasMore$;
|
||||
@ -56,27 +68,49 @@ export class ChargebacksComponent implements OnInit {
|
||||
stages = CHARGEBACK_STAGES;
|
||||
categories = CHARGEBACK_CATEGORIES;
|
||||
selected: StatChargeback[] = [];
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFormValue, v, { dateRange: isEqualDateRange })),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
private initFormValue = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private fb: NonNullableFormBuilder,
|
||||
private qp: QueryParamsService<{
|
||||
filters: ChargebacksComponent['filtersForm']['value'];
|
||||
dateRange: DateRange;
|
||||
}>,
|
||||
private qp: QueryParamsService<Partial<FormValue>>,
|
||||
private fetchChargebacksService: FetchChargebacksService,
|
||||
private dialog: DialogService,
|
||||
@Inject(DATE_RANGE_DAYS) private dateRangeDays: number,
|
||||
private destroyRef: DestroyRef,
|
||||
private dr: DestroyRef,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(
|
||||
merge({}, this.qp.params.filters, clean({ dateRange: this.qp.params.dateRange })),
|
||||
);
|
||||
this.filtersForm.valueChanges
|
||||
.pipe(startWith(null), debounceTime(500), takeUntilDestroyed(this.destroyRef))
|
||||
this.filtersForm.patchValue(this.qp.params, { emitEvent: false });
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.dr))
|
||||
.subscribe(() => {
|
||||
this.load();
|
||||
const value = clean(this.filtersForm.value);
|
||||
void this.qp.set(value);
|
||||
const { dateRange, party_id, shop_ids, ...rootParams } = value;
|
||||
this.load({
|
||||
...rootParams,
|
||||
common_search_query_params: clean({
|
||||
party_id,
|
||||
shop_ids,
|
||||
from_time: getNoTimeZoneIsoString(dateRange.start),
|
||||
to_time: getNoTimeZoneIsoString(endOfDay(dateRange.end)),
|
||||
}),
|
||||
...clean(
|
||||
{
|
||||
chargeback_stages: rootParams.chargeback_stages?.map(createUnion),
|
||||
chargeback_categories:
|
||||
rootParams.chargeback_categories?.map(createUnion),
|
||||
chargeback_statuses: rootParams.chargeback_statuses?.map(createUnion),
|
||||
},
|
||||
false,
|
||||
true,
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -84,34 +118,12 @@ export class ChargebacksComponent implements OnInit {
|
||||
this.fetchChargebacksService.more();
|
||||
}
|
||||
|
||||
load(options?: LoadOptions) {
|
||||
const { dateRange, ...filters } = clean(this.filtersForm.value);
|
||||
void this.qp.set({ filters, dateRange });
|
||||
const { party_id, shop_ids, ...rootParams } = filters;
|
||||
const commonParams = clean({ party_id, shop_ids });
|
||||
this.fetchChargebacksService.load(
|
||||
{
|
||||
...rootParams,
|
||||
common_search_query_params: {
|
||||
...commonParams,
|
||||
from_time: getNoTimeZoneIsoString(dateRange.start),
|
||||
to_time: getNoTimeZoneIsoString(endOfDay(dateRange.end)),
|
||||
},
|
||||
...clean(
|
||||
{
|
||||
chargeback_stages: rootParams.chargeback_stages?.map(createUnion),
|
||||
chargeback_categories: rootParams.chargeback_categories?.map(createUnion),
|
||||
chargeback_statuses: rootParams.chargeback_statuses?.map(createUnion),
|
||||
},
|
||||
false,
|
||||
true,
|
||||
),
|
||||
},
|
||||
options,
|
||||
);
|
||||
this.active =
|
||||
countProps(rootParams, commonParams) +
|
||||
+!isEqualDateRange(createDateRangeToToday(this.dateRangeDays), dateRange);
|
||||
reload(options?: LoadOptions) {
|
||||
this.fetchChargebacksService.reload(options);
|
||||
}
|
||||
|
||||
load(params: ChargebackSearchQuery, options?: LoadOptions) {
|
||||
this.fetchChargebacksService.load(params, options);
|
||||
}
|
||||
|
||||
create() {
|
||||
@ -120,7 +132,7 @@ export class ChargebacksComponent implements OnInit {
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
filter((res) => res.status === DialogResponseStatus.Success),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
takeUntilDestroyed(this.dr),
|
||||
)
|
||||
.subscribe((res) => {
|
||||
this.filtersForm.reset({
|
||||
@ -136,10 +148,10 @@ export class ChargebacksComponent implements OnInit {
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
filter((res) => res.status === DialogResponseStatus.Success),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
takeUntilDestroyed(this.dr),
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.load();
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,22 @@
|
||||
import { Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { DialogResponseStatus, DialogService, NotifyLogService } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogService,
|
||||
NotifyLogService,
|
||||
handleError,
|
||||
inProgressFrom,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import { BehaviorSubject, combineLatest, defer, merge, Observable, Subject, switchMap } from 'rxjs';
|
||||
import { first, map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { ClaimManagementService } from '@cc/app/api/claim-management';
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
import { getUnionKey, inProgressFrom, progressTo } from '@cc/utils';
|
||||
import { getUnionKey } from '@cc/utils';
|
||||
|
||||
import { DomainMetadataFormExtensionsService } from '../../shared/services';
|
||||
import { handleError } from '../../shared/services/notification-error';
|
||||
|
||||
import { AddModificationDialogComponent } from './components/add-modification-dialog/add-modification-dialog.component';
|
||||
import { ChangeStatusDialogComponent } from './components/change-status-dialog/change-status-dialog.component';
|
||||
|
@ -4,12 +4,17 @@ import { Validators, FormBuilder } from '@angular/forms';
|
||||
import { Claim, ModificationUnit } from '@vality/domain-proto/claim_management';
|
||||
import { Party } from '@vality/domain-proto/domain';
|
||||
import { ModificationChange, Modification } from '@vality/domain-proto/internal/claim_management';
|
||||
import { DialogSuperclass, DEFAULT_DIALOG_CONFIG, NotifyLogService } from '@vality/ng-core';
|
||||
import {
|
||||
DialogSuperclass,
|
||||
DEFAULT_DIALOG_CONFIG,
|
||||
NotifyLogService,
|
||||
inProgressFrom,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { DeepPartial } from 'utility-types';
|
||||
|
||||
import { ClaimManagementService } from '@cc/app/api/claim-management';
|
||||
import { inProgressFrom, progressTo } from '@cc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-add-modification-dialog',
|
||||
|
@ -2,15 +2,18 @@ import { Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Validators, FormBuilder } from '@angular/forms';
|
||||
import { Claim, ClaimStatus } from '@vality/domain-proto/claim_management';
|
||||
import { DialogResponseStatus, DialogSuperclass } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogSuperclass,
|
||||
NotifyLogService,
|
||||
inProgressFrom,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
import { ClaimManagementService } from '@cc/app/api/claim-management';
|
||||
import { AllowedClaimStatusesService } from '@cc/app/sections/claim/services/allowed-claim-statuses.service';
|
||||
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||
import { getUnionKey, inProgressFrom, progressTo } from '@cc/utils';
|
||||
|
||||
import { NotificationErrorService } from '../../../../shared/services/notification-error';
|
||||
import { getUnionKey } from '@cc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-change-status-dialog',
|
||||
@ -35,9 +38,8 @@ export class ChangeStatusDialogComponent extends DialogSuperclass<
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private claimManagementService: ClaimManagementService,
|
||||
private notificationService: NotificationService,
|
||||
private log: NotifyLogService,
|
||||
private allowedClaimStatusesService: AllowedClaimStatusesService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -68,9 +70,9 @@ export class ChangeStatusDialogComponent extends DialogSuperclass<
|
||||
result$.pipe(progressTo(this.progress$), takeUntilDestroyed(this.destroyRef)).subscribe({
|
||||
next: () => {
|
||||
this.dialogRef.close({ status: DialogResponseStatus.Success });
|
||||
this.notificationService.success('Status successfully changed');
|
||||
this.log.success('Status successfully changed');
|
||||
},
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
DialogSuperclass,
|
||||
DEFAULT_DIALOG_CONFIG,
|
||||
NotifyLogService,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import { of, BehaviorSubject } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
@ -27,7 +28,6 @@ import short from 'short-uuid';
|
||||
|
||||
import { MetadataFormExtension, isTypeWithAliases } from '@cc/app/shared/components/metadata-form';
|
||||
|
||||
import { progressTo } from '../../../../../utils';
|
||||
import { ClaimManagementService } from '../../../../api/claim-management';
|
||||
import { DomainStoreService } from '../../../../api/domain-config';
|
||||
import { DomainThriftFormComponent } from '../../../../shared/components/thrift-api-crud';
|
||||
|
@ -8,7 +8,14 @@ import {
|
||||
} from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Claim, ModificationUnit } from '@vality/domain-proto/claim_management';
|
||||
import { DialogResponseStatus, DialogService, ConfirmDialogComponent } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogService,
|
||||
ConfirmDialogComponent,
|
||||
NotifyLogService,
|
||||
inProgressFrom,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import isEmpty from 'lodash-es/isEmpty';
|
||||
import { BehaviorSubject, switchMap, from } from 'rxjs';
|
||||
import { filter, first } from 'rxjs/operators';
|
||||
@ -17,12 +24,9 @@ import { ClaimManagementService } from '@cc/app/api/claim-management';
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
import { getModificationName } from '@cc/app/sections/claim/utils/get-modification-name';
|
||||
import { DomainMetadataViewExtensionsService } from '@cc/app/shared/components/thrift-api-crud/domain/domain-thrift-viewer/services/domain-metadata-view-extensions';
|
||||
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||
import { Color, StatusColor } from '@cc/app/styles';
|
||||
import { inProgressFrom, progressTo } from '@cc/utils';
|
||||
import { getUnionValue } from '@cc/utils/get-union-key';
|
||||
|
||||
import { NotificationErrorService } from '../../../../shared/services/notification-error';
|
||||
import { AddModificationDialogComponent } from '../add-modification-dialog/add-modification-dialog.component';
|
||||
|
||||
@Component({
|
||||
@ -51,9 +55,8 @@ export class ModificationUnitTimelineItemComponent {
|
||||
private partyManagementService: PartyManagementService,
|
||||
private dialogService: DialogService,
|
||||
private claimManagementService: ClaimManagementService,
|
||||
private notificationService: NotificationService,
|
||||
private log: NotifyLogService,
|
||||
private domainMetadataViewExtensionsService: DomainMetadataViewExtensionsService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {}
|
||||
|
||||
@ -108,10 +111,10 @@ export class ModificationUnitTimelineItemComponent {
|
||||
)
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.notificationService.success();
|
||||
this.log.success();
|
||||
this.claimChanged.emit();
|
||||
},
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<cc-page-layout-actions
|
||||
><v-more-filters-button [filters]="filters"></v-more-filters-button
|
||||
></cc-page-layout-actions>
|
||||
<v-filters #filters [active]="active">
|
||||
<v-filters #filters [active]="active$ | async">
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<cc-merchant-field
|
||||
*ngIf="!(party$ | async)"
|
||||
@ -32,7 +32,7 @@
|
||||
[isLoading]="isLoading$ | async"
|
||||
[noParty]="!!(party$ | async)"
|
||||
(more)="more()"
|
||||
(update)="load($event)"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<button color="primary" mat-raised-button (click)="create()">Create</button>
|
||||
</cc-claims-table>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, DestroyRef } from '@angular/core';
|
||||
import { Component, OnInit, DestroyRef, Inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { NonNullableFormBuilder } from '@angular/forms';
|
||||
import { PartyID } from '@vality/domain-proto/domain';
|
||||
@ -8,11 +8,13 @@ import {
|
||||
QueryParamsService,
|
||||
clean,
|
||||
getValueChanges,
|
||||
countChanged,
|
||||
debounceTimeWithFirst,
|
||||
} from '@vality/ng-core';
|
||||
import { debounceTime } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { take, map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { CLAIM_STATUSES } from '../../api/claim-management';
|
||||
import { DEBOUNCE_TIME_MS } from '../../tokens';
|
||||
import { PartyStoreService } from '../party';
|
||||
|
||||
import { CreateClaimDialogComponent } from './components/create-claim-dialog/create-claim-dialog.component';
|
||||
@ -32,10 +34,14 @@ export class ClaimsComponent implements OnInit {
|
||||
claim_id: undefined as number,
|
||||
statuses: [[] as string[]],
|
||||
});
|
||||
active = 0;
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFilters, v)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
party$ = this.partyStoreService.party$;
|
||||
|
||||
private selectedPartyId: PartyID;
|
||||
private initFilters = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private fetchClaimsService: FetchClaimsService,
|
||||
@ -44,21 +50,21 @@ export class ClaimsComponent implements OnInit {
|
||||
private qp: QueryParamsService<ClaimsComponent['filtersForm']['value']>,
|
||||
private destroyRef: DestroyRef,
|
||||
private partyStoreService: PartyStoreService,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.filtersForm.patchValue(this.qp.params);
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(debounceTime(500), takeUntilDestroyed(this.destroyRef))
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => {
|
||||
this.load();
|
||||
const filters = clean(this.filtersForm.value);
|
||||
void this.qp.set(filters);
|
||||
this.load(filters);
|
||||
});
|
||||
}
|
||||
|
||||
load(options?: LoadOptions): void {
|
||||
const filters = clean(this.filtersForm.value);
|
||||
void this.qp.set(filters);
|
||||
this.active = Object.keys(filters).length;
|
||||
load(filters: ClaimsComponent['filtersForm']['value'], options?: LoadOptions): void {
|
||||
this.partyStoreService.party$.pipe(take(1)).subscribe((p) => {
|
||||
this.fetchClaimsService.load(
|
||||
clean({
|
||||
@ -71,6 +77,10 @@ export class ClaimsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
reload(options?: LoadOptions) {
|
||||
this.fetchClaimsService.reload(options);
|
||||
}
|
||||
|
||||
more(): void {
|
||||
this.fetchClaimsService.more();
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ import { Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService, progressTo } from '@vality/ng-core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { ClaimManagementService } from '@cc/app/api/claim-management';
|
||||
import { progressTo } from '@cc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-create-claim-dialog',
|
||||
|
@ -4,9 +4,9 @@
|
||||
[columns]="columns"
|
||||
[data]="reverts$ | async"
|
||||
[hasMore]="hasMore$ | async"
|
||||
[progress]="doAction$ | async"
|
||||
(more)="fetchMore()"
|
||||
(update)="update()"
|
||||
[progress]="isLoading$ | async"
|
||||
(more)="more()"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<v-table-actions>
|
||||
<button
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { DepositStatus, StatDeposit, StatDepositRevert } from '@vality/fistful-proto/fistful_stat';
|
||||
import { DialogService, Column } from '@vality/ng-core';
|
||||
import { DialogService, Column, UpdateOptions } from '@vality/ng-core';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@ -21,9 +21,9 @@ import { FetchRevertsService } from './services/fetch-reverts/fetch-reverts.serv
|
||||
export class RevertsComponent implements OnInit {
|
||||
@Input() deposit: StatDeposit;
|
||||
|
||||
reverts$ = this.fetchRevertsService.searchResult$;
|
||||
reverts$ = this.fetchRevertsService.result$;
|
||||
hasMore$ = this.fetchRevertsService.hasMore$;
|
||||
doAction$ = this.fetchRevertsService.doAction$;
|
||||
isLoading$ = this.fetchRevertsService.isLoading$;
|
||||
columns: Column<StatDepositRevert>[] = [
|
||||
{ field: 'id' },
|
||||
{
|
||||
@ -53,7 +53,7 @@ export class RevertsComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.fetchRevertsService.search({ deposit_id: this.deposit.id });
|
||||
this.fetchRevertsService.load({ deposit_id: this.deposit.id });
|
||||
}
|
||||
|
||||
createRevert() {
|
||||
@ -65,7 +65,7 @@ export class RevertsComponent implements OnInit {
|
||||
.afterClosed()
|
||||
.pipe(filter((res) => res?.status === 'success'))
|
||||
.subscribe(() => {
|
||||
this.fetchRevertsService.refresh();
|
||||
this.fetchRevertsService.reload();
|
||||
});
|
||||
}
|
||||
|
||||
@ -73,11 +73,11 @@ export class RevertsComponent implements OnInit {
|
||||
return getUnionKey(status) !== 'succeeded';
|
||||
}
|
||||
|
||||
update() {
|
||||
this.fetchRevertsService.refresh();
|
||||
reload(options: UpdateOptions) {
|
||||
this.fetchRevertsService.reload(options);
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.fetchRevertsService.fetchMore();
|
||||
more() {
|
||||
this.fetchRevertsService.more();
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,30 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatDepositRevert } from '@vality/fistful-proto/fistful_stat';
|
||||
import { Observable } from 'rxjs';
|
||||
import { FetchSuperclass, FetchOptions, clean } from '@vality/ng-core';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { createDsl, FistfulStatisticsService } from '@cc/app/api/fistful-stat';
|
||||
import { FetchResult, PartialFetcher } from '@cc/app/shared/services';
|
||||
import { SMALL_SEARCH_LIMIT } from '@cc/app/tokens';
|
||||
import { removeEmptyProperties } from '@cc/utils';
|
||||
|
||||
import { FetchRevertsParams } from '../../types/fetch-reverts-params';
|
||||
|
||||
@Injectable()
|
||||
export class FetchRevertsService extends PartialFetcher<StatDepositRevert, FetchRevertsParams> {
|
||||
constructor(
|
||||
private fistfulStatisticsService: FistfulStatisticsService,
|
||||
@Inject(SMALL_SEARCH_LIMIT) private smallSearchLimit: number,
|
||||
) {
|
||||
export class FetchRevertsService extends FetchSuperclass<StatDepositRevert, FetchRevertsParams> {
|
||||
constructor(private fistfulStatisticsService: FistfulStatisticsService) {
|
||||
super();
|
||||
}
|
||||
|
||||
fetch(
|
||||
params: FetchRevertsParams,
|
||||
continuationToken: string,
|
||||
): Observable<FetchResult<StatDepositRevert>> {
|
||||
fetch(params: FetchRevertsParams, options: FetchOptions) {
|
||||
return this.fistfulStatisticsService
|
||||
.GetDepositReverts({
|
||||
dsl: createDsl({
|
||||
deposit_reverts: {
|
||||
...removeEmptyProperties(params),
|
||||
size: this.smallSearchLimit.toString(),
|
||||
...clean(params),
|
||||
size: String(options.size),
|
||||
},
|
||||
}),
|
||||
...(!!continuationToken && { continuation_token: continuationToken }),
|
||||
...(!!options.continuationToken && {
|
||||
continuation_token: options.continuationToken,
|
||||
}),
|
||||
})
|
||||
.pipe(
|
||||
map((res) => ({
|
||||
|
@ -2,7 +2,7 @@
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
<v-filters #filters [active]="active" merge (clear)="filtersForm.reset()">
|
||||
<v-filters #filters [active]="active$ | async" merge (clear)="filtersForm.reset()">
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<v-date-range-field formControlName="dateRange" required></v-date-range-field>
|
||||
<v-input-field formControlName="amount_to" label="Amount To"></v-input-field>
|
||||
@ -28,7 +28,7 @@
|
||||
[hasMore]="hasMore$ | async"
|
||||
[progress]="isLoading$ | async"
|
||||
(more)="more()"
|
||||
(update)="update($event)"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<v-table-actions>
|
||||
<button color="primary" mat-raised-button (click)="createDeposit()">Create</button>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, Inject, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { NonNullableFormBuilder } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { StatDeposit, RevertStatus } from '@vality/fistful-proto/fistful_stat';
|
||||
import {
|
||||
@ -10,15 +10,17 @@ import {
|
||||
createDateRangeToToday,
|
||||
QueryParamsService,
|
||||
clean,
|
||||
countProps,
|
||||
isEqualDateRange,
|
||||
getNoTimeZoneIsoString,
|
||||
DialogService,
|
||||
DialogResponseStatus,
|
||||
debounceTimeWithFirst,
|
||||
getValueChanges,
|
||||
countChanged,
|
||||
} from '@vality/ng-core';
|
||||
import { endOfDay } from 'date-fns';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { filter, startWith, debounceTime } from 'rxjs/operators';
|
||||
import { filter, map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { getUnionKey } from '../../../utils';
|
||||
import { QueryDsl } from '../../api/fistful-stat';
|
||||
@ -40,7 +42,7 @@ const REVERT_STATUS: { [N in RevertStatus]: string } = {
|
||||
providers: [FetchDepositsService],
|
||||
})
|
||||
export class DepositsComponent implements OnInit {
|
||||
filtersForm = this.fb.nonNullable.group({
|
||||
filtersForm = this.fb.group({
|
||||
dateRange: createDateRangeToToday(this.dateRangeDays),
|
||||
amount_to: null as number,
|
||||
currency_code: null as string,
|
||||
@ -50,8 +52,6 @@ export class DepositsComponent implements OnInit {
|
||||
wallet_id: '',
|
||||
party_id: null as string,
|
||||
});
|
||||
active = 0;
|
||||
|
||||
deposits$ = this.fetchDepositsService.result$;
|
||||
hasMore$ = this.fetchDepositsService.hasMore$;
|
||||
isLoading$ = this.fetchDepositsService.isLoading$;
|
||||
@ -118,12 +118,18 @@ export class DepositsComponent implements OnInit {
|
||||
]),
|
||||
];
|
||||
depositStatuses: QueryDsl['query']['deposits']['status'][] = ['Pending', 'Succeeded', 'Failed'];
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFilters, v, { dateRange: isEqualDateRange })),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
private initFilters = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private dialog: DialogService,
|
||||
private fetchDepositsService: FetchDepositsService,
|
||||
private router: Router,
|
||||
private fb: FormBuilder,
|
||||
private fb: NonNullableFormBuilder,
|
||||
@Inject(DATE_RANGE_DAYS) private dateRangeDays: number,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
private qp: QueryParamsService<object>,
|
||||
@ -132,12 +138,8 @@ export class DepositsComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(this.qp.params);
|
||||
this.filtersForm.valueChanges
|
||||
.pipe(
|
||||
startWith(this.filtersForm.value),
|
||||
debounceTime(this.debounceTimeMs),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => {
|
||||
this.update();
|
||||
});
|
||||
@ -167,9 +169,10 @@ export class DepositsComponent implements OnInit {
|
||||
options,
|
||||
);
|
||||
void this.qp.set({ dateRange, ...filters });
|
||||
this.active =
|
||||
countProps(filters) +
|
||||
+!isEqualDateRange(dateRange, createDateRangeToToday(this.dateRangeDays));
|
||||
}
|
||||
|
||||
reload(options?: UpdateOptions) {
|
||||
this.fetchDepositsService.reload(options);
|
||||
}
|
||||
|
||||
more() {
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Party } from '@vality/domain-proto/domain';
|
||||
import { progressTo } from '@vality/ng-core';
|
||||
import { progressTo, debounceTimeWithFirst } from '@vality/ng-core';
|
||||
import { defer, merge, Observable, Subject, BehaviorSubject } from 'rxjs';
|
||||
import { map, shareReplay, switchMap, startWith, debounceTime } from 'rxjs/operators';
|
||||
import { map, shareReplay, switchMap, startWith } from 'rxjs/operators';
|
||||
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
|
||||
import { DEBOUNCE_TIME_MS } from '../../tokens';
|
||||
|
||||
@Injectable()
|
||||
export class PartyShopsService {
|
||||
party$: Observable<Party> = merge(
|
||||
@ -14,7 +16,7 @@ export class PartyShopsService {
|
||||
defer(() => this.reload$),
|
||||
).pipe(
|
||||
startWith(null),
|
||||
debounceTime(300),
|
||||
debounceTimeWithFirst(this.debounceTimeMs),
|
||||
map(() => this.route.snapshot.params.partyID),
|
||||
switchMap((partyID) =>
|
||||
this.partyManagementService.Get(partyID).pipe(progressTo(this.progress$)),
|
||||
@ -33,6 +35,7 @@ export class PartyShopsService {
|
||||
constructor(
|
||||
private partyManagementService: PartyManagementService,
|
||||
private route: ActivatedRoute,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
) {}
|
||||
|
||||
reload() {
|
||||
|
@ -3,14 +3,12 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { InvoicePaymentChargeback } from '@vality/domain-proto/domain';
|
||||
import { InvoicePaymentChargebackParams } from '@vality/domain-proto/payment_processing';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
import { from } from 'rxjs';
|
||||
import * as short from 'short-uuid';
|
||||
|
||||
import { InvoicingService } from '@cc/app/api/payment-processing';
|
||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-create-chargeback-dialog',
|
||||
@ -28,8 +26,7 @@ export class CreateChargebackDialogComponent extends DialogSuperclass<
|
||||
constructor(
|
||||
private invoicingService: InvoicingService,
|
||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private notificationService: NotificationService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -45,10 +42,10 @@ export class CreateChargebackDialogComponent extends DialogSuperclass<
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe({
|
||||
next: (res) => {
|
||||
this.notificationService.success('Chargeback created');
|
||||
this.log.success('Chargeback created');
|
||||
this.closeWithSuccess(res);
|
||||
},
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
<v-table
|
||||
[columns]="columns"
|
||||
[data]="refunds$ | async"
|
||||
[hasMore]="hasMore$ | async"
|
||||
[progress]="isLoading$ | async"
|
||||
(more)="fetchMore()"
|
||||
(more)="more()"
|
||||
(update)="reload($event)"
|
||||
></v-table>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { InvoicePaymentID, InvoiceID, PartyID } from '@vality/domain-proto/domain';
|
||||
import { Column, NotifyLogService } from '@vality/ng-core';
|
||||
import { Column, UpdateOptions } from '@vality/ng-core';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
|
||||
import { getUnionKey } from '../../../../utils';
|
||||
@ -21,9 +21,9 @@ export class RefundsTableComponent implements OnInit {
|
||||
@Input() invoiceID: InvoiceID;
|
||||
@Input() partyID: PartyID;
|
||||
|
||||
isLoading$ = this.fetchRefundsService.doAction$;
|
||||
isLoading$ = this.fetchRefundsService.isLoading$;
|
||||
hasMore$ = this.fetchRefundsService.hasMore$;
|
||||
refunds$ = this.fetchRefundsService.searchResult$;
|
||||
refunds$ = this.fetchRefundsService.result$;
|
||||
|
||||
columns: Column<Refund>[] = [
|
||||
{ field: 'created_at', type: 'datetime' },
|
||||
@ -48,23 +48,21 @@ export class RefundsTableComponent implements OnInit {
|
||||
'reason',
|
||||
];
|
||||
|
||||
constructor(
|
||||
private fetchRefundsService: FetchRefundsService,
|
||||
private log: NotifyLogService,
|
||||
) {}
|
||||
constructor(private fetchRefundsService: FetchRefundsService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.fetchRefundsService.search({
|
||||
this.fetchRefundsService.load({
|
||||
common_search_query_params: { party_id: this.partyID },
|
||||
payment_id: this.paymentID,
|
||||
invoice_ids: [this.invoiceID],
|
||||
});
|
||||
this.fetchRefundsService.errors$.subscribe((e) =>
|
||||
this.log.errorOperation(e, 'receive', 'refunds'),
|
||||
);
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.fetchRefundsService.fetchMore();
|
||||
more() {
|
||||
this.fetchRefundsService.more();
|
||||
}
|
||||
|
||||
reload(options: UpdateOptions) {
|
||||
this.fetchRefundsService.reload(options);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { TableModule } from '@vality/ng-core';
|
||||
|
||||
import {
|
||||
StatusModule,
|
||||
CommonPipesModule,
|
||||
ThriftPipesModule,
|
||||
AmountCurrencyPipe,
|
||||
} from '../../../shared';
|
||||
import { StatusModule, CommonPipesModule, ThriftPipesModule } from '../../../shared';
|
||||
|
||||
import { RefundsTableComponent } from './refunds-table.component';
|
||||
|
||||
@ -19,7 +14,6 @@ import { RefundsTableComponent } from './refunds-table.component';
|
||||
StatusModule,
|
||||
ThriftPipesModule,
|
||||
CommonPipesModule,
|
||||
AmountCurrencyPipe,
|
||||
TableModule,
|
||||
],
|
||||
declarations: [RefundsTableComponent],
|
||||
|
@ -1,36 +1,38 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatRefund, RefundSearchQuery } from '@vality/magista-proto/magista';
|
||||
import { cleanPrimitiveProps } from '@vality/ng-core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import {
|
||||
cleanPrimitiveProps,
|
||||
FetchSuperclass,
|
||||
FetchOptions,
|
||||
NotifyLogService,
|
||||
} from '@vality/ng-core';
|
||||
import { of } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { DeepPartial } from 'utility-types';
|
||||
|
||||
import { MerchantStatisticsService } from '../../../../api/magista';
|
||||
import { FetchResult, PartialFetcher } from '../../../../shared/services';
|
||||
|
||||
const SEARCH_LIMIT = 5;
|
||||
|
||||
@Injectable()
|
||||
export class FetchRefundsService extends PartialFetcher<
|
||||
export class FetchRefundsService extends FetchSuperclass<
|
||||
StatRefund,
|
||||
DeepPartial<RefundSearchQuery>
|
||||
> {
|
||||
constructor(private merchantStatisticsService: MerchantStatisticsService) {
|
||||
constructor(
|
||||
private merchantStatisticsService: MerchantStatisticsService,
|
||||
private log: NotifyLogService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected fetch(
|
||||
params: DeepPartial<RefundSearchQuery>,
|
||||
continuationToken: string,
|
||||
): Observable<FetchResult<StatRefund>> {
|
||||
protected fetch(params: DeepPartial<RefundSearchQuery>, options: FetchOptions) {
|
||||
return this.merchantStatisticsService
|
||||
.SearchRefunds(
|
||||
cleanPrimitiveProps({
|
||||
...params,
|
||||
common_search_query_params: Object.assign(
|
||||
{
|
||||
continuation_token: continuationToken,
|
||||
limit: SEARCH_LIMIT,
|
||||
continuation_token: options.continuationToken,
|
||||
limit: options.size,
|
||||
from_time: new Date(0).toISOString(), // TODO
|
||||
to_time: new Date().toISOString(),
|
||||
},
|
||||
@ -43,6 +45,10 @@ export class FetchRefundsService extends PartialFetcher<
|
||||
result: refunds,
|
||||
continuationToken: continuation_token,
|
||||
})),
|
||||
catchError((err) => {
|
||||
this.log.errorOperation(err, 'receive', 'refunds');
|
||||
return of({ result: [] });
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
</cc-page-layout-actions>
|
||||
<v-filters
|
||||
#filters
|
||||
[active]="active"
|
||||
[active]="active$ | async"
|
||||
merge
|
||||
(clear)="filtersForm.reset(); otherFiltersControl.reset()"
|
||||
>
|
||||
@ -29,13 +29,12 @@
|
||||
<v-input-field formControlName="error_message" label="Error message"></v-input-field>
|
||||
</ng-template>
|
||||
<ng-template vOtherFilters>
|
||||
<cc-metadata-form
|
||||
<cc-magista-thrift-form
|
||||
[extensions]="extensions"
|
||||
[formControl]="otherFiltersControl"
|
||||
[metadata]="metadata$ | async"
|
||||
namespace="magista"
|
||||
noToolbar
|
||||
type="PaymentSearchQuery"
|
||||
></cc-metadata-form>
|
||||
></cc-magista-thrift-form>
|
||||
</ng-template>
|
||||
</v-filters>
|
||||
<cc-payments-table
|
||||
@ -45,7 +44,7 @@
|
||||
[selected]="selected$ | async"
|
||||
(more)="more()"
|
||||
(selectedChange)="selected$.next($event)"
|
||||
(update)="update($event ?? {})"
|
||||
(update)="reload($event ?? {})"
|
||||
>
|
||||
<button
|
||||
[disabled]="!(selected$ | async)?.length"
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Component, OnInit, Inject, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { NonNullableFormBuilder } from '@angular/forms';
|
||||
import { ThriftAstMetadata } from '@vality/fistful-proto';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
import {
|
||||
DialogService,
|
||||
@ -12,20 +11,20 @@ import {
|
||||
DateRange,
|
||||
QueryParamsService,
|
||||
createDateRangeToToday,
|
||||
countProps,
|
||||
isEqualDateRange,
|
||||
debounceTimeWithFirst,
|
||||
getValueChanges,
|
||||
countChanged,
|
||||
} from '@vality/ng-core';
|
||||
import { endOfDay } from 'date-fns';
|
||||
import { uniq } from 'lodash-es';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
import lodashMerge from 'lodash-es/merge';
|
||||
import omit from 'lodash-es/omit';
|
||||
import { BehaviorSubject, debounceTime, from, of, merge } from 'rxjs';
|
||||
import { startWith, map, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { BehaviorSubject, of, merge } from 'rxjs';
|
||||
import { startWith, map, distinctUntilChanged, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { FailMachinesDialogComponent, Type } from '../../shared/components/fail-machines-dialog';
|
||||
import { MetadataFormExtension, isTypeWithAliases } from '../../shared/components/metadata-form';
|
||||
import { DATE_RANGE_DAYS } from '../../tokens';
|
||||
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../tokens';
|
||||
|
||||
import { CreatePaymentAdjustmentComponent } from './components/create-payment-adjustment/create-payment-adjustment.component';
|
||||
import { FetchPaymentsService } from './services/fetch-payments.service';
|
||||
@ -60,9 +59,6 @@ export class PaymentsComponent implements OnInit {
|
||||
common_search_query_params: {},
|
||||
payment_params: {},
|
||||
});
|
||||
metadata$ = from(
|
||||
import('@vality/magista-proto/metadata.json').then((m) => m.default as ThriftAstMetadata[]),
|
||||
);
|
||||
extensions: MetadataFormExtension[] = [
|
||||
{
|
||||
determinant: (data) =>
|
||||
@ -81,7 +77,14 @@ export class PaymentsComponent implements OnInit {
|
||||
extension: () => of({ hidden: true }),
|
||||
},
|
||||
];
|
||||
active = 0;
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((filters) =>
|
||||
countChanged(this.initFiltersValue, filters, { dateRange: isEqualDateRange }),
|
||||
),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
private initFiltersValue = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private qp: QueryParamsService<Filters>,
|
||||
@ -89,29 +92,33 @@ export class PaymentsComponent implements OnInit {
|
||||
private dialogService: DialogService,
|
||||
private fb: NonNullableFormBuilder,
|
||||
@Inject(DATE_RANGE_DAYS) private dateRangeDays: number,
|
||||
private destroyRef: DestroyRef,
|
||||
private dr: DestroyRef,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(
|
||||
lodashMerge({}, this.qp.params.filters, clean({ dateRange: this.qp.params.dateRange })),
|
||||
);
|
||||
this.otherFiltersControl.patchValue(
|
||||
lodashMerge({}, this.otherFiltersControl.value, this.qp.params.otherFilters || {}),
|
||||
Object.assign(
|
||||
{},
|
||||
this.qp.params.filters,
|
||||
clean({ dateRange: this.qp.params.dateRange }),
|
||||
),
|
||||
);
|
||||
this.otherFiltersControl.patchValue(Object.assign({}, this.qp.params.otherFilters));
|
||||
merge(this.filtersForm.valueChanges, this.otherFiltersControl.valueChanges)
|
||||
.pipe(
|
||||
startWith(null),
|
||||
debounceTime(500),
|
||||
debounceTimeWithFirst(this.debounceTimeMs),
|
||||
map(() => {
|
||||
const { dateRange, ...filters } = clean(this.filtersForm.value);
|
||||
const otherFilters = clean(this.otherFiltersControl.value);
|
||||
return { filters, dateRange, otherFilters };
|
||||
}),
|
||||
distinctUntilChanged(isEqual),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
takeUntilDestroyed(this.dr),
|
||||
)
|
||||
.subscribe((filters) => {
|
||||
void this.qp.set(filters);
|
||||
this.load(filters);
|
||||
});
|
||||
}
|
||||
@ -121,7 +128,6 @@ export class PaymentsComponent implements OnInit {
|
||||
}
|
||||
|
||||
load({ filters, otherFilters, dateRange }: Filters, options?: LoadOptions) {
|
||||
void this.qp.set({ filters, otherFilters, dateRange });
|
||||
const { invoice_ids, party_id, shop_ids, external_id, ...paymentParams } = filters;
|
||||
const searchParams = clean({
|
||||
...otherFilters,
|
||||
@ -137,15 +143,9 @@ export class PaymentsComponent implements OnInit {
|
||||
invoice_ids,
|
||||
});
|
||||
this.fetchPaymentsService.load(searchParams, options);
|
||||
this.active =
|
||||
countProps(
|
||||
omit(searchParams, 'payment_params', 'common_search_query_params'),
|
||||
searchParams.payment_params,
|
||||
omit(searchParams.common_search_query_params, 'from_time', 'to_time'),
|
||||
) + +!isEqualDateRange(dateRange, createDateRangeToToday(this.dateRangeDays));
|
||||
}
|
||||
|
||||
update(options?: LoadOptions) {
|
||||
reload(options?: LoadOptions) {
|
||||
this.fetchPaymentsService.reload(options);
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ export class PaymentsComponent implements OnInit {
|
||||
.afterClosed()
|
||||
.subscribe((res) => {
|
||||
if (res.status === DialogResponseStatus.Success) {
|
||||
this.update();
|
||||
this.reload();
|
||||
this.selected$.next([]);
|
||||
} else if (res.data?.errors?.length) {
|
||||
this.selected$.next(res.data.errors.map(({ data }) => data));
|
||||
@ -174,7 +174,7 @@ export class PaymentsComponent implements OnInit {
|
||||
.afterClosed()
|
||||
.subscribe((res) => {
|
||||
if (res.status === DialogResponseStatus.Success) {
|
||||
this.update();
|
||||
this.reload();
|
||||
this.selected$.next([]);
|
||||
} else if (res.data?.errors?.length) {
|
||||
this.selected$.next(
|
||||
|
@ -15,6 +15,8 @@ import { PageLayoutModule, ShopFieldModule } from '@cc/app/shared';
|
||||
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
|
||||
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||
|
||||
import { MagistaThriftFormComponent } from '../../shared/components/thrift-api-crud';
|
||||
|
||||
import { CreatePaymentAdjustmentComponent } from './components/create-payment-adjustment/create-payment-adjustment.component';
|
||||
import { PaymentsTableComponent } from './components/payments-table/payments-table.component';
|
||||
import { PaymentsRoutingModule } from './payments-routing.module';
|
||||
@ -37,6 +39,7 @@ import { PaymentsComponent } from './payments.component';
|
||||
ShopFieldModule,
|
||||
InputFieldModule,
|
||||
FormsModule,
|
||||
MagistaThriftFormComponent,
|
||||
],
|
||||
declarations: [PaymentsComponent, CreatePaymentAdjustmentComponent, PaymentsTableComponent],
|
||||
})
|
||||
|
@ -1,15 +1,16 @@
|
||||
import { Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { DialogResponseStatus, DialogSuperclass } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogSuperclass,
|
||||
NotifyLogService,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import { PayoutID } from '@vality/payout-manager-proto/payout_manager';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { PayoutManagementService } from '@cc/app/api/payout-manager';
|
||||
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||
import { progressTo } from '@cc/utils/operators';
|
||||
|
||||
import { NotificationErrorService } from '../../../../../shared/services/notification-error';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-cancel-payout-dialog',
|
||||
@ -24,8 +25,7 @@ export class CancelPayoutDialogComponent extends DialogSuperclass<
|
||||
|
||||
constructor(
|
||||
private payoutManagementService: PayoutManagementService,
|
||||
private notificationService: NotificationService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -38,9 +38,9 @@ export class CancelPayoutDialogComponent extends DialogSuperclass<
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.dialogRef.close({ status: DialogResponseStatus.Success });
|
||||
this.notificationService.success('Payout canceled successfully');
|
||||
this.log.success('Payout canceled successfully');
|
||||
},
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { DialogResponseStatus, DialogSuperclass } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogSuperclass,
|
||||
NotifyLogService,
|
||||
progressTo,
|
||||
toMinor,
|
||||
} from '@vality/ng-core';
|
||||
import { PayoutParams } from '@vality/payout-manager-proto/payout_manager';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import omitBy from 'lodash-es/omitBy';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { PayoutManagementService } from '@cc/app/api/payout-manager';
|
||||
import { NotificationService } from '@cc/app/shared/services/notification';
|
||||
import { progressTo } from '@cc/utils/operators';
|
||||
import { toMinor } from '@cc/utils/to-minor';
|
||||
|
||||
import { NotificationErrorService } from '../../../../../shared/services/notification-error';
|
||||
|
||||
interface CreatePayoutDialogForm {
|
||||
partyId: string;
|
||||
@ -40,8 +41,7 @@ export class CreatePayoutDialogComponent extends DialogSuperclass<CreatePayoutDi
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private payoutManagementService: PayoutManagementService,
|
||||
private notificationService: NotificationService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -58,7 +58,7 @@ export class CreatePayoutDialogComponent extends DialogSuperclass<CreatePayoutDi
|
||||
party_id: value.partyId,
|
||||
},
|
||||
cash: {
|
||||
amount: toMinor(value.amount),
|
||||
amount: toMinor(value.amount, value.currency), // TODO use domain currencies refs
|
||||
currency: { symbolic_code: value.currency },
|
||||
},
|
||||
payout_tool_id: value.payoutToolId,
|
||||
@ -69,10 +69,10 @@ export class CreatePayoutDialogComponent extends DialogSuperclass<CreatePayoutDi
|
||||
.pipe(takeUntilDestroyed(this.destroyRef), progressTo(this.progress$))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.notificationService.success('Payout created successfully');
|
||||
this.log.success('Payout created successfully');
|
||||
this.dialogRef.close({ status: DialogResponseStatus.Success });
|
||||
},
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
<v-filters #filters [active]="active" merge (clear)="filtersForm.reset()">
|
||||
<v-filters #filters [active]="active$ | async" merge (clear)="filtersForm.reset()">
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<v-date-range-field formControlName="dateRange" required></v-date-range-field>
|
||||
<mat-form-field>
|
||||
@ -52,7 +52,7 @@
|
||||
[hasMore]="hasMore$ | async"
|
||||
[progress]="inProgress$ | async"
|
||||
(more)="more()"
|
||||
(update)="search($event)"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<v-table-actions>
|
||||
<button color="primary" mat-raised-button (click)="create()">Create</button>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component, OnInit, Inject, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { NonNullableFormBuilder } from '@angular/forms';
|
||||
import { Party, Shop, ShopID, PartyID } from '@vality/domain-proto/domain';
|
||||
import { magista } from '@vality/magista-proto';
|
||||
import { StatPayout } from '@vality/magista-proto/magista';
|
||||
@ -14,18 +14,17 @@ import {
|
||||
Column,
|
||||
createOperationColumn,
|
||||
DateRange,
|
||||
countProps,
|
||||
isEqualDateRange,
|
||||
UpdateOptions,
|
||||
debounceTimeWithFirst,
|
||||
countChanged,
|
||||
} from '@vality/ng-core';
|
||||
import { endOfDay } from 'date-fns';
|
||||
import omit from 'lodash-es/omit';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { getUnionKey } from '../../../../utils';
|
||||
import { createCurrencyColumn, createPartyColumn, createShopColumn } from '../../../shared';
|
||||
import { DATE_RANGE_DAYS } from '../../../tokens';
|
||||
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../../tokens';
|
||||
import { PayoutActionsService } from '../services/payout-actions.service';
|
||||
|
||||
import { CreatePayoutDialogComponent } from './components/create-payout-dialog/create-payout-dialog.component';
|
||||
@ -102,7 +101,12 @@ export class PayoutsComponent implements OnInit {
|
||||
];
|
||||
statusTypeEnum = magista.PayoutStatusType;
|
||||
payoutToolTypeEnum = magista.PayoutToolType;
|
||||
active = 0;
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFilters, v)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
private initFilters = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private fetchPayoutsService: FetchPayoutsService,
|
||||
@ -110,19 +114,19 @@ export class PayoutsComponent implements OnInit {
|
||||
private dialogService: DialogService,
|
||||
@Inject(DATE_RANGE_DAYS) private dateRangeDays: number,
|
||||
private payoutActionsService: PayoutActionsService,
|
||||
private fb: FormBuilder,
|
||||
private fb: NonNullableFormBuilder,
|
||||
private destroyRef: DestroyRef,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(this.qp.params);
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(
|
||||
filter(() => this.filtersForm.valid),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe((value) => void this.qp.set(clean(value)));
|
||||
this.qp.params$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.search());
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.qp.set(clean(value));
|
||||
this.search();
|
||||
});
|
||||
}
|
||||
|
||||
more() {
|
||||
@ -130,10 +134,7 @@ export class PayoutsComponent implements OnInit {
|
||||
}
|
||||
|
||||
search(options?: UpdateOptions) {
|
||||
const value = this.qp.params;
|
||||
if (!value.dateRange) {
|
||||
return;
|
||||
}
|
||||
const value = clean(this.filtersForm.value);
|
||||
this.fetchPayoutsService.load(
|
||||
clean({
|
||||
common_search_query_params: clean({
|
||||
@ -151,9 +152,10 @@ export class PayoutsComponent implements OnInit {
|
||||
}),
|
||||
options,
|
||||
);
|
||||
this.active =
|
||||
countProps(omit(value, 'dateRange')) +
|
||||
+!isEqualDateRange(value.dateRange, createDateRangeToToday(this.dateRangeDays));
|
||||
}
|
||||
|
||||
reload(options?: UpdateOptions) {
|
||||
this.fetchPayoutsService.reload(options);
|
||||
}
|
||||
|
||||
create() {
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { Injectable, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { PayoutID, PayoutStatus } from '@vality/magista-proto/magista';
|
||||
import { DialogResponseStatus, DialogService, ConfirmDialogComponent } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogService,
|
||||
ConfirmDialogComponent,
|
||||
NotifyLogService,
|
||||
} from '@vality/ng-core';
|
||||
import { switchMap } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
import { PayoutManagementService } from '@cc/app/api/payout-manager';
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
|
||||
import { CancelPayoutDialogComponent } from '../payouts/components/cancel-payout-dialog/cancel-payout-dialog.component';
|
||||
|
||||
@ -15,7 +19,7 @@ export class PayoutActionsService {
|
||||
constructor(
|
||||
private payoutManagementService: PayoutManagementService,
|
||||
private dialogService: DialogService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {}
|
||||
|
||||
@ -41,7 +45,7 @@ export class PayoutActionsService {
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe({
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,13 @@
|
||||
import { Component, OnInit, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Validators, FormControl } from '@angular/forms';
|
||||
import { DialogResponseStatus, DialogSuperclass, getValue } from '@vality/ng-core';
|
||||
import {
|
||||
DialogResponseStatus,
|
||||
DialogSuperclass,
|
||||
getValue,
|
||||
NotifyLogService,
|
||||
progressTo,
|
||||
} from '@vality/ng-core';
|
||||
import {
|
||||
RepairInvoicesRequest,
|
||||
RepairWithdrawalsRequest,
|
||||
@ -12,11 +18,8 @@ import { BehaviorSubject, from } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
|
||||
import { progressTo } from '../../../../../utils';
|
||||
import { RepairManagementService } from '../../../../api/repairer';
|
||||
import { NotificationService } from '../../../../shared/services/notification';
|
||||
|
||||
enum Types {
|
||||
Same,
|
||||
@ -58,8 +61,7 @@ export class RepairByScenarioDialogComponent
|
||||
|
||||
constructor(
|
||||
private repairManagementService: RepairManagementService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private notificationService: NotificationService,
|
||||
private log: NotifyLogService,
|
||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
@ -91,10 +93,10 @@ export class RepairByScenarioDialogComponent
|
||||
.pipe(progressTo(this.progress$), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.notificationService.success();
|
||||
this.log.success();
|
||||
this.dialogRef.close({ status: DialogResponseStatus.Success });
|
||||
},
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
<v-filters #filters [active]="active" merge (clear)="filtersForm.reset()">
|
||||
<v-filters #filters [active]="active$ | async" merge (clear)="filtersForm.reset()">
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<v-date-range-field formControlName="timespan"></v-date-range-field>
|
||||
<v-list-field formControlName="ids" label="IDs"></v-list-field>
|
||||
@ -40,9 +40,9 @@
|
||||
[progress]="inProgress$ | async"
|
||||
[rowSelected]="selected$ | async"
|
||||
rowSelectable
|
||||
(more)="fetchMore()"
|
||||
(more)="more()"
|
||||
(rowSelectedChange)="selected$.next($event)"
|
||||
(update)="update($event.size)"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<v-table-actions>
|
||||
<button
|
||||
|
@ -11,25 +11,25 @@ import {
|
||||
NotifyLogService,
|
||||
DateRange,
|
||||
getNoTimeZoneIsoString,
|
||||
countProps,
|
||||
createDateRangeToToday,
|
||||
isEqualDateRange,
|
||||
getValueChanges,
|
||||
countChanged,
|
||||
debounceTimeWithFirst,
|
||||
FetchOptions,
|
||||
getEnumKey,
|
||||
} from '@vality/ng-core';
|
||||
import { repairer } from '@vality/repairer-proto';
|
||||
import { Namespace, ProviderID, RepairStatus, Machine } from '@vality/repairer-proto/repairer';
|
||||
import { endOfDay } from 'date-fns';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import omit from 'lodash-es/omit';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { filter, switchMap, debounceTime } from 'rxjs/operators';
|
||||
|
||||
import { getEnumKey } from '@cc/utils';
|
||||
import { filter, switchMap, map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { RepairManagementService } from '../../api/repairer';
|
||||
import { createProviderColumn } from '../../shared/utils/table/create-provider-column';
|
||||
import { DATE_RANGE_DAYS } from '../../tokens';
|
||||
import { DATE_RANGE_DAYS, DEBOUNCE_TIME_MS } from '../../tokens';
|
||||
|
||||
import { RepairByScenarioDialogComponent } from './components/repair-by-scenario-dialog/repair-by-scenario-dialog.component';
|
||||
import { MachinesService } from './services/machines.service';
|
||||
@ -49,8 +49,8 @@ interface Filters {
|
||||
providers: [MachinesService],
|
||||
})
|
||||
export class RepairingComponent implements OnInit {
|
||||
machines$ = this.machinesService.searchResult$;
|
||||
inProgress$ = this.machinesService.doAction$;
|
||||
machines$ = this.machinesService.result$;
|
||||
inProgress$ = this.machinesService.isLoading$;
|
||||
hasMore$ = this.machinesService.hasMore$;
|
||||
filtersForm = this.fb.group({
|
||||
ids: [null as string[]],
|
||||
@ -89,7 +89,12 @@ export class RepairingComponent implements OnInit {
|
||||
field: 'error_message',
|
||||
},
|
||||
];
|
||||
active = 0;
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFilters, v, { timespan: isEqualDateRange })),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
private initFilters = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private machinesService: MachinesService,
|
||||
@ -100,16 +105,17 @@ export class RepairingComponent implements OnInit {
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
@Inject(DATE_RANGE_DAYS) private dateRangeDays: number,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(this.qp.params);
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(debounceTime(500), takeUntilDestroyed(this.destroyRef))
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((params: Filters) => {
|
||||
const { ids, ns, timespan, provider_id, status, error_message } = params;
|
||||
void this.qp.set(clean(params));
|
||||
this.machinesService.search(
|
||||
this.machinesService.load(
|
||||
clean({
|
||||
ids,
|
||||
ns,
|
||||
@ -125,19 +131,15 @@ export class RepairingComponent implements OnInit {
|
||||
: null,
|
||||
}),
|
||||
);
|
||||
this.active =
|
||||
countProps(omit(clean(params), 'timespan')) +
|
||||
+!isEqualDateRange(timespan, createDateRangeToToday(this.dateRangeDays));
|
||||
});
|
||||
}
|
||||
|
||||
update(size: number) {
|
||||
this.machinesService.refresh(size);
|
||||
this.selected$.next([]);
|
||||
reload(options?: FetchOptions) {
|
||||
this.machinesService.reload(options);
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.machinesService.fetchMore();
|
||||
more() {
|
||||
this.machinesService.more();
|
||||
}
|
||||
|
||||
repair() {
|
||||
|
@ -1,32 +1,36 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FetchSuperclass, NotifyLogService, FetchOptions } from '@vality/ng-core';
|
||||
import { Machine, SearchRequest } from '@vality/repairer-proto/repairer';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { of } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { RepairManagementService } from '../../../api/repairer';
|
||||
import { PartialFetcher } from '../../../shared/services';
|
||||
import { NotificationErrorService } from '../../../shared/services/notification-error';
|
||||
|
||||
@Injectable()
|
||||
export class MachinesService extends PartialFetcher<Machine, SearchRequest> {
|
||||
export class MachinesService extends FetchSuperclass<Machine, SearchRequest> {
|
||||
constructor(
|
||||
private repairManagementService: RepairManagementService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected fetch(params: SearchRequest, continuationToken: string, size: number) {
|
||||
protected fetch(params: SearchRequest, options: FetchOptions) {
|
||||
return this.repairManagementService
|
||||
.Search({ limit: size, continuation_token: continuationToken, ...params })
|
||||
.Search({
|
||||
limit: options.size,
|
||||
continuation_token: options.continuationToken,
|
||||
...params,
|
||||
})
|
||||
.pipe(
|
||||
map(({ machines, continuation_token }) => ({
|
||||
result: machines,
|
||||
continuationToken: continuation_token,
|
||||
})),
|
||||
catchError((err) => {
|
||||
this.log.error(err);
|
||||
return of({ result: [] });
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
protected handleError(err) {
|
||||
this.notificationErrorService.error(err);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
|
||||
import { RoutingRulesService } from '../services/routing-rules';
|
||||
import { TargetRuleset } from '../target-ruleset-form';
|
||||
import { RoutingRulesType } from '../types/routing-rules-type';
|
||||
@ -23,7 +21,7 @@ export class ChangeTargetDialogComponent extends DialogSuperclass<
|
||||
|
||||
constructor(
|
||||
private routingRulesService: RoutingRulesService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -51,6 +49,6 @@ export class ChangeTargetDialogComponent extends DialogSuperclass<
|
||||
delegateIdx,
|
||||
})
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => this.dialogRef.close(), this.notificationErrorService.error);
|
||||
.subscribe(() => this.dialogRef.close(), this.log.error);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { UntypedFormBuilder } from '@angular/forms';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { RoutingRulesType } from '@cc/app/sections/routing-rules/types/routing-rules-type';
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
|
||||
import { RoutingRulesService } from '../../services/routing-rules';
|
||||
import { TargetRuleset } from '../../target-ruleset-form';
|
||||
@ -31,7 +30,7 @@ export class AttachNewRulesetDialogComponent extends DialogSuperclass<
|
||||
constructor(
|
||||
private fb: UntypedFormBuilder,
|
||||
private routingRulesService: RoutingRulesService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -49,7 +48,7 @@ export class AttachNewRulesetDialogComponent extends DialogSuperclass<
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe({
|
||||
next: () => this.dialogRef.close(),
|
||||
error: (err) => this.notificationErrorService.error(err),
|
||||
error: (err) => this.log.error(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,11 @@ import { ChangeDetectionStrategy, Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DialogService, NotifyLogService } from '@vality/ng-core';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { first, map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||
import { RoutingRulesType } from '@cc/app/sections/routing-rules/types/routing-rules-type';
|
||||
|
||||
import { handleError } from '../../../../utils';
|
||||
import { RoutingRulesTypeService } from '../routing-rules-type.service';
|
||||
import { RoutingRulesService } from '../services/routing-rules';
|
||||
|
||||
@ -73,7 +72,13 @@ export class PartyDelegateRulesetsComponent {
|
||||
type: this.route.snapshot.params.type,
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(handleError(this.log.error), takeUntilDestroyed(this.destroyRef))
|
||||
.pipe(
|
||||
catchError((err) => {
|
||||
this.log.error(err);
|
||||
throw err;
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { Shop } from '@vality/domain-proto/domain';
|
||||
import { StatWallet } from '@vality/fistful-proto/fistful_stat';
|
||||
import { DialogResponseStatus, DialogSuperclass } from '@vality/ng-core';
|
||||
|
||||
import { NotificationErrorService } from '@cc/app/shared/services/notification-error';
|
||||
import { DialogResponseStatus, DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
|
||||
import { RoutingRulesService } from '../../services/routing-rules';
|
||||
import { RoutingRulesType } from '../../types/routing-rules-type';
|
||||
@ -27,7 +25,7 @@ export class AddPartyRoutingRuleDialogComponent extends DialogSuperclass<
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private routingRulesService: RoutingRulesService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -49,7 +47,7 @@ export class AddPartyRoutingRuleDialogComponent extends DialogSuperclass<
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe({
|
||||
next: () => this.dialogRef.close({ status: DialogResponseStatus.Success }),
|
||||
error: this.notificationErrorService.error,
|
||||
error: this.log.error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Component, DestroyRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { UntypedFormBuilder } from '@angular/forms';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
|
||||
import { NotificationErrorService } from '../../../../shared/services/notification-error';
|
||||
import { RoutingRulesService } from '../../services/routing-rules';
|
||||
|
||||
@Component({
|
||||
@ -23,7 +22,7 @@ export class InitializeRoutingRulesDialogComponent extends DialogSuperclass<
|
||||
constructor(
|
||||
private fb: UntypedFormBuilder,
|
||||
private routingRulesService: RoutingRulesService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {
|
||||
super();
|
||||
@ -40,6 +39,6 @@ export class InitializeRoutingRulesDialogComponent extends DialogSuperclass<
|
||||
delegateDescription,
|
||||
})
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => this.dialogRef.close(), this.notificationErrorService.error);
|
||||
.subscribe(() => this.dialogRef.close(), this.log.error);
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,8 @@ import {
|
||||
ComponentChanges,
|
||||
NotifyLogService,
|
||||
} from '@vality/ng-core';
|
||||
import { filter, switchMap } from 'rxjs/operators';
|
||||
import { filter, switchMap, catchError } from 'rxjs/operators';
|
||||
|
||||
import { handleError } from '../../../../utils/operators/handle-error';
|
||||
import { ChangeDelegateRulesetDialogComponent } from '../change-delegate-ruleset-dialog';
|
||||
import { ChangeTargetDialogComponent } from '../change-target-dialog';
|
||||
import { RoutingRulesService } from '../services/routing-rules';
|
||||
@ -120,7 +119,13 @@ export class RoutingRulesListComponent<
|
||||
delegateIdx: delegateId.delegateIdx,
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(handleError(this.log.error), takeUntilDestroyed(this.destroyRef))
|
||||
.pipe(
|
||||
catchError((err) => {
|
||||
this.log.error(err);
|
||||
throw err;
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { getEnumValues } from '@vality/ng-core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { startWith, map } from 'rxjs/operators';
|
||||
|
||||
import { getEnumValues } from '../../../utils';
|
||||
|
||||
import { RoutingRulesType } from './types/routing-rules-type';
|
||||
|
||||
@Injectable()
|
||||
|
@ -7,6 +7,6 @@
|
||||
externalFilter
|
||||
noActions
|
||||
(filterChange)="searchParamsUpdated($event)"
|
||||
(update)="update()"
|
||||
(update)="reload($event)"
|
||||
></v-table>
|
||||
</cc-page-layout>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Party } from '@vality/deanonimus-proto/deanonimus';
|
||||
import { Column, createOperationColumn, QueryParamsService } from '@vality/ng-core';
|
||||
import { Column, createOperationColumn, QueryParamsService, UpdateOptions } from '@vality/ng-core';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@ -16,8 +16,8 @@ import { getUnionKey } from '../../../utils';
|
||||
})
|
||||
export class SearchPartiesComponent {
|
||||
initSearchParams$ = this.qp.params$.pipe(map((p) => p?.text ?? ''));
|
||||
inProgress$ = this.fetchPartiesService.inProgress$;
|
||||
parties$ = this.fetchPartiesService.parties$;
|
||||
inProgress$ = this.fetchPartiesService.isLoading$;
|
||||
parties$ = this.fetchPartiesService.result$;
|
||||
columns: Column<Party>[] = [
|
||||
{ field: 'id' },
|
||||
{
|
||||
@ -70,10 +70,10 @@ export class SearchPartiesComponent {
|
||||
|
||||
searchParamsUpdated(filter: string) {
|
||||
void this.qp.set({ text: filter });
|
||||
this.fetchPartiesService.searchParties(filter);
|
||||
this.fetchPartiesService.load(filter);
|
||||
}
|
||||
|
||||
update() {
|
||||
this.fetchPartiesService.searchParties(this.qp.params.text);
|
||||
reload(options: UpdateOptions) {
|
||||
this.fetchPartiesService.reload(options);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
|
||||
import { FistfulAdminService } from '../../../api/fistful-admin';
|
||||
import { NotificationService } from '../../../shared/services/notification';
|
||||
import { NotificationErrorService } from '../../../shared/services/notification-error';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-create-source',
|
||||
@ -15,8 +13,7 @@ export class CreateSourceComponent extends DialogSuperclass<void> {
|
||||
|
||||
constructor(
|
||||
private fistfulAdminService: FistfulAdminService,
|
||||
private errorService: NotificationErrorService,
|
||||
private notificationService: NotificationService,
|
||||
private log: NotifyLogService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@ -25,10 +22,10 @@ export class CreateSourceComponent extends DialogSuperclass<void> {
|
||||
this.fistfulAdminService.CreateSource(this.control.value).subscribe({
|
||||
next: () => {
|
||||
this.closeWithSuccess();
|
||||
this.notificationService.success('Source created successfully!');
|
||||
this.log.success('Source created successfully!');
|
||||
},
|
||||
error: (err) => {
|
||||
this.errorService.error(err);
|
||||
this.log.error(err);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatSource } from '@vality/fistful-proto/internal/fistful_stat';
|
||||
import { compareDifferentTypes, NotifyLogService } from '@vality/ng-core';
|
||||
import { compareDifferentTypes, NotifyLogService, progressTo } from '@vality/ng-core';
|
||||
import { Observable, switchMap, of, BehaviorSubject } from 'rxjs';
|
||||
import { shareReplay, map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { FistfulStatisticsService, createDsl } from '@cc/app/api/fistful-stat';
|
||||
import { progressTo } from '@cc/utils';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
@ -10,7 +10,12 @@
|
||||
<!-- ]"-->
|
||||
<!-- ></v-switch-button>-->
|
||||
</cc-page-layout-actions>
|
||||
<v-filters *ngIf="isFilterControl.value" [active]="active" merge (clear)="filtersForm.reset()">
|
||||
<v-filters
|
||||
*ngIf="isFilterControl.value"
|
||||
[active]="active$ | async"
|
||||
merge
|
||||
(clear)="filtersForm.reset()"
|
||||
>
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<cc-merchant-field
|
||||
*ngIf="!(party$ | async)"
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
runInInjectionContext,
|
||||
} from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormBuilder, FormControl } from '@angular/forms';
|
||||
import { FormControl, NonNullableFormBuilder } from '@angular/forms';
|
||||
import { SearchWalletHit } from '@vality/deanonimus-proto/internal/deanonimus';
|
||||
import { IdentityState } from '@vality/fistful-proto/identity';
|
||||
import { AccountBalance } from '@vality/fistful-proto/internal/account';
|
||||
@ -18,14 +18,15 @@ import {
|
||||
Column,
|
||||
QueryParamsService,
|
||||
NotifyLogService,
|
||||
countProps,
|
||||
FiltersComponent,
|
||||
UpdateOptions,
|
||||
getValueChanges,
|
||||
countChanged,
|
||||
debounceTimeWithFirst,
|
||||
} from '@vality/ng-core';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import { of } from 'rxjs';
|
||||
import { map, shareReplay, catchError, debounceTime, take } from 'rxjs/operators';
|
||||
import { map, shareReplay, catchError, take } from 'rxjs/operators';
|
||||
import { MemoizeExpiring } from 'typescript-memoize';
|
||||
|
||||
import { WalletParams } from '@cc/app/api/fistful-stat/query-dsl/types/wallet';
|
||||
@ -137,16 +138,21 @@ export class WalletsComponent implements OnInit {
|
||||
currency_code: null as string,
|
||||
wallet_id: [null as string[]],
|
||||
});
|
||||
active = 0;
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFilters, v)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
@ViewChild(FiltersComponent) filters!: FiltersComponent;
|
||||
typeQp = this.qp.createNamespace<{ isFilter: boolean }>('type');
|
||||
party$ = this.partyStoreService.party$;
|
||||
|
||||
private initFilters = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private fetchWalletsService: FetchWalletsService,
|
||||
private fetchWalletsTextService: FetchWalletsTextService,
|
||||
private qp: QueryParamsService<WalletParams>,
|
||||
private fb: FormBuilder,
|
||||
private fb: NonNullableFormBuilder,
|
||||
private walletManagementService: ManagementService,
|
||||
private log: NotifyLogService,
|
||||
@Inject(DEBOUNCE_TIME_MS) private debounceTimeMs: number,
|
||||
@ -168,7 +174,7 @@ export class WalletsComponent implements OnInit {
|
||||
void this.typeQp.set({ isFilter: !!value });
|
||||
});
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(debounceTime(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
void this.qp.set(clean(value));
|
||||
this.filterSearch();
|
||||
@ -177,7 +183,6 @@ export class WalletsComponent implements OnInit {
|
||||
|
||||
filterSearch(opts?: UpdateOptions) {
|
||||
const props = clean(this.filtersForm.value);
|
||||
this.active = countProps(props);
|
||||
this.partyStoreService.party$.pipe(take(1)).subscribe((p) => {
|
||||
this.fetchWalletsService.load(
|
||||
clean({
|
||||
|
@ -8,7 +8,7 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { TableModule, ListFieldModule, FiltersModule, SwitchButtonModule } from '@vality/ng-core';
|
||||
|
||||
import { AmountCurrencyPipe, PageLayoutModule } from '@cc/app/shared';
|
||||
import { PageLayoutModule } from '@cc/app/shared';
|
||||
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
|
||||
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||
|
||||
@ -30,7 +30,6 @@ import { WalletsComponent } from './wallets.component';
|
||||
MerchantFieldModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
AmountCurrencyPipe,
|
||||
PageLayoutModule,
|
||||
ListFieldModule,
|
||||
FiltersModule,
|
||||
|
@ -2,7 +2,7 @@
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
<v-filters #filters [active]="active" merge (clear)="filtersForm.reset()">
|
||||
<v-filters #filters [active]="active$ | async" merge (clear)="filtersForm.reset()">
|
||||
<ng-template [formGroup]="filtersForm">
|
||||
<v-date-range-field formControlName="dateRange"></v-date-range-field>
|
||||
<cc-merchant-field formControlName="merchant"></cc-merchant-field>
|
||||
@ -35,7 +35,7 @@
|
||||
[progress]="inProgress$ | async"
|
||||
rowSelectable
|
||||
(more)="more()"
|
||||
(update)="update($event)"
|
||||
(update)="reload($event)"
|
||||
>
|
||||
<v-table-actions>
|
||||
<button
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
QueryParamsService,
|
||||
Column,
|
||||
UpdateOptions,
|
||||
countProps,
|
||||
clean,
|
||||
DialogService,
|
||||
DateRange,
|
||||
@ -17,11 +16,12 @@ import {
|
||||
createDateRangeToToday,
|
||||
isEqualDateRange,
|
||||
getValueChanges,
|
||||
countChanged,
|
||||
debounceTimeWithFirst,
|
||||
} from '@vality/ng-core';
|
||||
import { endOfDay } from 'date-fns';
|
||||
import omit from 'lodash-es/omit';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { WithdrawalParams } from '@cc/app/api/fistful-stat';
|
||||
|
||||
@ -65,7 +65,10 @@ export class WithdrawalsComponent implements OnInit {
|
||||
providerId: null,
|
||||
terminalId: null,
|
||||
});
|
||||
active = 0;
|
||||
active$ = getValueChanges(this.filtersForm).pipe(
|
||||
map((v) => countChanged(this.initFilters, v, { dateRange: isEqualDateRange })),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
withdrawals$ = this.fetchWithdrawalsService.result$;
|
||||
inProgress$ = this.fetchWithdrawalsService.isLoading$;
|
||||
hasMore$ = this.fetchWithdrawalsService.hasMore$;
|
||||
@ -113,6 +116,8 @@ export class WithdrawalsComponent implements OnInit {
|
||||
selected: StatWithdrawal[] = [];
|
||||
statuses: WithdrawalParams['status'][] = ['Pending', 'Succeeded', 'Failed'];
|
||||
|
||||
private initFilters = this.filtersForm.value;
|
||||
|
||||
constructor(
|
||||
private fetchWithdrawalsService: FetchWithdrawalsService,
|
||||
private fb: NonNullableFormBuilder,
|
||||
@ -127,7 +132,7 @@ export class WithdrawalsComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(Object.assign({}, this.qp.params));
|
||||
getValueChanges(this.filtersForm)
|
||||
.pipe(debounceTime(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.pipe(debounceTimeWithFirst(this.debounceTimeMs), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => this.update());
|
||||
}
|
||||
|
||||
@ -158,15 +163,16 @@ export class WithdrawalsComponent implements OnInit {
|
||||
withdrawal_provider_id: providerId,
|
||||
});
|
||||
this.fetchWithdrawalsService.load(params, options);
|
||||
this.active =
|
||||
countProps(omit(params, 'from_time', 'to_time')) +
|
||||
+!isEqualDateRange(dateRange, createDateRangeToToday(this.dateRangeDays));
|
||||
}
|
||||
|
||||
more() {
|
||||
this.fetchWithdrawalsService.more();
|
||||
}
|
||||
|
||||
reload(options: UpdateOptions) {
|
||||
this.fetchWithdrawalsService.reload(options);
|
||||
}
|
||||
|
||||
adjustment() {
|
||||
this.dialogService.open(CreateAdjustmentDialogComponent, {
|
||||
withdrawals: this.selected,
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { Component, Input, AfterViewInit, booleanAttribute, DestroyRef } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
AfterViewInit,
|
||||
booleanAttribute,
|
||||
DestroyRef,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { PartyID } from '@vality/domain-proto/domain';
|
||||
import {
|
||||
@ -7,19 +14,15 @@ import {
|
||||
FormControlSuperclass,
|
||||
createControlProviders,
|
||||
getValueChanges,
|
||||
debounceTimeWithFirst,
|
||||
} from '@vality/ng-core';
|
||||
import { BehaviorSubject, Observable, of, ReplaySubject, Subject, merge } from 'rxjs';
|
||||
import {
|
||||
catchError,
|
||||
debounceTime,
|
||||
map,
|
||||
switchMap,
|
||||
tap,
|
||||
distinctUntilChanged,
|
||||
} from 'rxjs/operators';
|
||||
import { catchError, map, switchMap, tap, distinctUntilChanged } from 'rxjs/operators';
|
||||
|
||||
import { DeanonimusService } from '@cc/app/api/deanonimus';
|
||||
|
||||
import { DEBOUNCE_TIME_MS } from '../../../tokens';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-merchant-field',
|
||||
templateUrl: 'merchant-field.component.html',
|
||||
@ -39,6 +42,8 @@ export class MerchantFieldComponent
|
||||
searchChange$ = new Subject<string>();
|
||||
progress$ = new BehaviorSubject(false);
|
||||
|
||||
private debounceTimeMs = inject(DEBOUNCE_TIME_MS);
|
||||
|
||||
constructor(
|
||||
private deanonimusService: DeanonimusService,
|
||||
private log: NotifyLogService,
|
||||
@ -55,7 +60,7 @@ export class MerchantFieldComponent
|
||||
this.options$.next([]);
|
||||
this.progress$.next(true);
|
||||
}),
|
||||
debounceTime(600),
|
||||
debounceTimeWithFirst(this.debounceTimeMs),
|
||||
switchMap((term) => this.searchOptions(term)),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
|
@ -1,14 +1,18 @@
|
||||
import { Component, Input, OnInit, booleanAttribute } from '@angular/core';
|
||||
import { PayoutTool } from '@vality/domain-proto/domain';
|
||||
import { PartyID, ShopID } from '@vality/domain-proto/payment_processing';
|
||||
import { FormControlSuperclass, Option, createControlProviders } from '@vality/ng-core';
|
||||
import {
|
||||
FormControlSuperclass,
|
||||
Option,
|
||||
createControlProviders,
|
||||
NotifyLogService,
|
||||
handleError,
|
||||
} from '@vality/ng-core';
|
||||
import { BehaviorSubject, combineLatest, defer, Observable, of, switchMap } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
|
||||
import { handleError, NotificationErrorService } from '../../services/notification-error';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payout-tool-field',
|
||||
templateUrl: 'payout-tool-field.component.html',
|
||||
@ -47,13 +51,7 @@ export class PayoutToolFieldComponent
|
||||
),
|
||||
map((contract) => contract.payout_tools),
|
||||
)
|
||||
.pipe(
|
||||
handleError(
|
||||
this.notificationErrorService.error,
|
||||
null,
|
||||
of<PayoutTool[]>([]),
|
||||
),
|
||||
)
|
||||
.pipe(handleError(this.log.error, []))
|
||||
: of<PayoutTool[]>([]),
|
||||
),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
@ -61,7 +59,7 @@ export class PayoutToolFieldComponent
|
||||
|
||||
constructor(
|
||||
private partyManagementService: PartyManagementService,
|
||||
private notificationErrorService: NotificationErrorService,
|
||||
private log: NotifyLogService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
<cc-metadata-form
|
||||
[extensions]="extensions"
|
||||
<cc-thrift-editor
|
||||
[defaultValue]="defaultValue"
|
||||
[extensions]="extensions$ | async"
|
||||
[formControl]="control"
|
||||
[metadata]="metadata$ | async"
|
||||
[namespace]="namespace"
|
||||
[namespace]="namespace ?? defaultNamespace"
|
||||
[noToolbar]="noToolbar"
|
||||
[type]="type"
|
||||
></cc-metadata-form>
|
||||
></cc-thrift-editor>
|
||||
|
@ -1,25 +1,21 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ThriftAstMetadata } from '@vality/fistful-proto';
|
||||
import { FormControlSuperclass, createControlProviders } from '@vality/ng-core';
|
||||
import { from } from 'rxjs';
|
||||
import { createControlProviders, getImportValue } from '@vality/ng-core';
|
||||
|
||||
import { MetadataFormModule, MetadataFormExtension } from '../../../metadata-form';
|
||||
import { MetadataFormModule } from '../../../metadata-form';
|
||||
import { ThriftEditorModule } from '../../../thrift-editor';
|
||||
import { BaseThriftFormSuperclass } from '../../thrift-forms/utils/thrift-form-superclass';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'cc-magista-thrift-form',
|
||||
templateUrl: './magista-thrift-form.component.html',
|
||||
providers: createControlProviders(() => MagistaThriftFormComponent),
|
||||
imports: [CommonModule, ReactiveFormsModule, MetadataFormModule],
|
||||
imports: [CommonModule, ReactiveFormsModule, MetadataFormModule, ThriftEditorModule],
|
||||
})
|
||||
export class MagistaThriftFormComponent extends FormControlSuperclass<unknown> {
|
||||
@Input() namespace: string;
|
||||
@Input() type: string;
|
||||
|
||||
metadata$ = from(
|
||||
import('@vality/magista-proto/metadata.json').then((m) => m.default as ThriftAstMetadata[]),
|
||||
);
|
||||
extensions: MetadataFormExtension[] = [];
|
||||
export class MagistaThriftFormComponent extends BaseThriftFormSuperclass {
|
||||
metadata$ = getImportValue<ThriftAstMetadata[]>(import('@vality/magista-proto/metadata.json'));
|
||||
defaultNamespace = 'magista';
|
||||
}
|
||||
|
@ -1,89 +0,0 @@
|
||||
import { formatCurrency, getCurrencySymbol } from '@angular/common';
|
||||
import {
|
||||
Pipe,
|
||||
Inject,
|
||||
LOCALE_ID,
|
||||
DEFAULT_CURRENCY_CODE,
|
||||
PipeTransform,
|
||||
DestroyRef,
|
||||
} from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { CurrencyObject } from '@vality/domain-proto/domain';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import { ReplaySubject, combineLatest } from 'rxjs';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/domain-config';
|
||||
|
||||
import { toMajor } from '../../../utils';
|
||||
|
||||
@Pipe({
|
||||
standalone: true,
|
||||
pure: false,
|
||||
name: 'amountCurrency',
|
||||
})
|
||||
export class AmountCurrencyPipe implements PipeTransform {
|
||||
private params$ = new ReplaySubject<{
|
||||
amount: number;
|
||||
currencyCode: string;
|
||||
format: 'short' | 'long';
|
||||
}>(1);
|
||||
private latestValue: string = '';
|
||||
private isInit = false;
|
||||
|
||||
constructor(
|
||||
@Inject(LOCALE_ID) private _locale: string,
|
||||
@Inject(DEFAULT_CURRENCY_CODE) private _defaultCurrencyCode: string = 'USD',
|
||||
private domainStoreService: DomainStoreService,
|
||||
private destroyRef: DestroyRef,
|
||||
) {}
|
||||
|
||||
init() {
|
||||
this.isInit = true;
|
||||
combineLatest([
|
||||
this.domainStoreService.getObjects('currency').pipe(startWith([] as CurrencyObject[])),
|
||||
this.params$,
|
||||
])
|
||||
.pipe(
|
||||
map(([currencies, { amount, currencyCode, format }]) => {
|
||||
if (isNil(amount)) {
|
||||
return '?';
|
||||
}
|
||||
const exponent = currencies.find((c) => c.data.symbolic_code === currencyCode)
|
||||
?.data?.exponent;
|
||||
if (!currencyCode || !exponent) {
|
||||
return formatCurrency(
|
||||
toMajor(amount, exponent),
|
||||
this._locale,
|
||||
'',
|
||||
'',
|
||||
format === 'short' ? '0.0-2' : undefined,
|
||||
);
|
||||
}
|
||||
return formatCurrency(
|
||||
toMajor(amount, exponent),
|
||||
this._locale,
|
||||
getCurrencySymbol(currencyCode, 'narrow', this._locale),
|
||||
currencyCode,
|
||||
format === 'short' ? '0.0-2' : undefined,
|
||||
);
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe((value) => {
|
||||
this.latestValue = value;
|
||||
});
|
||||
}
|
||||
|
||||
transform(
|
||||
amount: number,
|
||||
currencyCode: string = this._defaultCurrencyCode,
|
||||
format: 'short' | 'long' = 'long',
|
||||
) {
|
||||
this.params$.next({ amount, currencyCode, format });
|
||||
if (!this.isInit) {
|
||||
this.init();
|
||||
}
|
||||
return this.latestValue;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
export * from './thrift';
|
||||
export * from './common';
|
||||
export * from './value-type-title';
|
||||
export * from './amount-currency.pipe';
|
||||
|
@ -1,43 +1,31 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Party } from '@vality/deanonimus-proto/deanonimus';
|
||||
import { NotifyLogService } from '@vality/ng-core';
|
||||
import { Observable, of, Subject, defer, BehaviorSubject } from 'rxjs';
|
||||
import { map, shareReplay, switchMap, debounceTime } from 'rxjs/operators';
|
||||
import {
|
||||
NotifyLogService,
|
||||
handleError,
|
||||
FetchOptions,
|
||||
SingleFetchSuperclass,
|
||||
} from '@vality/ng-core';
|
||||
import { of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { DeanonimusService } from '@cc/app/api/deanonimus';
|
||||
import { progressTo, inProgressFrom } from '@cc/utils';
|
||||
|
||||
import { handleError } from './notification-error';
|
||||
|
||||
@Injectable()
|
||||
export class FetchPartiesService {
|
||||
parties$: Observable<Party[]> = defer(() => this.searchParties$).pipe(
|
||||
debounceTime(200),
|
||||
switchMap((text) =>
|
||||
text
|
||||
? this.deanonimusService.searchParty(text).pipe(
|
||||
map((hits) => hits.map((hit) => hit.party)),
|
||||
handleError(this.log.error, null, of<Party[]>([])),
|
||||
progressTo(this.progress$),
|
||||
)
|
||||
: of([]),
|
||||
),
|
||||
shareReplay(1),
|
||||
);
|
||||
inProgress$ = inProgressFrom(
|
||||
() => this.progress$,
|
||||
() => this.parties$,
|
||||
);
|
||||
|
||||
private progress$ = new BehaviorSubject(0);
|
||||
private searchParties$: Subject<string> = new Subject();
|
||||
|
||||
export class FetchPartiesService extends SingleFetchSuperclass<Party, string> {
|
||||
constructor(
|
||||
private deanonimusService: DeanonimusService,
|
||||
private log: NotifyLogService,
|
||||
) {}
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
searchParties(text: string) {
|
||||
this.searchParties$.next(text);
|
||||
protected fetch(text: string, _options: FetchOptions) {
|
||||
return text
|
||||
? this.deanonimusService.searchParty(text).pipe(
|
||||
map((hits) => ({ result: hits.map((hit) => hit.party) })),
|
||||
handleError(this.log.error, { result: [] }),
|
||||
)
|
||||
: of({ result: [] });
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ export * from './app-auth-guard';
|
||||
export * from './fetch-parties.service';
|
||||
export * from './keycloak-token-info';
|
||||
export * from './user-info-based-id-generator';
|
||||
export * from './partial-fetcher';
|
||||
export * from './domain-metadata-form-extensions';
|
||||
export * from './domain-secret-service';
|
||||
export * from './amount-currency.service';
|
||||
|
@ -1,2 +0,0 @@
|
||||
export * from './notification-error.service';
|
||||
export * from './utils/handle-error';
|
@ -1,38 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
import { ErrorService } from './types/error-service';
|
||||
|
||||
const DEFAULT_DURATION_MS = 6000;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class NotificationErrorService implements ErrorService {
|
||||
constructor(private snackBar: MatSnackBar) {}
|
||||
|
||||
error = (error: unknown, clientMessage?: string): void => {
|
||||
let result: string;
|
||||
const name = String((error as Record<PropertyKey, unknown>)?.['name'] ?? '');
|
||||
const message = String((error as Record<PropertyKey, unknown>)?.['message'] ?? '');
|
||||
|
||||
if (clientMessage) {
|
||||
result = clientMessage;
|
||||
} else {
|
||||
result = message || name || 'Unknown error';
|
||||
}
|
||||
console.warn(
|
||||
[
|
||||
`❗️ Caught error: ${result}.`,
|
||||
name && `Name: ${name}.`,
|
||||
message && `Message: ${message}.`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' '),
|
||||
);
|
||||
this.snackBar.open(result, 'OK', {
|
||||
duration: DEFAULT_DURATION_MS,
|
||||
});
|
||||
};
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export interface ErrorService {
|
||||
error: (error: unknown, message?: string) => void;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Observable, EMPTY } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
export function handleError<T>(
|
||||
errorHandler: (error: unknown, message?: string) => void,
|
||||
message?: string,
|
||||
result: Observable<T> = EMPTY,
|
||||
) {
|
||||
return (source: Observable<T>): Observable<T> =>
|
||||
source.pipe(
|
||||
catchError((err) => {
|
||||
errorHandler(err, message);
|
||||
return result;
|
||||
}),
|
||||
);
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './notification.service';
|
@ -1,24 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
const DEFAULT_DURATION_MS = 3000;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class NotificationService {
|
||||
constructor(private snackBar: MatSnackBar) {}
|
||||
|
||||
success(message: string = 'Success') {
|
||||
return this.snackBar.open(message, 'OK', {
|
||||
duration: DEFAULT_DURATION_MS,
|
||||
});
|
||||
}
|
||||
|
||||
error(message: string = 'Error') {
|
||||
return this.snackBar.open(message, 'OK', {
|
||||
duration: DEFAULT_DURATION_MS,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const DEBOUNCE_FETCHER_ACTION_TIME = new InjectionToken<number>('debounceFetcherActionTime');
|
||||
export const DEFAULT_FETCHER_DEBOUNCE_ACTION_TIME = 300;
|
@ -1,5 +0,0 @@
|
||||
export interface FetchAction<P = unknown> {
|
||||
type: 'search' | 'fetchMore';
|
||||
value?: P;
|
||||
size?: number;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { FetchResult } from './fetch-result';
|
||||
|
||||
export type FetchFn<P, R> = (
|
||||
params: P,
|
||||
continuationToken?: string,
|
||||
size?: number,
|
||||
) => Observable<FetchResult<R>>;
|
@ -1,5 +0,0 @@
|
||||
export interface FetchResult<T> {
|
||||
result?: T[];
|
||||
continuationToken?: string;
|
||||
error?: unknown;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export * from './partial-fetcher';
|
||||
export * from './fetch-result';
|
||||
export * from './fetch-action';
|
||||
export * from './consts';
|
@ -1,2 +0,0 @@
|
||||
export * from './scan-action';
|
||||
export * from './scan-search-result';
|
@ -1,5 +0,0 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { scan } from 'rxjs/operators';
|
||||
|
||||
export const scanAction = <T>(s: Observable<T>) =>
|
||||
s.pipe(scan<T, T>((lastAction, currentAction) => ({ ...lastAction, ...currentAction }), null));
|
@ -1,48 +0,0 @@
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, first, map, mergeScan } from 'rxjs/operators';
|
||||
|
||||
import { FetchAction } from '../fetch-action';
|
||||
import { FetchFn } from '../fetch-fn';
|
||||
import { FetchResult } from '../fetch-result';
|
||||
|
||||
export const handleFetchResultError =
|
||||
<R>(result: R[] = [], continuationToken?: string) =>
|
||||
(s: Observable<FetchResult<R>>): Observable<FetchResult<R>> =>
|
||||
s.pipe(
|
||||
catchError((error) =>
|
||||
of<FetchResult<R>>({
|
||||
result,
|
||||
continuationToken,
|
||||
error,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
export const scanFetchResult =
|
||||
<P, R>(fn: FetchFn<P, R>, defSize: number) =>
|
||||
(s: Observable<FetchAction<P>>): Observable<FetchResult<R>> =>
|
||||
s.pipe(
|
||||
mergeScan<FetchAction<P>, FetchResult<R>>(
|
||||
({ result, continuationToken }, { type, value, size }) => {
|
||||
size = size ?? defSize;
|
||||
switch (type) {
|
||||
case 'search':
|
||||
return fn(value, undefined, size).pipe(
|
||||
first(),
|
||||
handleFetchResultError(),
|
||||
);
|
||||
case 'fetchMore':
|
||||
return fn(value, continuationToken, size).pipe(
|
||||
first(),
|
||||
map((r) => ({
|
||||
result: result.concat(r.result),
|
||||
continuationToken: r.continuationToken,
|
||||
})),
|
||||
handleFetchResultError(result, continuationToken),
|
||||
);
|
||||
}
|
||||
},
|
||||
{ result: [] },
|
||||
1,
|
||||
),
|
||||
);
|
@ -1,136 +0,0 @@
|
||||
import { DestroyRef, inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { EMPTY, merge, Observable, of, Subject } from 'rxjs';
|
||||
import {
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
map,
|
||||
pluck,
|
||||
share,
|
||||
shareReplay,
|
||||
startWith,
|
||||
switchMap,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { progress } from '@cc/app/shared/custom-operators';
|
||||
|
||||
import { FetchAction } from './fetch-action';
|
||||
import { FetchFn } from './fetch-fn';
|
||||
import { FetchResult } from './fetch-result';
|
||||
import { scanAction, scanFetchResult } from './operators';
|
||||
import { SHARE_REPLAY_CONF } from './utils/share-replay-conf';
|
||||
|
||||
// TODO: make free of subscription & UntilDestroy
|
||||
// TODO: share public props together
|
||||
// TODO: make fetcher injectable
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export abstract class PartialFetcher<R, P> {
|
||||
readonly fetchResultChanges$: Observable<{
|
||||
result: R[];
|
||||
hasMore: boolean;
|
||||
continuationToken: string;
|
||||
}>;
|
||||
|
||||
readonly searchResult$: Observable<R[]>;
|
||||
readonly hasMore$: Observable<boolean>;
|
||||
readonly doAction$: Observable<boolean>;
|
||||
readonly doSearchAction$: Observable<boolean>;
|
||||
readonly errors$: Observable<unknown>;
|
||||
|
||||
private action$ = new Subject<FetchAction<P>>();
|
||||
private destroyRef = inject(DestroyRef);
|
||||
|
||||
// TODO: make a dependency for DI
|
||||
constructor(
|
||||
debounceActionTime: number = 300,
|
||||
private size = 25,
|
||||
) {
|
||||
const actionWithParams$ = this.getActionWithParams(debounceActionTime);
|
||||
const fetchResult$ = this.getFetchResult(actionWithParams$);
|
||||
|
||||
this.fetchResultChanges$ = fetchResult$.pipe(
|
||||
map(({ result, continuationToken }) => ({
|
||||
result: result ?? [],
|
||||
continuationToken,
|
||||
hasMore: !!continuationToken,
|
||||
})),
|
||||
share(),
|
||||
);
|
||||
this.searchResult$ = this.fetchResultChanges$.pipe(
|
||||
pluck('result'),
|
||||
shareReplay(SHARE_REPLAY_CONF),
|
||||
);
|
||||
|
||||
this.hasMore$ = this.fetchResultChanges$.pipe(
|
||||
pluck('hasMore'),
|
||||
startWith(null as boolean),
|
||||
distinctUntilChanged(),
|
||||
shareReplay(SHARE_REPLAY_CONF),
|
||||
);
|
||||
|
||||
this.doAction$ = progress(actionWithParams$, fetchResult$, false).pipe(
|
||||
shareReplay(SHARE_REPLAY_CONF),
|
||||
);
|
||||
this.doSearchAction$ = progress(
|
||||
actionWithParams$.pipe(filter(({ type }) => type === 'search')),
|
||||
fetchResult$,
|
||||
true,
|
||||
).pipe(shareReplay(SHARE_REPLAY_CONF));
|
||||
this.errors$ = fetchResult$.pipe(
|
||||
switchMap(({ error }) => (error ? of(error) : EMPTY)),
|
||||
tap((error) => this.handleError(error)),
|
||||
share(),
|
||||
);
|
||||
|
||||
merge(
|
||||
this.searchResult$,
|
||||
this.hasMore$,
|
||||
this.doAction$,
|
||||
this.doSearchAction$,
|
||||
this.errors$,
|
||||
this.fetchResultChanges$,
|
||||
)
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
search(value: P, size?: number) {
|
||||
this.action$.next({ type: 'search', value, size });
|
||||
}
|
||||
|
||||
refresh(size?: number) {
|
||||
this.action$.next({ type: 'search', size });
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.action$.next({ type: 'fetchMore' });
|
||||
}
|
||||
|
||||
protected handleError(error: unknown): void {
|
||||
console.error('Partial fetcher error: ', error);
|
||||
}
|
||||
|
||||
protected abstract fetch(...args: Parameters<FetchFn<P, R>>): ReturnType<FetchFn<P, R>>;
|
||||
|
||||
private getActionWithParams(debounceActionTime: number): Observable<FetchAction<P>> {
|
||||
return this.action$.pipe(
|
||||
scanAction,
|
||||
debounceActionTime ? debounceTime(debounceActionTime) : tap(),
|
||||
share(),
|
||||
);
|
||||
}
|
||||
|
||||
private getFetchResult(
|
||||
actionWithParams$: Observable<FetchAction<P>>,
|
||||
): Observable<FetchResult<R>> {
|
||||
const fetchFn = this.fetch.bind(this) as FetchFn<P, R>;
|
||||
return actionWithParams$.pipe(
|
||||
scanFetchResult(fetchFn, this.size),
|
||||
shareReplay(SHARE_REPLAY_CONF),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
import { ShareReplayConfig } from 'rxjs';
|
||||
|
||||
// Default share replay config
|
||||
export const SHARE_REPLAY_CONF: ShareReplayConfig = { bufferSize: 1, refCount: true };
|
@ -1,13 +0,0 @@
|
||||
import { clean, isEmpty } from '@vality/ng-core';
|
||||
import isObject from 'lodash-es/isObject';
|
||||
|
||||
function isEmptyThrift(value: unknown): boolean {
|
||||
if (isObject(value) && value.constructor === Object) {
|
||||
return false;
|
||||
}
|
||||
return isEmpty(value);
|
||||
}
|
||||
|
||||
export function cleanThrift<T extends object>(obj: T) {
|
||||
return clean(obj, false, false, (v) => !isEmptyThrift(v));
|
||||
}
|
@ -1,2 +1 @@
|
||||
export * from './clean-thrift';
|
||||
export * from './table';
|
||||
|
@ -2,9 +2,6 @@ import { InjectionToken } from '@angular/core';
|
||||
import { MatDateFormats } from '@angular/material/core';
|
||||
import { DATE_QUERY_PARAMS_SERIALIZERS, Serializer } from '@vality/ng-core';
|
||||
|
||||
export const SMALL_SEARCH_LIMIT = new InjectionToken<number>('smallSearchLimit');
|
||||
export const DEFAULT_SMALL_SEARCH_LIMIT = 5;
|
||||
|
||||
export const DEFAULT_QUERY_PARAMS_SERIALIZERS: Serializer[] = DATE_QUERY_PARAMS_SERIALIZERS;
|
||||
|
||||
export const DEFAULT_MAT_DATE_FORMATS: MatDateFormats = {
|
||||
@ -20,7 +17,7 @@ export const DEFAULT_MAT_DATE_FORMATS: MatDateFormats = {
|
||||
};
|
||||
|
||||
export const DATE_RANGE_DAYS = new InjectionToken<number>('DATE_RANGE_DAYS');
|
||||
export const DEFAULT_DATE_RANGE_DAYS: number = 30;
|
||||
export const DEFAULT_DATE_RANGE_DAYS: number = 1;
|
||||
|
||||
export const DEBOUNCE_TIME_MS = new InjectionToken<number>('DEBOUNCE_TIME_MS');
|
||||
export const DEFAULT_DEBOUNCE_TIME_MS: number = 300;
|
||||
export const DEFAULT_DEBOUNCE_TIME_MS: number = 500;
|
||||
|
@ -1,43 +0,0 @@
|
||||
import { ValuesType } from 'utility-types';
|
||||
|
||||
export function getEnumEntries<E extends Record<PropertyKey, unknown>>(
|
||||
srcEnum: E,
|
||||
): [key: keyof E, value: ValuesType<E>][] {
|
||||
const entries = Object.entries(srcEnum);
|
||||
if (!entries.length) {
|
||||
return [];
|
||||
}
|
||||
const isValueNumberEnum = entries.some(([, v]) => typeof v === 'number');
|
||||
if (isValueNumberEnum) {
|
||||
return entries.filter(([, v]) => typeof v === 'number') as never;
|
||||
}
|
||||
return entries as never;
|
||||
}
|
||||
|
||||
export function getEnumKeyValues<E extends Record<PropertyKey, unknown>>(
|
||||
srcEnum: E,
|
||||
): { key: keyof E; value: ValuesType<E> }[] {
|
||||
return getEnumEntries(srcEnum).map(([key, value]) => ({ key, value }));
|
||||
}
|
||||
|
||||
export function getEnumKeys<E extends Record<PropertyKey, unknown>>(srcEnum: E): (keyof E)[] {
|
||||
return getEnumEntries(srcEnum).map(([k]) => k);
|
||||
}
|
||||
|
||||
export function getEnumValues<E extends Record<PropertyKey, unknown>>(srcEnum: E): ValuesType<E>[] {
|
||||
return getEnumEntries(srcEnum).map(([, v]) => v);
|
||||
}
|
||||
|
||||
export function getEnumKey<E extends Record<PropertyKey, unknown>>(
|
||||
srcEnum: E,
|
||||
value: ValuesType<E>,
|
||||
): keyof E {
|
||||
return getEnumKeyValues(srcEnum).find((e) => String(e.value) === String(value))?.key;
|
||||
}
|
||||
|
||||
export function enumHasValue<E extends Record<PropertyKey, unknown>>(
|
||||
srcEnum: E,
|
||||
value: ValuesType<E> | string,
|
||||
): value is ValuesType<E> {
|
||||
return getEnumValues(srcEnum).includes(value as ValuesType<E>);
|
||||
}
|
@ -1,14 +1,9 @@
|
||||
export * from './get-union-key';
|
||||
export * from './remove-empty-properties';
|
||||
export * from './wrap-values-to-array';
|
||||
export * from './thrift-json-converter';
|
||||
export * from './to-minor';
|
||||
export * from './to-major';
|
||||
export * from './thrift-utils';
|
||||
export * from './has-active-fragments';
|
||||
export * from './poll';
|
||||
export * from './operators';
|
||||
export * from './get-enum-keys';
|
||||
export * from './enumerate';
|
||||
export * from './thrift-instance';
|
||||
export * from './csv';
|
||||
|
@ -1,11 +0,0 @@
|
||||
import { merge, Observable, MonoTypeOperatorFunction, EMPTY, mergeMap } from 'rxjs';
|
||||
|
||||
import { ObservableOrFn, getObservable } from './get-observable';
|
||||
|
||||
export function attach<T>(attached: ObservableOrFn<T>, main: ObservableOrFn): Observable<T> {
|
||||
return merge(getObservable(attached), getObservable(main).pipe(mergeMap(() => EMPTY)));
|
||||
}
|
||||
|
||||
export function attachTo<T>(main: ObservableOrFn): MonoTypeOperatorFunction<T> {
|
||||
return (src$) => attach(src$, main);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { Observable, defer } from 'rxjs';
|
||||
|
||||
export type ObservableOrFn<T = unknown> = (() => Observable<T>) | Observable<T>;
|
||||
|
||||
export function getObservable<T>(obsOrFn: ObservableOrFn<T>): Observable<T> {
|
||||
return typeof obsOrFn === 'function' ? defer(obsOrFn) : obsOrFn;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Should be called once
|
||||
* It's better to use before the operator "share"
|
||||
*/
|
||||
export function handleError(handle: (error: unknown) => void) {
|
||||
return <T>(src$: Observable<T>) =>
|
||||
src$.pipe(
|
||||
catchError((error) => {
|
||||
handle(error);
|
||||
return throwError(error);
|
||||
}),
|
||||
);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { map, delay, share } from 'rxjs/operators';
|
||||
|
||||
import { attach } from './attach';
|
||||
import { getObservable, ObservableOrFn } from './get-observable';
|
||||
|
||||
export function inProgressFrom(progress: ObservableOrFn<number>, main?: ObservableOrFn) {
|
||||
return (main ? attach(progress, main) : getObservable(progress)).pipe(
|
||||
map(Boolean),
|
||||
// make async to bypass angular detect changes
|
||||
delay(0),
|
||||
share(),
|
||||
);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export * from './progress-to';
|
||||
export * from './handle-error';
|
||||
export * from './in-progress-from';
|
@ -1,13 +0,0 @@
|
||||
import { BehaviorSubject, defer, MonoTypeOperatorFunction, isObservable } from 'rxjs';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
|
||||
export function progressTo<T>(
|
||||
subject$: BehaviorSubject<number> | (() => BehaviorSubject<number>),
|
||||
): MonoTypeOperatorFunction<T> {
|
||||
const getSub = () => (isObservable(subject$) ? subject$ : subject$());
|
||||
return (src$) =>
|
||||
defer(() => {
|
||||
getSub().next(getSub().getValue() + 1);
|
||||
return src$.pipe(finalize(() => getSub().next(getSub().getValue() - 1)));
|
||||
});
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
import identity from 'lodash-es/identity';
|
||||
import pickBy from 'lodash-es/pickBy';
|
||||
|
||||
export const removeEmptyProperties = <T extends object>(s: T) => pickBy(s, identity) as Partial<T>;
|
@ -1,9 +0,0 @@
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import round from 'lodash-es/round';
|
||||
|
||||
export const toMajor = (amount: number, exponent = 2): number | null => {
|
||||
if (isNil(amount)) {
|
||||
return null;
|
||||
}
|
||||
return round(amount / 10 ** exponent, exponent);
|
||||
};
|
@ -1,2 +0,0 @@
|
||||
export const toMinor = (amount: number, exponent = 2): number =>
|
||||
Math.round(amount * 10 ** exponent);
|
Loading…
Reference in New Issue
Block a user