Add Routing and Customer Search Service

This commit is contained in:
Sebastian
2020-09-28 17:54:05 +02:00
parent 00887b3889
commit e2a58242f9
15 changed files with 274 additions and 176 deletions

View File

@@ -14,4 +14,11 @@ export class CrmCustomerService {
take: 5,
});
}
getCustomers(queryString: string) {
return this.customerService.CustomerListCustomers({
input: { qs: queryString },
take: 20,
});
}
}

View File

@@ -1,46 +1 @@
<a class="card-create-customer">
<span class="title"> Kundendaten erfassen </span>
</a>
<div class="card-search-customer">
<h1 class="title">Kundensuche</h1>
<p class="info">
Wie lautet Ihr Name oder <br />
Ihre E-Mail-Adresse?
</p>
<ui-searchbox>
<input
[formControl]="queryControl"
type="text"
uiSearchboxInput
placeholder="Name, E-Mail, Kundennummer, ..."
(inputChange)="inputChange$.next($event)"
/>
<ui-searchbox-warning>
Keine Suchergebnisse
</ui-searchbox-warning>
<button
*ngIf="queryControl?.value?.length"
type="reset"
uiSearchboxClearButton
(click)="queryControl.reset()"
>
<ui-icon icon="close" size="22px"></ui-icon>
</button>
<button
type="submit"
uiSearchboxSearchButton
(click)="autocomplete.toggle()"
>
<ui-icon icon="search" size="24px"></ui-icon>
</button>
<ui-searchbox-autocomplete #autocomplete>
<button
uiSearchboxAutocompleteOption
[value]="result?.query"
*ngFor="let result of autocompleteResult$ | async"
>
{{ result?.display }}
</button>
</ui-searchbox-autocomplete>
</ui-searchbox>
</div>
<router-outlet></router-outlet>

View File

@@ -1,38 +0,0 @@
:host {
@apply flex flex-col box-border;
}
.title {
@apply text-3xl font-bold;
}
.info {
@apply text-2xl mt-1;
}
.card-create-customer,
.card-search-customer {
@apply bg-white rounded p-4 text-center;
box-shadow: 0 -2px 24px 0 #dce2e9;
}
.card-create-customer .title {
@apply text-inactive-customer text-xl;
}
.card-search-customer {
height: calc(100vh - 380px);
}
ui-searchbox {
@apply max-w-lg mx-auto;
[uiSearchboxSearchButton] {
@apply bg-brand text-white;
}
[uiSearchboxClearButton] {
@apply text-inactive-customer;
}
}

View File

