mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Add Routing and Customer Search Service
This commit is contained in:
@@ -14,4 +14,11 @@ export class CrmCustomerService {
|
||||
take: 5,
|
||||
});
|
||||
}
|
||||
|
||||
getCustomers(queryString: string) {
|
||||
return this.customerService.CustomerListCustomers({
|
||||
input: { qs: queryString },
|
||||
take: 20,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerSearchService {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './search-main.component';
|
||||
// end:ng42.barrel
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './search-results.component';
|
||||
// end:ng42.barrel
|
||||
@@ -0,0 +1 @@
|
||||
<h1>Hallo Lorenz</h1>
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user