IMP-88,IMP-133: Full-text search by wallets, wallets autocomplete for withdrawals and deposits (#355)

This commit is contained in:
Rinat Arsaev 2024-05-07 11:16:00 +05:00 committed by GitHub
parent 7ea5d9a403
commit 31460f99d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 137 additions and 20 deletions

View File

@ -18,7 +18,7 @@
</mat-form-field> </mat-form-field>
<v-input-field formControlName="deposit_id" label="Deposit ID"></v-input-field> <v-input-field formControlName="deposit_id" label="Deposit ID"></v-input-field>
<v-input-field formControlName="identity_id" label="Identity ID"></v-input-field> <v-input-field formControlName="identity_id" label="Identity ID"></v-input-field>
<v-input-field formControlName="wallet_id" label="Wallet ID"></v-input-field> <cc-wallet-field formControlName="wallet_id"></cc-wallet-field>
<cc-merchant-field formControlName="party_id"></cc-merchant-field> <cc-merchant-field formControlName="party_id"></cc-merchant-field>
</ng-template> </ng-template>
</v-filters> </v-filters>

View File

@ -49,7 +49,7 @@ export class DepositsComponent implements OnInit {
status: '' as QueryDsl['query']['deposits']['status'], status: '' as QueryDsl['query']['deposits']['status'],
deposit_id: '', deposit_id: '',
identity_id: '', identity_id: '',
wallet_id: '', wallet_id: null as string,
party_id: null as string, party_id: null as string,
}); });
deposits$ = this.fetchDepositsService.result$; deposits$ = this.fetchDepositsService.result$;

View File

@ -19,7 +19,7 @@ import {
SelectFieldModule, SelectFieldModule,
} from '@vality/ng-core'; } from '@vality/ng-core';
import { PageLayoutModule } from '../../shared'; import { PageLayoutModule, WalletFieldModule } from '../../shared';
import { CurrencyFieldComponent } from '../../shared/components/currency-field'; import { CurrencyFieldComponent } from '../../shared/components/currency-field';
import { MerchantFieldModule } from '../../shared/components/merchant-field'; import { MerchantFieldModule } from '../../shared/components/merchant-field';
@ -51,6 +51,7 @@ import { DepositsComponent } from './deposits.component';
AutocompleteFieldModule, AutocompleteFieldModule,
SelectFieldModule, SelectFieldModule,
CurrencyFieldComponent, CurrencyFieldComponent,
WalletFieldModule,
], ],
declarations: [DepositsComponent], declarations: [DepositsComponent],
}) })

View File

@ -1,14 +1,13 @@
<cc-page-layout title="Wallets"> <cc-page-layout title="Wallets">
<cc-page-layout-actions> <cc-page-layout-actions>
<v-more-filters-button *ngIf="filters" [filters]="filters"></v-more-filters-button> <v-more-filters-button *ngIf="filters" [filters]="filters"></v-more-filters-button>
<!--TODO wait backend fix--> <v-switch-button
<!-- <v-switch-button--> [formControl]="isFilterControl"
<!-- [formControl]="isFilterControl"--> [states]="[
<!-- [states]="[--> { label: 'full-text search', icon: 'travel_explore' },
<!-- { label: 'full-text search', icon: 'travel_explore' },--> { label: 'filters', icon: 'manage_search' }
<!-- { label: 'filters', icon: 'manage_search' }--> ]"
<!-- ]"--> ></v-switch-button>
<!-- ></v-switch-button>-->
</cc-page-layout-actions> </cc-page-layout-actions>
<v-filters <v-filters
*ngIf="isFilterControl.value" *ngIf="isFilterControl.value"

View File