@@ -23,97 +23,13 @@ import {
takeUntil,
tap,
} from 'rxjs/operators';
import { CustomerSearchService } from './customer-search.service';
@Component({
selector: 'page-customer-search',
templateUrl: 'customer-search.component.html',
styleUrls: ['customer-search.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [CustomerSearchService],
})
export class CustomerSearchComponent implements OnInit, OnDestroy {
private destroy$ = new Subject();
queryControl: FormControl;
autocompleteResult$: Observable<AutocompleteDTO[]>;
inputChange$ = new Subject<string>();
@ViewChild(UiSearchboxAutocompleteComponent, {
read: UiSearchboxAutocompleteComponent,
static: true,
})
autocomplete: UiSearchboxAutocompleteComponent;
constructor(
public cdr: ChangeDetectorRef,
private customerSearch: CrmCustomerService,
private router: Router,
private activatedRoute: ActivatedRoute,
private zone: NgZone
) {}
ngOnInit() {
this.initQueryControl();
this.initAutocomplete();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
initAutocomplete() {
this.autocompleteResult$ = this.inputChange$.pipe(
takeUntil(this.destroy$),
filter(() => this.queryControl.valid),
debounceTime(150),
switchMap((queryString) =>
this.customerSearch.complete(queryString).pipe(
map((response) => response.result),
catchError(() => {
// TODO Dialog Service impl. fur Anzeige der Fehlermeldung
return [];
})
)
),
tap((result) => {
if (result.length) {
this.autocomplete.open();
} else {
this.autocomplete.close();
}
setTimeout(() => {
this.cdr.detectChanges();
});
})
);
}
initQueryControl() {
this.queryControl = new FormControl(
this.activatedRoute.snapshot.queryParams.query || '',
[Validators.required]
);
this.queryControl.valueChanges
.pipe(
takeUntil(this.destroy$),
debounceTime(500),
tap((query) => this.updateQueryParam({ query }))
)
.subscribe(() => {
this.cdr.detectChanges();
});
}
updateQueryParam(params: { query?: string }) {
this.zone.run(() => {
this.router.navigate(['./'], {
queryParams: params,
relativeTo: this.activatedRoute,
queryParamsHandling: 'merge',
});
});
}
}
export class CustomerSearchComponent {}

View File

@@ -4,10 +4,27 @@ import { CustomerSearchComponent } from './customer-search.component';
import { UiSearchboxModule } from '@ui/searchbox';
import { UiIconModule } from '@ui/icon';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { CustomerSearchMainComponent } from './search-main';
import { CustomerSearchResultComponent } from './search-results';
@NgModule({
imports: [CommonModule, UiSearchboxModule, UiIconModule, ReactiveFormsModule],
exports: [CustomerSearchComponent],
declarations: [CustomerSearchComponent],
imports: [
CommonModule,
RouterModule,
UiSearchboxModule,
UiIconModule,
ReactiveFormsModule,
],
exports: [
CustomerSearchComponent,
CustomerSearchMainComponent,
CustomerSearchResultComponent,
],
declarations: [
CustomerSearchComponent,
CustomerSearchMainComponent,
CustomerSearchResultComponent,
],
})
export class CustomerSearchModule {}

View File

@@ -0,0 +1,6 @@
import { Injectable } from '@angular/core';
@Injectable()
export class CustomerSearchService {
constructor() {}
}

View File

@@ -0,0 +1,3 @@
// start:ng42.barrel
export * from './search-main.component';
// end:ng42.barrel

View File

@@ -0,0 +1,46 @@
<a class="card-create-customer">
<span class="title"> Kundendaten erfassen </span>
</a>
<div class="card-search-customer">
<h1 class="title">Kundensuche</h1>
<p class="info">
Wie lautet Ihr Name oder <br />
Ihre E-Mail-Adresse?
</p>
<ui-searchbox>
<input
[formControl]="queryControl"
type="text"
uiSearchboxInput
placeholder="Name, E-Mail, Kundennummer, ..."
(inputChange)="inputChange$.next($event)"
/>
<ui-searchbox-warning>
Keine Suchergebnisse
</ui-searchbox-warning>
<button
*ngIf="queryControl?.value?.length"
type="reset"
uiSearchboxClearButton
(click)="queryControl.reset()"
>
<ui-icon icon="close" size="22px"></ui-icon>
</button>
<button
type="submit"
uiSearchboxSearchButton
(click)="autocomplete.toggle()"
>
<ui-icon icon="search" size="24px"></ui-icon>
</button>
<ui-searchbox-autocomplete #autocomplete>
<button
uiSearchboxAutocompleteOption
[value]="result?.query"
*ngFor="let result of autocompleteResult$ | async"
>
{{ result?.display }}
</button>
</ui-searchbox-autocomplete>
</ui-searchbox>
</div>

View File

@@ -0,0 +1,38 @@
:host {
@apply flex flex-col box-border;
}
.title {
@apply text-3xl font-bold;
}
.info {
@apply text-2xl mt-1;
}
.card-create-customer,
.card-search-customer {
@apply bg-white rounded p-4 text-center;
box-shadow: 0 -2px 24px 0 #dce2e9;
}
.card-create-customer .title {
@apply text-inactive-customer text-xl;
}
.card-search-customer {
height: calc(100vh - 380px);
}
ui-searchbox {
@apply max-w-lg mx-auto;
[uiSearchboxSearchButton] {
@apply bg-brand text-white;
}
[uiSearchboxClearButton] {
@apply text-inactive-customer;
}
}

View File

@@ -0,0 +1,120 @@
import {
Component,
ChangeDetectionStrategy,
ChangeDetectorRef,
NgZone,
OnDestroy,
OnInit,
ViewChild,
} from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { CrmCustomerService } from '@domain/crm';
import { AutocompleteDTO } from '@swagger/crm';
import { UiSearchboxAutocompleteComponent } from '@ui/searchbox';
import { Subject, Observable } from 'rxjs';
import {
catchError,
debounceTime,
filter,
map,
switchMap,
takeUntil,
tap,
} from 'rxjs/operators';
import { CustomerSearchService } from '../customer-search.service';
@Component({
selector: 'customer-search-main',
templateUrl: 'search-main.component.html',
styleUrls: ['search-main.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerSearchMainComponent implements OnInit, OnDestroy {
private destroy$ = new Subject();
queryControl: FormControl;
autocompleteResult$: Observable<AutocompleteDTO[]>;
inputChange$ = new Subject<string>();
@ViewChild(UiSearchboxAutocompleteComponent, {
read: UiSearchboxAutocompleteComponent,
static: true,
})
autocomplete: UiSearchboxAutocompleteComponent;
constructor(
public search: CustomerSearchService,
public cdr: ChangeDetectorRef,
private customerSearch: CrmCustomerService,
private router: Router,
private activatedRoute: ActivatedRoute,
private zone: NgZone
) {}
ngOnInit() {
this.initQueryControl();
this.initAutocomplete();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
initAutocomplete() {
this.autocompleteResult$ = this.inputChange$.pipe(
takeUntil(this.destroy$),
filter(() => this.queryControl.valid),
debounceTime(150),
switchMap((queryString) =>
this.customerSearch.complete(queryString).pipe(
map((response) => response.result),
catchError(() => {
// TODO Dialog Service impl. fur Anzeige der Fehlermeldung
return [];
})
)
),
tap((result) => {
if (result.length) {
this.autocomplete.open();
} else {
this.autocomplete.close();
}
setTimeout(() => {
this.cdr.detectChanges();
});
})
);
}
initQueryControl() {
this.queryControl = new FormControl(
this.activatedRoute.snapshot.queryParams.query || '',
[Validators.required]
);
this.queryControl.valueChanges
.pipe(
takeUntil(this.destroy$),
debounceTime(500),
tap((query) => this.updateQueryParam({ query }))
)
.subscribe(() => {
this.cdr.detectChanges();
});
}
updateQueryParam(params: { query?: string }) {
this.zone.run(() => {
this.router.navigate(['./'], {
queryParams: params,
relativeTo: this.activatedRoute,
queryParamsHandling: 'merge',
});
});
}
}

View File

@@ -0,0 +1,3 @@
// start:ng42.barrel
export * from './search-results.component';
// end:ng42.barrel

View File

@@ -0,0 +1 @@
<h1>Hallo Lorenz</h1>

View File

@@ -0,0 +1,12 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
@Component({
selector: 'customer-search-result',
templateUrl: './search-results.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerSearchResultComponent implements OnInit {
constructor() {}
ngOnInit() {}
}

View File

@@ -2,6 +2,8 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerSearchComponent } from './customer-search/customer-search.component';
import { CustomerSearchModule } from './customer-search/customer-search.module';
import { CustomerSearchMainComponent } from './customer-search/search-main/search-main.component';
import { CustomerSearchResultComponent } from './customer-search/search-results/search-results.component';
import { PageCustomerComponent } from './page-customer.component';
const routes: Routes = [
@@ -12,13 +14,17 @@ const routes: Routes = [
{
path: 'search',
component: CustomerSearchComponent,
children: [
{ path: '', component: CustomerSearchMainComponent },
{ path: 'result', component: CustomerSearchResultComponent },
],
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes), CustomerSearchModule],
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PageCustomerRoutingModule {}

View File

@@ -4,9 +4,15 @@ import { CommonModule } from '@angular/common';
import { PageCustomerComponent } from './page-customer.component';
import { PageCustomerRoutingModule } from './page-customer-routing.module';
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
import { CustomerSearchModule } from './customer-search/customer-search.module';
@NgModule({
imports: [CommonModule, PageCustomerRoutingModule, ShellBreadcrumbModule],
imports: [
CommonModule,
PageCustomerRoutingModule,
ShellBreadcrumbModule,
CustomerSearchModule,
],
exports: [PageCustomerComponent],
declarations: [PageCustomerComponent],
})