From 8714939d3e8a3348ac064dc3ff659c47d3e07ff1 Mon Sep 17 00:00:00 2001 From: Denis Ezhov Date: Thu, 29 Apr 2021 14:26:49 +0300 Subject: [PATCH] FRONTENT-506. Wallet autocomplete (#431) * wallet autocomplete * fix * fix with bug * dsh-autocomplete-input * fix * lint fix * package lock fix * fixes * more fixes * more more fixes * fixes * more fixes * remove validator * fixes --- .../main-filters/main-filters.component.html | 5 +- .../main-filters/main-filters.module.ts | 12 ++++- .../create-webhook-form.component.html | 15 ++---- .../create-webhook-form.component.ts | 22 +++----- .../create-webhook/create-webhook.module.ts | 4 ++ .../search-form/search-form.component.html | 8 +-- .../search-form/search-form.component.ts | 5 +- .../search-form/search-form.service.ts | 19 ++++--- .../withdrawals/withdrawals.module.ts | 2 + .../autocomplete-field.component.html | 15 ++++++ .../autocomplete-field.component.ts | 50 +++++++++++++++++++ .../autocomplete-field.module.ts | 30 +++++++++++ .../inputs/autocomplete-field/index.ts | 3 ++ .../inputs/autocomplete-field/types/index.ts | 1 + .../inputs/autocomplete-field/types/option.ts | 4 ++ .../inputs/wallet-autocomplete-field/index.ts | 2 + .../utils/wallets-to-options.ts | 6 +++ .../wallet-autocomplete-field.component.html | 6 +++ .../wallet-autocomplete-field.component.ts | 23 +++++++++ .../wallet-autocomplete-field.module.ts | 14 ++++++ .../i18n/wallet-autocomplete-field/ru.json | 3 ++ 21 files changed, 206 insertions(+), 43 deletions(-) create mode 100644 src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.html create mode 100644 src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.ts create mode 100644 src/app/shared/components/inputs/autocomplete-field/autocomplete-field.module.ts create mode 100644 src/app/shared/components/inputs/autocomplete-field/index.ts create mode 100644 src/app/shared/components/inputs/autocomplete-field/types/index.ts create mode 100644 src/app/shared/components/inputs/autocomplete-field/types/option.ts create mode 100644 src/app/shared/components/inputs/wallet-autocomplete-field/index.ts create mode 100644 src/app/shared/components/inputs/wallet-autocomplete-field/utils/wallets-to-options.ts create mode 100644 src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.html create mode 100644 src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.ts create mode 100644 src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.module.ts create mode 100644 src/assets/i18n/wallet-autocomplete-field/ru.json diff --git a/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.component.html b/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.component.html index 5d7c5398..bf70852a 100644 --- a/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.component.html +++ b/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.component.html @@ -5,10 +5,7 @@ {{ t('depositID') }} - - {{ t('walletID') }} - - +
diff --git a/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.module.ts b/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.module.ts index f8be1faa..29ca251a 100644 --- a/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.module.ts +++ b/src/app/sections/wallet-section/deposits/deposits-filters/additional-filters/main-filters/main-filters.module.ts @@ -6,10 +6,20 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { TranslocoModule } from '@ngneat/transloco'; +import { WalletAutocompleteFieldModule } from '@dsh/app/shared/components/inputs/wallet-autocomplete-field'; + import { MainFiltersComponent } from './main-filters.component'; @NgModule({ - imports: [CommonModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, FlexLayoutModule, TranslocoModule], + imports: [ + CommonModule, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + FlexLayoutModule, + TranslocoModule, + WalletAutocompleteFieldModule, + ], declarations: [MainFiltersComponent], exports: [MainFiltersComponent], }) diff --git a/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.html b/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.html index ec0f8899..f703f74f 100644 --- a/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.html +++ b/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.html @@ -28,17 +28,10 @@ t('createWebhook.eventTypes.destination') }} - - {{ t('createWebhook.wallet') }} - - - {{ c('any') }} - - - {{ wallet.name }} - - - +
{{ t('createWebhook.events') }}
diff --git a/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.ts b/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.ts index 718e8530..0dd90b7b 100644 --- a/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.ts +++ b/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook-form/create-webhook-form.component.ts @@ -1,38 +1,32 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { BehaviorSubject } from 'rxjs'; import { WebhookScope } from '@dsh/api-codegen/wallet-api/swagger-codegen'; import { IdentityService } from '@dsh/api/identity'; -import { WalletService } from '@dsh/api/wallet'; import { oneMustBeSelected } from '@dsh/components/form-controls'; import { getEventsByTopic } from '../get-events-by-topic'; import TopicEnum = WebhookScope.TopicEnum; +@UntilDestroy() @Component({ selector: 'dsh-create-webhook-form', templateUrl: 'create-webhook-form.component.html', }) export class CreateWebhookFormComponent implements OnInit { - @Input() - form: FormGroup; - - wallets$ = this.walletService.wallets$; + @Input() form: FormGroup; identities$ = this.identityService.identities$; activeTopic$ = new BehaviorSubject('WithdrawalsTopic'); - constructor( - private walletService: WalletService, - private identityService: IdentityService, - private fb: FormBuilder - ) {} + constructor(private identityService: IdentityService, private fb: FormBuilder) {} - ngOnInit() { - this.activeTopic$.subscribe((activeTopic) => { + ngOnInit(): void { + this.activeTopic$.pipe(untilDestroyed(this)).subscribe((activeTopic) => { if (activeTopic === 'WithdrawalsTopic') { this.form.addControl('walletID', this.fb.control('')); } else { @@ -54,11 +48,11 @@ export class CreateWebhookFormComponent implements OnInit { }); } - changeActiveTopic(topic: TopicEnum) { + changeActiveTopic(topic: TopicEnum): void { this.activeTopic$.next(topic); } - get eventTypes() { + get eventTypes(): FormArray { return this.form.get('eventTypes') as FormArray; } } diff --git a/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook.module.ts b/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook.module.ts index 0c0010e1..3f3a0093 100644 --- a/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook.module.ts +++ b/src/app/sections/wallet-section/integrations/webhooks/create-webhook/create-webhook.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FlexModule } from '@angular/flex-layout'; import { ReactiveFormsModule } from '@angular/forms'; +import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialogModule } from '@angular/material/dialog'; import { MatDividerModule } from '@angular/material/divider'; @@ -12,6 +13,7 @@ import { MatSelectModule } from '@angular/material/select'; import { TranslocoModule } from '@ngneat/transloco'; import { BaseDialogModule } from '@dsh/app/shared/components/dialog/base-dialog'; +import { WalletAutocompleteFieldModule } from '@dsh/app/shared/components/inputs/wallet-autocomplete-field'; import { ButtonModule } from '@dsh/components/buttons'; import { CreateWebhookDialogComponent } from './create-webhook-dialog.component'; @@ -33,6 +35,8 @@ import { CreateWebhookService } from './create-webhook.service'; MatCheckboxModule, MatInputModule, BaseDialogModule, + MatAutocompleteModule, + WalletAutocompleteFieldModule, ], declarations: [CreateWebhookDialogComponent, CreateWebhookFormComponent], providers: [CreateWebhookService], diff --git a/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.html b/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.html index fcad3b50..324abc03 100644 --- a/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.html +++ b/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.html @@ -31,10 +31,10 @@ {{ t('withdrawalID') }} - - {{ t('walletID') }} - - +
diff --git a/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.ts b/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.ts index b230159a..8efc0584 100644 --- a/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.ts +++ b/src/app/sections/wallet-section/withdrawals/search-form/search-form.component.ts @@ -11,11 +11,14 @@ import { SearchFormService } from './search-form.service'; }) export class SearchFormComponent { form = this.searchFormService.form; - reset = this.searchFormService.reset; withdrawalStatuses: WithdrawalStatus.StatusEnum[] = ['Pending', 'Succeeded', 'Failed']; expanded = false; constructor(private searchFormService: SearchFormService) {} + + reset(): void { + this.searchFormService.reset(); + } } diff --git a/src/app/sections/wallet-section/withdrawals/search-form/search-form.service.ts b/src/app/sections/wallet-section/withdrawals/search-form/search-form.service.ts index 10f30547..d832fc26 100644 --- a/src/app/sections/wallet-section/withdrawals/search-form/search-form.service.ts +++ b/src/app/sections/wallet-section/withdrawals/search-form/search-form.service.ts @@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import moment from 'moment'; import { map, startWith } from 'rxjs/operators'; +import { removeEmptyProperties } from '../../../payment-section/operations/operators'; import { WithdrawalsService } from '../withdrawals.service'; import { FormParams } from './form-params'; import { toFormValue } from './to-form-value'; @@ -38,24 +39,26 @@ export class SearchFormService { this.init(); } - search(value) { + search(value): void { this.depositsService.search(toSearchParams(value)); } - reset() { + reset(): void { this.form.setValue(SearchFormService.defaultParams); } - private init() { + private init(): void { this.syncQueryParams(); - this.form.valueChanges.pipe(startWith(this.form.value)).subscribe((v) => this.search(v)); + this.form.valueChanges.pipe(startWith(this.form.value), removeEmptyProperties).subscribe((v) => this.search(v)); } - private syncQueryParams() { + private syncQueryParams(): void { const formValue = toFormValue(this.route.snapshot.queryParams, SearchFormService.defaultParams); this.form.setValue(formValue); - this.form.valueChanges.pipe(startWith(formValue), map(toQueryParams)).subscribe((queryParams) => { - this.router.navigate([location.pathname], { queryParams }); - }); + this.form.valueChanges + .pipe(startWith(formValue), removeEmptyProperties, map(toQueryParams)) + .subscribe((queryParams) => { + this.router.navigate([location.pathname], { queryParams }); + }); } } diff --git a/src/app/sections/wallet-section/withdrawals/withdrawals.module.ts b/src/app/sections/wallet-section/withdrawals/withdrawals.module.ts index 3be7a62d..536bc85a 100644 --- a/src/app/sections/wallet-section/withdrawals/withdrawals.module.ts +++ b/src/app/sections/wallet-section/withdrawals/withdrawals.module.ts @@ -8,6 +8,7 @@ import { MatSelectModule } from '@angular/material/select'; import { TranslocoModule } from '@ngneat/transloco'; import { WithdrawalsModule as WithdrawalsApiModule } from '@dsh/api/withdrawals'; +import { WalletAutocompleteFieldModule } from '@dsh/app/shared/components/inputs/wallet-autocomplete-field'; import { ToMajorModule } from '@dsh/app/shared/pipes'; import { ButtonModule } from '@dsh/components/buttons'; import { RangeDatepickerModule } from '@dsh/components/form-controls'; @@ -50,6 +51,7 @@ import { WithdrawalsComponent } from './withdrawals.component'; InvoiceDetailsModule, WalletSectionModule, WithdrawalInfoModule, + WalletAutocompleteFieldModule, ], declarations: [WithdrawalsComponent, SearchFormComponent, WithdrawalListComponent], }) diff --git a/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.html b/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.html new file mode 100644 index 00000000..8d18c47a --- /dev/null +++ b/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.html @@ -0,0 +1,15 @@ + + {{ title }} + + + + + + {{ option.label }} + + + + + diff --git a/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.ts b/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.ts new file mode 100644 index 00000000..22b3818d --- /dev/null +++ b/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.component.ts @@ -0,0 +1,50 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { FormControl } from '@ngneat/reactive-forms'; +import { Observable } from 'rxjs'; +import { map, startWith } from 'rxjs/operators'; + +import { coerceBoolean } from '@dsh/utils'; + +import { Option } from './types'; + +@Component({ + selector: 'dsh-autocomplete-field', + templateUrl: 'autocomplete-field.component.html', +}) +export class AutocompleteFieldComponent implements OnInit { + @Input() control: FormControl; + + @Input() title: string; + + @Input() options: Option[]; + + filteredOptions$: Observable; + + @Input() @coerceBoolean required = false; + + constructor() { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + this.displayLabel = this.displayLabel.bind(this); + } + + ngOnInit(): void { + this.filteredOptions$ = this.control.valueChanges.pipe( + startWith(this.control.value), + map((searchValue) => (searchValue ? this.filterOptions(searchValue) : this.options)) + ); + } + + displayLabel(selectedValue: unknown): string { + const label = this.options?.find((option) => option.value === selectedValue)?.label; + return label ? label : ''; + } + + clearValue(): void { + this.control.reset(); + } + + private filterOptions(searchValue: string): Option[] { + const filterValue = searchValue.toLowerCase(); + return this.options?.filter((option) => option.label.toLowerCase().includes(filterValue)); + } +} diff --git a/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.module.ts b/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.module.ts new file mode 100644 index 00000000..bcf0a96a --- /dev/null +++ b/src/app/shared/components/inputs/autocomplete-field/autocomplete-field.module.ts @@ -0,0 +1,30 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatAutocompleteModule } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; + +import { ButtonModule } from '@dsh/components/buttons'; + +import { AutocompleteFieldComponent } from './autocomplete-field.component'; + +@NgModule({ + imports: [ + CommonModule, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + FlexLayoutModule, + MatAutocompleteModule, + MatButtonModule, + MatIconModule, + ButtonModule, + ], + declarations: [AutocompleteFieldComponent], + exports: [AutocompleteFieldComponent], +}) +export class AutocompleteFieldModule {} diff --git a/src/app/shared/components/inputs/autocomplete-field/index.ts b/src/app/shared/components/inputs/autocomplete-field/index.ts new file mode 100644 index 00000000..dbb0a917 --- /dev/null +++ b/src/app/shared/components/inputs/autocomplete-field/index.ts @@ -0,0 +1,3 @@ +export * from './autocomplete-field.module'; +export * from './autocomplete-field.component'; +export * from './types'; diff --git a/src/app/shared/components/inputs/autocomplete-field/types/index.ts b/src/app/shared/components/inputs/autocomplete-field/types/index.ts new file mode 100644 index 00000000..4216a007 --- /dev/null +++ b/src/app/shared/components/inputs/autocomplete-field/types/index.ts @@ -0,0 +1 @@ +export * from './option'; diff --git a/src/app/shared/components/inputs/autocomplete-field/types/option.ts b/src/app/shared/components/inputs/autocomplete-field/types/option.ts new file mode 100644 index 00000000..ad732cbd --- /dev/null +++ b/src/app/shared/components/inputs/autocomplete-field/types/option.ts @@ -0,0 +1,4 @@ +export interface Option { + value: T; + label: string; +} diff --git a/src/app/shared/components/inputs/wallet-autocomplete-field/index.ts b/src/app/shared/components/inputs/wallet-autocomplete-field/index.ts new file mode 100644 index 00000000..fc04e809 --- /dev/null +++ b/src/app/shared/components/inputs/wallet-autocomplete-field/index.ts @@ -0,0 +1,2 @@ +export * from './wallet-autocomplete-field.module'; +export * from './wallet-autocomplete-field.component'; diff --git a/src/app/shared/components/inputs/wallet-autocomplete-field/utils/wallets-to-options.ts b/src/app/shared/components/inputs/wallet-autocomplete-field/utils/wallets-to-options.ts new file mode 100644 index 00000000..a1fae031 --- /dev/null +++ b/src/app/shared/components/inputs/wallet-autocomplete-field/utils/wallets-to-options.ts @@ -0,0 +1,6 @@ +import { Wallet } from '@dsh/api-codegen/wallet-api'; +import { Option } from '@dsh/app/shared/components/inputs/autocomplete-field'; + +export function walletsToOptions(wallets: Wallet[]): Option[] { + return wallets.map((wallet) => ({ label: wallet.name, value: wallet.id })); +} diff --git a/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.html b/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.html new file mode 100644 index 00000000..abe88e92 --- /dev/null +++ b/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.html @@ -0,0 +1,6 @@ + diff --git a/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.ts b/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.ts new file mode 100644 index 00000000..cf22e367 --- /dev/null +++ b/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from '@angular/core'; +import { FormControl } from '@ngneat/reactive-forms'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { map, shareReplay } from 'rxjs/operators'; + +import { WalletService } from '@dsh/api'; +import { walletsToOptions } from '@dsh/app/shared/components/inputs/wallet-autocomplete-field/utils/wallets-to-options'; +import { coerceBoolean } from '@dsh/utils'; + +@UntilDestroy() +@Component({ + selector: 'dsh-wallet-autocomplete-field', + templateUrl: 'wallet-autocomplete-field.component.html', +}) +export class WalletAutocompleteFieldComponent { + @Input() control: FormControl; + + options$ = this.walletService.wallets$.pipe(map(walletsToOptions), untilDestroyed(this), shareReplay(1)); + + @Input() @coerceBoolean required = false; + + constructor(private walletService: WalletService) {} +} diff --git a/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.module.ts b/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.module.ts new file mode 100644 index 00000000..731655d6 --- /dev/null +++ b/src/app/shared/components/inputs/wallet-autocomplete-field/wallet-autocomplete-field.module.ts @@ -0,0 +1,14 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { TranslocoModule } from '@ngneat/transloco'; + +import { AutocompleteFieldModule } from '@dsh/app/shared/components/inputs/autocomplete-field'; + +import { WalletAutocompleteFieldComponent } from './wallet-autocomplete-field.component'; + +@NgModule({ + imports: [CommonModule, TranslocoModule, AutocompleteFieldModule], + declarations: [WalletAutocompleteFieldComponent], + exports: [WalletAutocompleteFieldComponent], +}) +export class WalletAutocompleteFieldModule {} diff --git a/src/assets/i18n/wallet-autocomplete-field/ru.json b/src/assets/i18n/wallet-autocomplete-field/ru.json new file mode 100644 index 00000000..0d26a3b1 --- /dev/null +++ b/src/assets/i18n/wallet-autocomplete-field/ru.json @@ -0,0 +1,3 @@ +{ + "title": "Кошелек" +}