@ -46,7 +46,7 @@ import { FetchWalletsService } from './fetch-wallets.service';
providers: [FetchWalletsService, FetchWalletsTextService, PartyStoreService], providers: [FetchWalletsService, FetchWalletsTextService, PartyStoreService],
}) })
export class WalletsComponent implements OnInit { export class WalletsComponent implements OnInit {
isFilterControl = new FormControl(1); isFilterControl = new FormControl(0);
filterWallets$ = this.fetchWalletsService.result$; filterWallets$ = this.fetchWalletsService.result$;
filtersLoading$ = this.fetchWalletsService.isLoading$; filtersLoading$ = this.fetchWalletsService.isLoading$;
@ -210,7 +210,7 @@ export class WalletsComponent implements OnInit {
getBalance(walletId: string) { getBalance(walletId: string) {
return this.walletManagementService.GetAccountBalance(walletId).pipe( return this.walletManagementService.GetAccountBalance(walletId).pipe(
catchError((err) => { catchError((err) => {
this.log.error(err); console.error(err);
return of<Partial<AccountBalance>>({}); return of<Partial<AccountBalance>>({});
}), }),
shareReplay({ refCount: true, bufferSize: 1 }), shareReplay({ refCount: true, bufferSize: 1 }),
@ -221,7 +221,7 @@ export class WalletsComponent implements OnInit {
getIdentity(id: string) { getIdentity(id: string) {
return this.identityManagementService.Get(id, {}).pipe( return this.identityManagementService.Get(id, {}).pipe(
catchError((err) => { catchError((err) => {
this.log.error(err); console.error(err);
return of<Partial<IdentityState>>({}); return of<Partial<IdentityState>>({});
}), }),
shareReplay({ refCount: true, bufferSize: 1 }), shareReplay({ refCount: true, bufferSize: 1 }),

View File

@ -16,10 +16,7 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<v-list-field formControlName="withdrawalIds" label="Withdrawal IDs"></v-list-field> <v-list-field formControlName="withdrawalIds" label="Withdrawal IDs"></v-list-field>
<mat-form-field> <cc-wallet-field formControlName="walletId"></cc-wallet-field>
<mat-label>Wallet ID</mat-label>
<input formControlName="walletId" matInput />
</mat-form-field>
<v-number-range-field formControlName="amount" label="Amount"></v-number-range-field> <v-number-range-field formControlName="amount" label="Amount"></v-number-range-field>
<v-input-field formControlName="errorMessage" label="Error message"></v-input-field> <v-input-field formControlName="errorMessage" label="Error message"></v-input-field>
<v-input-field formControlName="terminalId" label="Terminal ID"></v-input-field> <v-input-field formControlName="terminalId" label="Terminal ID"></v-input-field>

View File

@ -18,13 +18,13 @@ import {
NumberRangeFieldModule, NumberRangeFieldModule,
DateRangeFieldModule, DateRangeFieldModule,
InputFieldModule, InputFieldModule,
AutocompleteFieldModule,
} from '@vality/ng-core'; } from '@vality/ng-core';
import { PageLayoutModule } from '../../shared'; import { PageLayoutModule, WalletFieldModule, ThriftPipesModule } from '../../shared';
import { FistfulThriftFormComponent } from '../../shared/components/fistful-thrift-form'; import { FistfulThriftFormComponent } from '../../shared/components/fistful-thrift-form';
import { MerchantFieldModule } from '../../shared/components/merchant-field'; import { MerchantFieldModule } from '../../shared/components/merchant-field';
import { MetadataFormModule } from '../../shared/components/metadata-form'; import { MetadataFormModule } from '../../shared/components/metadata-form';
import { ThriftPipesModule } from '../../shared/pipes/thrift';
import { CreateAdjustmentDialogComponent } from './components/create-adjustment-dialog/create-adjustment-dialog.component'; import { CreateAdjustmentDialogComponent } from './components/create-adjustment-dialog/create-adjustment-dialog.component';
import { WithdrawalsRoutingModule } from './withdrawals-routing.module'; import { WithdrawalsRoutingModule } from './withdrawals-routing.module';
@ -57,6 +57,8 @@ import { WithdrawalsComponent } from './withdrawals.component';
InputFieldModule, InputFieldModule,
NumberRangeFieldModule, NumberRangeFieldModule,
FistfulThriftFormComponent, FistfulThriftFormComponent,
AutocompleteFieldModule,
WalletFieldModule,
], ],
declarations: [WithdrawalsComponent, CreateAdjustmentDialogComponent], declarations: [WithdrawalsComponent, CreateAdjustmentDialogComponent],
}) })

View File

@ -4,3 +4,4 @@ export * from './shop-details';
export * from './payout-tool-details'; export * from './payout-tool-details';
export * from './payout-tool-field'; export * from './payout-tool-field';
export * from './page-layout'; export * from './page-layout';
export * from './wallet-field';

View File

@ -0,0 +1,2 @@
export * from './wallet-field.component';
export * from './wallet-field.module';

View File

@ -0,0 +1,13 @@
<v-select-field
[appearance]="appearance"
[formControl]="control"
[hint]="hint"
[label]="label || 'Wallet'"
[multiple]="multiple"
[options]="options$ | async"
[progress]="!!(progress$ | async)"
[required]="required"
[size]="size"
externalSearch
(searchChange)="this.searchChange$.next($event)"
></v-select-field>

View File

@ -0,0 +1,89 @@
import {
Component,
Input,
AfterViewInit,
booleanAttribute,
DestroyRef,
inject,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { WalletID } from '@vality/domain-proto/domain';
import {
Option,
NotifyLogService,
FormControlSuperclass,
createControlProviders,
getValueChanges,
debounceTimeWithFirst,
} from '@vality/ng-core';
import { BehaviorSubject, Observable, of, ReplaySubject, Subject, merge } from 'rxjs';
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-wallet-field',
templateUrl: 'wallet-field.component.html',
providers: createControlProviders(() => WalletFieldComponent),
})
export class WalletFieldComponent extends FormControlSuperclass<WalletID> implements AfterViewInit {
@Input() label: string;
@Input({ transform: booleanAttribute }) required: boolean;
@Input() size?: string;
@Input() appearance?: string;
@Input() hint?: string;
@Input({ transform: booleanAttribute }) multiple = false;
options$ = new ReplaySubject<Option<WalletID>[]>(1);
searchChange$ = new Subject<string>();
progress$ = new BehaviorSubject(false);
private debounceTimeMs = inject(DEBOUNCE_TIME_MS);
constructor(
private deanonimusService: DeanonimusService,
private log: NotifyLogService,
private destroyRef: DestroyRef,
) {
super();
}
ngAfterViewInit() {
merge(getValueChanges(this.control), this.searchChange$)
.pipe(
distinctUntilChanged(),
tap(() => {
this.options$.next([]);
this.progress$.next(true);
}),
debounceTimeWithFirst(this.debounceTimeMs),
switchMap((term) => this.searchOptions(term)),
takeUntilDestroyed(this.destroyRef),
)
.subscribe((options) => {
this.options$.next(options);
this.progress$.next(false);
});
}
private searchOptions(str: string): Observable<Option<WalletID>[]> {
if (!str) {
return of([]);
}
return this.deanonimusService.searchWalletText(str).pipe(
map((wallets) =>
wallets.map((p) => ({
label: p.wallet.name,
value: p.wallet.id,
description: p.wallet.id,
})),
),
catchError((err) => {
this.log.error(err, 'Search error');
return of([]);
}),
);
}
}

View File

@ -0,0 +1,13 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { SelectFieldModule } from '@vality/ng-core';
import { WalletFieldComponent } from './wallet-field.component';
@NgModule({
imports: [CommonModule, ReactiveFormsModule, SelectFieldModule],
declarations: [WalletFieldComponent],
exports: [WalletFieldComponent],
})
export class WalletFieldModule {}