mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Add Filter Overlay & Refactor Searchbox to own component
This commit is contained in:
@@ -1 +1,20 @@
|
||||
<button class="filter" [class.active]="true" (click)="filterActive = true">
|
||||
<ui-icon size="22px" icon="filter_alit"></ui-icon>
|
||||
<span class="label">Filter</span>
|
||||
</button>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<div class="filter-overlay" [class.active]="filterActive">
|
||||
<div class="filter-content">
|
||||
<div class="filter-close-right">
|
||||
<button class="filter-close" (click)="filterActive = false">
|
||||
<ui-icon size="20px" icon="close"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
<h2 class="filter-header">
|
||||
Filter
|
||||
</h2>
|
||||
<page-customer-search-filter></page-customer-search-filter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
:host {
|
||||
@apply flex flex-col box-content w-full relative;
|
||||
}
|
||||
|
||||
.filter {
|
||||
@apply absolute font-sans flex items-center font-bold bg-wild-blue-yonder border-0 text-regular py-px-8 px-px-15 rounded-filter;
|
||||
|
||||
right: 0;
|
||||
top: -50px;
|
||||
|
||||
.label {
|
||||
@apply ml-px-5;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-dark-cerulean text-white ml-px-5;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-content {
|
||||
@apply max-w-content mx-auto mt-px-25 px-px-15;
|
||||
|
||||
.filter-close-right {
|
||||
@apply pr-px-10 text-right;
|
||||
}
|
||||
|
||||
.filter-header {
|
||||
@apply text-center text-page-heading mt-0;
|
||||
}
|
||||
|
||||
button.filter-close {
|
||||
@apply border-0 bg-transparent text-ucla-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-overlay {
|
||||
@apply fixed bg-glitter z-fixed;
|
||||
|
||||
transform: translatex(100%);
|
||||
transition: transform 0.5s ease-out;
|
||||
top: 135px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
&.active {
|
||||
transform: translatex(0%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { Component, ChangeDetectionStrategy, forwardRef, NgZone, OnInit } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
forwardRef,
|
||||
NgZone,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { CustomerSearch } from './customer-search.service';
|
||||
|
||||
@@ -16,8 +23,15 @@ import { CustomerSearch } from './customer-search.service';
|
||||
],
|
||||
})
|
||||
export class CustomerSearchComponent extends CustomerSearch implements OnInit {
|
||||
constructor(protected customerSearch: CrmCustomerService, zone: NgZone, router: Router) {
|
||||
super(zone, router);
|
||||
filterActive = false;
|
||||
|
||||
constructor(
|
||||
protected customerSearch: CrmCustomerService,
|
||||
zone: NgZone,
|
||||
router: Router,
|
||||
env: EnvironmentService
|
||||
) {
|
||||
super(zone, router, env);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -9,10 +9,30 @@ import { CustomerSearchMainComponent } from './search-main';
|
||||
import { CustomerSearchResultComponent } from './search-results';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { CustomerResultCardComponent } from './search-results/customer-result-card/customer-result-card.component';
|
||||
import { CustomerSearchFilterComponent } from './search-filter/search-filter.component';
|
||||
import { CustomerSearchboxComponent } from './shared/customer-searchbox';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, UiSearchboxModule, UiCommonModule, UiIconModule, ReactiveFormsModule],
|
||||
exports: [CustomerSearchComponent, CustomerSearchMainComponent, CustomerSearchResultComponent],
|
||||
declarations: [CustomerSearchComponent, CustomerSearchMainComponent, CustomerSearchResultComponent, CustomerResultCardComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
UiSearchboxModule,
|
||||
UiCommonModule,
|
||||
UiIconModule,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
exports: [
|
||||
CustomerSearchComponent,
|
||||
CustomerSearchMainComponent,
|
||||
CustomerSearchResultComponent,
|
||||
],
|
||||
declarations: [
|
||||
CustomerSearchComponent,
|
||||
CustomerSearchMainComponent,
|
||||
CustomerSearchResultComponent,
|
||||
CustomerResultCardComponent,
|
||||
CustomerSearchFilterComponent,
|
||||
CustomerSearchboxComponent,
|
||||
],
|
||||
})
|
||||
export class CustomerSearchModule {}
|
||||
|
||||
@@ -8,8 +8,8 @@ import { take } from 'rxjs/operators';
|
||||
import { CustomerSearchComponent } from './customer-search.component';
|
||||
import { CustomerSearch } from './customer-search.service';
|
||||
|
||||
function customerSearchCompFn(crmService, zone, router) {
|
||||
return new CustomerSearchComponent(crmService, zone, router);
|
||||
function customerSearchCompFn(crmService, zone, router, env) {
|
||||
return new CustomerSearchComponent(crmService, zone, router, env);
|
||||
}
|
||||
|
||||
class MockCrmCustomerService {
|
||||
|
||||
@@ -2,14 +2,13 @@ import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable, NgZone, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormControl, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { PagedResult } from '@domain/defs';
|
||||
import { AutocompleteDTO, CustomerInfoDTO } from '@swagger/crm';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import {
|
||||
catchError,
|
||||
debounceTime,
|
||||
filter,
|
||||
map,
|
||||
shareReplay,
|
||||
switchMap,
|
||||
@@ -63,7 +62,11 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
return this.searchResult$.value.hits;
|
||||
}
|
||||
|
||||
constructor(private zone: NgZone, private router: Router) {}
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private router: Router,
|
||||
private environmentService: EnvironmentService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.initQueryControl();
|
||||
@@ -125,6 +128,17 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
startSearch() {
|
||||
if (
|
||||
!this.queryControl.value ||
|
||||
(!this.queryControl.value.length && this.environmentService.isMobile())
|
||||
) {
|
||||
return this.scan();
|
||||
}
|
||||
|
||||
return this.search();
|
||||
}
|
||||
|
||||
search(options: { isNewSearch: boolean } = { isNewSearch: true }): void {
|
||||
if (
|
||||
!options.isNewSearch &&
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<page-customer-searchbox></page-customer-searchbox>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
@apply flex flex-col box-border w-full;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { CustomerSearch } from '../customer-search.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search-filter',
|
||||
selector: 'page-customer-search-filter',
|
||||
templateUrl: 'search-filter.component.html',
|
||||
styleUrls: ['search-filter.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SearchFilterComponent implements OnInit {
|
||||
export class CustomerSearchFilterComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
@@ -10,66 +10,5 @@
|
||||
Wie lautet Ihr Name oder <br />
|
||||
Ihre E-Mail-Adresse?
|
||||
</p>
|
||||
<ui-searchbox>
|
||||
<input
|
||||
#input
|
||||
[formControl]="search.queryControl"
|
||||
type="text"
|
||||
uiSearchboxInput
|
||||
placeholder="Name, E-Mail, Kundenkartennummer, ..."
|
||||
(inputChange)="search.inputChange$.next($event)"
|
||||
(keydown.enter)="search.search(); autocomplete.close()"
|
||||
/>
|
||||
<ui-searchbox-warning *ngIf="searchState === 'empty'">
|
||||
Keine Suchergebnisse
|
||||
</ui-searchbox-warning>
|
||||
<button
|
||||
*ngIf="search.queryControl?.value?.length"
|
||||
type="reset"
|
||||
uiSearchboxClearButton
|
||||
(click)="search.queryControl.reset(); input.focus()"
|
||||
>
|
||||
<ui-icon icon="close" size="22px"></ui-icon>
|
||||
</button>
|
||||
<button
|
||||
[class.scan]="isMobile && !input?.value?.length"
|
||||
type="submit"
|
||||
uiSearchboxSearchButton
|
||||
(click)="startSearch()"
|
||||
[disabled]="searchState === 'fetching'"
|
||||
>
|
||||
<ui-icon
|
||||
class="spin"
|
||||
*ngIf="searchState === 'fetching'"
|
||||
icon="spinner"
|
||||
size="32px"
|
||||
></ui-icon>
|
||||
|
||||
<ng-container *ngIf="searchState !== 'fetching'">
|
||||
<ui-icon
|
||||
*ngIf="isMobile && !input?.value?.length"
|
||||
icon="scan"
|
||||
size="32px"
|
||||
></ui-icon>
|
||||
<ui-icon
|
||||
*ngIf="!isMobile || !!input?.value?.length"
|
||||
icon="search"
|
||||
size="24px"
|
||||
></ui-icon>
|
||||
</ng-container>
|
||||
</button>
|
||||
<ui-searchbox-autocomplete
|
||||
uiClickOutside
|
||||
(clicked)="autocomplete.close()"
|
||||
#autocomplete
|
||||
>
|
||||
<button
|
||||
uiSearchboxAutocompleteOption
|
||||
[value]="result?.display"
|
||||
*ngFor="let result of search.autocompleteResult$ | async"
|
||||
>
|
||||
{{ result?.display }}
|
||||
</button>
|
||||
</ui-searchbox-autocomplete>
|
||||
</ui-searchbox>
|
||||
<page-customer-searchbox></page-customer-searchbox>
|
||||
</div>
|
||||
|
||||
@@ -24,34 +24,3 @@
|
||||
.card-search-customer {
|
||||
height: calc(100vh - 380px);
|
||||
}
|
||||
|
||||
ui-searchbox {
|
||||
@apply max-w-lg mx-auto;
|
||||
|
||||
input {
|
||||
caret-color: #f70400;
|
||||
}
|
||||
|
||||
[uiSearchboxSearchButton] {
|
||||
@apply bg-white text-brand;
|
||||
|
||||
&:not(.scan) {
|
||||
@apply pr-px-25;
|
||||
}
|
||||
|
||||
&.scan {
|
||||
@apply bg-brand text-white;
|
||||
}
|
||||
.spin {
|
||||
@apply bg-white text-ucla-blue;
|
||||
}
|
||||
}
|
||||
|
||||
[uiSearchboxClearButton] {
|
||||
@apply text-inactive-customer;
|
||||
}
|
||||
}
|
||||
|
||||
.spin {
|
||||
@apply animate-spin;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
|
||||
|
||||
async detectDevice() {
|
||||
this.isMobile = await this.environmentService.isMobile();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
subscribeToSearchResult() {
|
||||
@@ -87,16 +88,4 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startSearch() {
|
||||
if (
|
||||
!this.search.queryControl.value ||
|
||||
(!this.search.queryControl.value.length &&
|
||||
this.environmentService.isMobile())
|
||||
) {
|
||||
return this.search.scan();
|
||||
}
|
||||
|
||||
return this.search.search();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
<div class="header">
|
||||
<h4 class="heading">{{ customer?.firstName }} {{ customer?.lastName }} {{ customer?.organisation?.name }}</h4>
|
||||
<h4 class="heading">
|
||||
<span *ngIf="customer.customerType === 16">{{
|
||||
customer?.organisation?.name
|
||||
}}</span>
|
||||
<span *ngIf="customer.customerType !== 16"
|
||||
>{{ customer?.firstName }} {{ customer?.lastName }}
|
||||
</span>
|
||||
</h4>
|
||||
<span class="date">{{ customer?.created | date: 'dd.MM.yy' }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="data">
|
||||
<div class="name">PLZ und Ort</div>
|
||||
<div class="value">{{ customer?.address?.zipCode }} {{ customer?.address?.city }}</div>
|
||||
<div class="value">
|
||||
{{ customer?.address?.zipCode }} {{ customer?.address?.city }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="data" *ngIf="customer.customerType === 16">
|
||||
<div class="name">Ansprechpartner</div>
|
||||
<div class="value">[Klärungsbedarf]</div>
|
||||
<div class="value">{{ customer?.firstName }} {{ customer?.lastName }}</div>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="name">E-Mail</div>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<div *ngIf="search.searchState$ | async as searchState">
|
||||
<ui-searchbox>
|
||||
<input
|
||||
#input
|
||||
[formControl]="search.queryControl"
|
||||
type="text"
|
||||
uiSearchboxInput
|
||||
placeholder="Name, E-Mail, Kundenkartennummer, ..."
|
||||
(inputChange)="search.inputChange$.next($event)"
|
||||
(keydown.enter)="search.search(); autocomplete.close()"
|
||||
/>
|
||||
<ui-searchbox-warning *ngIf="searchState === 'empty'">
|
||||
Keine Suchergebnisse
|
||||
</ui-searchbox-warning>
|
||||
<button
|
||||
*ngIf="search.queryControl?.value?.length"
|
||||
type="reset"
|
||||
uiSearchboxClearButton
|
||||
(click)="search.queryControl.reset(); input.focus()"
|
||||
>
|
||||
<ui-icon icon="close" size="22px"></ui-icon>
|
||||
</button>
|
||||
<button
|
||||
[class.scan]="isMobile && !input?.value?.length"
|
||||
type="submit"
|
||||
uiSearchboxSearchButton
|
||||
(click)="search.startSearch()"
|
||||
[disabled]="searchState === 'fetching'"
|
||||
>
|
||||
<ui-icon
|
||||
class="spin"
|
||||
*ngIf="searchState === 'fetching'"
|
||||
icon="spinner"
|
||||
size="32px"
|
||||
></ui-icon>
|
||||
|
||||
<ng-container *ngIf="searchState !== 'fetching'">
|
||||
<ui-icon
|
||||
*ngIf="isMobile && !input?.value?.length"
|
||||
icon="scan"
|
||||
size="32px"
|
||||
></ui-icon>
|
||||
<ui-icon
|
||||
*ngIf="!isMobile || !!input?.value?.length"
|
||||
icon="search"
|
||||
size="24px"
|
||||
></ui-icon>
|
||||
</ng-container>
|
||||
</button>
|
||||
<ui-searchbox-autocomplete
|
||||
uiClickOutside
|
||||
(clicked)="autocomplete.close()"
|
||||
#autocomplete
|
||||
>
|
||||
<button
|
||||
uiSearchboxAutocompleteOption
|
||||
[value]="result?.display"
|
||||
*ngFor="let result of search.autocompleteResult$ | async"
|
||||
>
|
||||
{{ result?.display }}
|
||||
</button>
|
||||
</ui-searchbox-autocomplete>
|
||||
</ui-searchbox>
|
||||
</div>
|
||||
|
||||
<h1>VALUE {{ search.queryControl?.value }}</h1>
|
||||
@@ -0,0 +1,30 @@
|
||||
ui-searchbox {
|
||||
@apply max-w-lg mx-auto;
|
||||
|
||||
input {
|
||||
caret-color: #f70400;
|
||||
}
|
||||
|
||||
[uiSearchboxSearchButton] {
|
||||
@apply bg-white text-brand;
|
||||
|
||||
&:not(.scan) {
|
||||
@apply pr-px-25;
|
||||
}
|
||||
|
||||
&.scan {
|
||||
@apply bg-brand text-white;
|
||||
}
|
||||
.spin {
|
||||
@apply bg-white text-ucla-blue;
|
||||
}
|
||||
}
|
||||
|
||||
[uiSearchboxClearButton] {
|
||||
@apply text-inactive-customer;
|
||||
}
|
||||
}
|
||||
|
||||
.spin {
|
||||
@apply animate-spin;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { CustomerSearch } from '../../customer-search.service';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-searchbox',
|
||||
templateUrl: 'customer-searchbox.component.html',
|
||||
styleUrls: ['customer-searchbox.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CustomerSearchboxComponent implements OnInit {
|
||||
isMobile: boolean;
|
||||
|
||||
queryControl = new FormControl();
|
||||
|
||||
constructor(
|
||||
public search: CustomerSearch,
|
||||
private environmentService: EnvironmentService,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.detectDevice();
|
||||
}
|
||||
|
||||
async detectDevice() {
|
||||
this.isMobile = await this.environmentService.isMobile();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './customer-searchbox.component';
|
||||
// end:ng42.barrel
|
||||
@@ -11,17 +11,42 @@ import {
|
||||
AfterViewInit,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { Observable, of, Subject, BehaviorSubject, combineLatest, merge } from 'rxjs';
|
||||
import { RemissionProduct, RemissionService, RemissionProcess } from '@isa/remission';
|
||||
import {
|
||||
Observable,
|
||||
of,
|
||||
Subject,
|
||||
BehaviorSubject,
|
||||
combineLatest,
|
||||
merge,
|
||||
} from 'rxjs';
|
||||
import {
|
||||
RemissionProduct,
|
||||
RemissionService,
|
||||
RemissionProcess,
|
||||
} from '@isa/remission';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import { RemissionSelectors } from 'apps/sales/src/app/core/store/selectors/remission.selectors';
|
||||
import { map, switchMap, filter, catchError, takeUntil, take, distinctUntilChanged, debounceTime, tap, skip } from 'rxjs/operators';
|
||||
import {
|
||||
map,
|
||||
switchMap,
|
||||
filter,
|
||||
catchError,
|
||||
takeUntil,
|
||||
take,
|
||||
distinctUntilChanged,
|
||||
debounceTime,
|
||||
tap,
|
||||
skip,
|
||||
} from 'rxjs/operators';
|
||||
import { RemissionListComponent } from '../../../components/remission-list';
|
||||
import { RemissionResourceType } from '../../../models/remission-resource-type.model';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { RemissionProcessStatuses } from 'apps/sales/src/app/core/models/remission-process-statuses.model';
|
||||
import { RemissionToTopToBottomActionsComponent } from '../../../components/remission-to-top-to-bottom-actions';
|
||||
import { UpdateShippingDocuent, SetRemissionActiveView } from 'apps/sales/src/app/core/store/actions/remission.actions';
|
||||
import {
|
||||
UpdateShippingDocuent,
|
||||
SetRemissionActiveView,
|
||||
} from 'apps/sales/src/app/core/store/actions/remission.actions';
|
||||
import { RemissionActiveView } from '../../../models';
|
||||
import { RemissionHelperService } from '../../../services';
|
||||
|
||||
@@ -31,7 +56,8 @@ import { RemissionHelperService } from '../../../services';
|
||||
styleUrls: ['./product-list.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class RemissionProductListComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
export class RemissionProductListComponent
|
||||
implements OnInit, OnDestroy, AfterViewInit {
|
||||
@ViewChild('toTopToBottomActions')
|
||||
toTopToBottomActions: RemissionToTopToBottomActionsComponent;
|
||||
@ViewChild('remissionList')
|
||||
@@ -40,7 +66,9 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
|
||||
@Input() remissionListContainer: HTMLElement;
|
||||
@Input() shippingDocumentContainer: HTMLElement;
|
||||
@Input() containerScrolled$: Observable<Event> = new Subject<Event>().asObservable();
|
||||
@Input() containerScrolled$: Observable<Event> = new Subject<
|
||||
Event
|
||||
>().asObservable();
|
||||
@Input() shippingDocumentRef: QueryList<ElementRef>;
|
||||
@Input() set slideOutOfView(shouldBeOutOfView: boolean) {
|
||||
if (!shouldBeOutOfView) {
|
||||
@@ -58,8 +86,12 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
_removeFromDocumentFlow = false;
|
||||
|
||||
@Select(RemissionSelectors.getIsLoading) isLoading$: Observable<boolean>;
|
||||
@Select(RemissionSelectors.getRemissionProcess) remissionProcess$: Observable<RemissionProcess>;
|
||||
@Select(RemissionSelectors.getRemissionSource) source$: Observable<RemissionResourceType>;
|
||||
@Select(RemissionSelectors.getRemissionProcess) remissionProcess$: Observable<
|
||||
RemissionProcess
|
||||
>;
|
||||
@Select(RemissionSelectors.getRemissionSource) source$: Observable<
|
||||
RemissionResourceType
|
||||
>;
|
||||
@Select(RemissionSelectors.getRemissionProcessStatuses)
|
||||
remissionProcessStatuses$: Observable<RemissionProcessStatuses>;
|
||||
@Select(RemissionSelectors.getRemissiontarget)
|
||||
@@ -140,7 +172,10 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
|
||||
initProducts() {
|
||||
this.remissionProductsData$ = this.remissionProcess$.pipe(
|
||||
filter((process) => !isNullOrUndefined(process) && !isNullOrUndefined(process.id)),
|
||||
filter(
|
||||
(process) =>
|
||||
!isNullOrUndefined(process) && !isNullOrUndefined(process.id)
|
||||
),
|
||||
take(1),
|
||||
map((process) => process.id),
|
||||
switchMap((remissionProcessId) =>
|
||||
@@ -148,7 +183,10 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
filter((data) => !isNullOrUndefined(data)),
|
||||
map((data) => {
|
||||
if (!data.hits) {
|
||||
data.hits = (this.latestRemissionProductsData$.value && this.latestRemissionProductsData$.value.hits) || 0;
|
||||
data.hits =
|
||||
(this.latestRemissionProductsData$.value &&
|
||||
this.latestRemissionProductsData$.value.hits) ||
|
||||
0;
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -209,7 +247,8 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
const { clientHeight, scrollHeight, scrollTop } = target;
|
||||
|
||||
if (this.refetchProductsOnScroll()) {
|
||||
const shippingContainerHeight = this.shippingDocumentContainer.clientHeight;
|
||||
const shippingContainerHeight = this.shippingDocumentContainer
|
||||
.clientHeight;
|
||||
if (
|
||||
this.shouldRefreshProducts({
|
||||
clientHeight,
|
||||
@@ -247,7 +286,8 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
const pixelsScrolledUpToTriggerRefresh = 150;
|
||||
|
||||
return (
|
||||
scrollTop + clientHeight - scrollHeight < pixelsScrolledUpToTriggerRefresh - shippingContainerHeight &&
|
||||
scrollTop + clientHeight - scrollHeight <
|
||||
pixelsScrolledUpToTriggerRefresh - shippingContainerHeight &&
|
||||
!!this.viewShippingDocumentFromJumpToBottom
|
||||
);
|
||||
}
|
||||
@@ -258,7 +298,10 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
this.refetchRemissionProductsOnScrollUp$.next();
|
||||
}
|
||||
|
||||
private setScrollToTopBotomVisibility(topValue: boolean, bottomValue: boolean) {
|
||||
private setScrollToTopBotomVisibility(
|
||||
topValue: boolean,
|
||||
bottomValue: boolean
|
||||
) {
|
||||
this.showJumpToTop$.next(topValue);
|
||||
this.showJumpToBottom$.next(bottomValue);
|
||||
}
|
||||
@@ -269,21 +312,25 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
private setUpIntersectionObservers() {
|
||||
this.remissionHitsRef.changes.pipe(this.returnFirstElement).subscribe((element) => {
|
||||
this.subscribeToIntersectionSub({
|
||||
element,
|
||||
sub: this.isNumberOfHitsVisible$,
|
||||
type: 'top',
|
||||
this.remissionHitsRef.changes
|
||||
.pipe(this.returnFirstElement)
|
||||
.subscribe((element) => {
|
||||
this.subscribeToIntersectionSub({
|
||||
element,
|
||||
sub: this.isNumberOfHitsVisible$,
|
||||
type: 'top',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.shippingDocumentRef.changes.pipe(this.returnFirstElement).subscribe((element) => {
|
||||
this.subscribeToIntersectionSub({
|
||||
element,
|
||||
sub: this.isShippingDocumentVisible$,
|
||||
type: 'bottom',
|
||||
this.shippingDocumentRef.changes
|
||||
.pipe(this.returnFirstElement)
|
||||
.subscribe((element) => {
|
||||
this.subscribeToIntersectionSub({
|
||||
element,
|
||||
sub: this.isShippingDocumentVisible$,
|
||||
type: 'bottom',
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private returnFirstElement(el: Observable<any>): Observable<any> {
|
||||
@@ -293,7 +340,11 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
);
|
||||
}
|
||||
|
||||
private subscribeToIntersectionSub(params: { element: Element; sub: BehaviorSubject<boolean>; type: 'top' | 'bottom' }) {
|
||||
private subscribeToIntersectionSub(params: {
|
||||
element: Element;
|
||||
sub: BehaviorSubject<boolean>;
|
||||
type: 'top' | 'bottom';
|
||||
}) {
|
||||
const { element, sub, type } = params;
|
||||
|
||||
const unsubscribe = this.intersectionObserverSubs.get(type);
|
||||
@@ -301,7 +352,10 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
unsubscribe();
|
||||
}
|
||||
|
||||
this.intersectionObserverSubs.set(type, this.initIntersectionObserver(element, type));
|
||||
this.intersectionObserverSubs.set(
|
||||
type,
|
||||
this.initIntersectionObserver(element, type)
|
||||
);
|
||||
|
||||
this.intersectionObserver$
|
||||
.pipe(
|
||||
@@ -320,11 +374,13 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
private initIntersectionObserver(element: Element, type: 'top' | 'bottom') {
|
||||
const intersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
this.intersectionObserver$.next({ entry, observer, type });
|
||||
});
|
||||
});
|
||||
const intersectionObserver = new IntersectionObserver(
|
||||
(entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
this.intersectionObserver$.next({ entry, observer, type });
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
intersectionObserver.observe(element);
|
||||
|
||||
@@ -359,26 +415,37 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
this.isLoading$
|
||||
)
|
||||
.pipe(
|
||||
map(([isNumberOfHitsVisible, isShippingDocumentVisible, hits, isLoading]) => {
|
||||
if (!hits || hits === -1 || !!isLoading) {
|
||||
map(
|
||||
([
|
||||
isNumberOfHitsVisible,
|
||||
isShippingDocumentVisible,
|
||||
hits,
|
||||
isLoading,
|
||||
]) => {
|
||||
if (!hits || hits === -1 || !!isLoading) {
|
||||
return {
|
||||
showTop: false,
|
||||
showBottom: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
showTop: false,
|
||||
showBottom: false,
|
||||
showTop: !isShippingDocumentVisible,
|
||||
showBottom: !isNumberOfHitsVisible,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
showTop: !isShippingDocumentVisible,
|
||||
showBottom: !isNumberOfHitsVisible,
|
||||
};
|
||||
}),
|
||||
),
|
||||
takeUntil(this.destroy$),
|
||||
debounceTime(350)
|
||||
)
|
||||
.subscribe(({ showTop, showBottom }) => this.setScrollToTopBotomVisibility(showTop, showBottom));
|
||||
.subscribe(({ showTop, showBottom }) =>
|
||||
this.setScrollToTopBotomVisibility(showTop, showBottom)
|
||||
);
|
||||
}
|
||||
|
||||
private resetRemissionListScrollPosition(waitForAnimationToComplete: boolean = false) {
|
||||
private resetRemissionListScrollPosition(
|
||||
waitForAnimationToComplete: boolean = false
|
||||
) {
|
||||
if (!this.remissionHitsRef || !this.remissionHitsRef.first) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
@import '~@angular/cdk/overlay-prebuilt.css';
|
||||
@import './scss/theme';
|
||||
|
||||
* {
|
||||
@apply font-sans;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0; // remove scrollbar space
|
||||
background: transparent; // optional: just make scrollbar invisible */
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Directive,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
@@ -47,8 +46,10 @@ export class UiSearchboxInputDirective implements ControlValueAccessor {
|
||||
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
|
||||
|
||||
writeValue(obj: any): void {
|
||||
this.value = obj;
|
||||
console.log(obj);
|
||||
this.setValue(obj, { inputType: 'init' });
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
@@ -74,7 +75,7 @@ export class UiSearchboxInputDirective implements ControlValueAccessor {
|
||||
|
||||
setValue(
|
||||
value: string,
|
||||
{ inputType }: { inputType?: 'input' | 'autocomplete' }
|
||||
{ inputType }: { inputType?: 'input' | 'autocomplete' | 'init' }
|
||||
) {
|
||||
this.value = value;
|
||||
this.onChange(value);
|
||||
|
||||
@@ -8,13 +8,16 @@ module.exports = {
|
||||
'desktop-xl': '1680px',
|
||||
},
|
||||
zIndex: {
|
||||
dropdown: 10,
|
||||
sticky: 20,
|
||||
fixed: 30,
|
||||
modalBackdrop: 40,
|
||||
modal: 50,
|
||||
popover: 60,
|
||||
tooltip: 70,
|
||||
dropdown: 50,
|
||||
sticky: 100,
|
||||
fixed: 150,
|
||||
modalBackdrop: 200,
|
||||
modal: 250,
|
||||
popover: 300,
|
||||
tooltip: 350,
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Open Sans'],
|
||||
},
|
||||
extend: {
|
||||
fontSize: {
|
||||
@@ -27,6 +30,7 @@ module.exports = {
|
||||
},
|
||||
spacing: {
|
||||
'px-5': '5px',
|
||||
'px-8': '8px',
|
||||
'px-10': '10px',
|
||||
'px-15': '15px',
|
||||
'px-20': '20px',
|
||||
@@ -42,6 +46,9 @@ module.exports = {
|
||||
warning: '#be8100',
|
||||
brand: '#f70400',
|
||||
'ucla-blue': '#5a728a',
|
||||
'wild-blue-yonder': '#9cb1c6',
|
||||
'dark-cerulean': '#1f466c',
|
||||
glitter: '#e9f0f8',
|
||||
// active: '#1f466c',
|
||||
// inactive: '#3980c6',
|
||||
// disabled: '#b0cce8',
|
||||
@@ -63,6 +70,7 @@ module.exports = {
|
||||
},
|
||||
borderRadius: {
|
||||
card: '5px',
|
||||
filter: '20px',
|
||||
autocomplete: '30px',
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user