mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
#1460 Implemented Scroll Position Service with Prefetch
This commit is contained in:
committed by
Lorenz Hilpert
parent
cd0dcca911
commit
fd60dca5ab
@@ -7,6 +7,7 @@ import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { CountryDTO, CustomerDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
|
||||
import { UiValidators } from '@ui/common';
|
||||
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
import { validateEmail } from '../../validators/email-validator';
|
||||
@@ -34,7 +35,8 @@ export abstract class CustomerDataEditComponent implements OnInit {
|
||||
private cdr: ChangeDetectorRef,
|
||||
private location: Location,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private application: ApplicationService
|
||||
private application: ApplicationService,
|
||||
private scrollPositionService: ScrollPositionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -126,6 +128,12 @@ export abstract class CustomerDataEditComponent implements OnInit {
|
||||
|
||||
try {
|
||||
await this.customerService.patchCustomer(this.customerId, this.control.value).toPromise();
|
||||
if (!!this.scrollPositionService.data) {
|
||||
const index = this.scrollPositionService.data?.result?.findIndex((customer) => customer.id === this.customerId);
|
||||
const obj = this.scrollPositionService.data?.result[index];
|
||||
const updatedObj = Object.assign(obj, this.control.value);
|
||||
this.scrollPositionService.data.result.splice(index, 1, updatedObj);
|
||||
}
|
||||
this.location.back();
|
||||
} catch (err) {
|
||||
this.control.enable();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ApplicationService, ProcessService } from '@core/application';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { CartService } from '@domain/cart';
|
||||
@@ -8,7 +8,7 @@ import { AddressHelper, AssignedPayerHelper, CrmCustomerService } from '@domain/
|
||||
import { CustomerDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { ShippingAddressHelper } from 'apps/domain/crm/src/lib/helpers/shipping-address.helper';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { first, map, shareReplay, switchMap, tap } from 'rxjs/operators';
|
||||
import { CantAddCustomerToCartModalComponent } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.component';
|
||||
import { CantAddCustomerToCartData } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.data';
|
||||
@@ -19,7 +19,7 @@ import { CantAddCustomerToCartData } from '../modals/cant-add-customer-to-cart-m
|
||||
styleUrls: ['customer-details.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CustomerDetailsComponent implements OnInit, OnDestroy {
|
||||
export class CustomerDetailsComponent implements OnInit {
|
||||
customerId$: Observable<number>;
|
||||
customer$: Observable<CustomerDTO>;
|
||||
|
||||
@@ -39,8 +39,6 @@ export class CustomerDetailsComponent implements OnInit, OnDestroy {
|
||||
|
||||
private currentBreadcrumb: Breadcrumb;
|
||||
|
||||
scrollSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private customerDetailsService: CrmCustomerService,
|
||||
@@ -106,15 +104,6 @@ export class CustomerDetailsComponent implements OnInit, OnDestroy {
|
||||
)
|
||||
);
|
||||
|
||||
this.scrollSubscription = this.router.events.subscribe((events) => {
|
||||
if (events instanceof NavigationStart) {
|
||||
if (!events?.url.includes('/customer/search') && !events?.url.includes('query')) {
|
||||
// Scrollposition im sessionStorage löschen wenn nicht zur suche zurück navigiert wird
|
||||
sessionStorage.removeItem('scrollPos');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.isB2b$ = this.customerType$.pipe(map((type) => type === 'b2b'));
|
||||
this.isWebshopOrGuest$ = this.customerType$.pipe(map((type) => type === 'webshop' || type === 'guest'));
|
||||
|
||||
@@ -124,12 +113,6 @@ export class CustomerDetailsComponent implements OnInit, OnDestroy {
|
||||
this.createBreadcrumb();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (!!this.scrollSubscription) {
|
||||
this.scrollSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
async createBreadcrumb() {
|
||||
const customerId = await this.customerId$.pipe(first()).toPromise();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { NativeContainerService } from 'native-container';
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { delay, map, switchMap } from 'rxjs/operators';
|
||||
import { CustomerSearch } from './customer-search.service';
|
||||
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-search',
|
||||
@@ -37,9 +38,10 @@ export class CustomerSearchComponent extends CustomerSearch implements OnInit {
|
||||
filterMapping: UiFilterMappingService,
|
||||
nativeContainer: NativeContainerService,
|
||||
application: ApplicationService,
|
||||
breadcrumb: BreadcrumbService
|
||||
breadcrumb: BreadcrumbService,
|
||||
scrollPositionService: ScrollPositionService
|
||||
) {
|
||||
super(zone, router, application, breadcrumb, env, filterMapping, nativeContainer);
|
||||
super(zone, router, application, breadcrumb, env, filterMapping, nativeContainer, scrollPositionService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { NativeContainerService } from 'native-container';
|
||||
import { StringDictionary } from '@cmf/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
|
||||
|
||||
@Injectable()
|
||||
export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
@@ -47,8 +48,6 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
result: [],
|
||||
});
|
||||
|
||||
searchCompleted = new Subject();
|
||||
|
||||
public searchState$ = new BehaviorSubject<ResultState>('init');
|
||||
|
||||
get searchState(): ResultState {
|
||||
@@ -82,7 +81,8 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private environmentService: EnvironmentService,
|
||||
private filterMapping: UiFilterMappingService,
|
||||
private nativeContainer: NativeContainerService
|
||||
private nativeContainer: NativeContainerService,
|
||||
private scrollPositionService: ScrollPositionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -253,7 +253,11 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
switchMap(([effectiveTake, hitsTake]) => {
|
||||
return this.customerSearch
|
||||
.getCustomers(this.queryFilter.query, {
|
||||
skip: options.isNewSearch ? 0 : this.numberOfResultsFetched - effectiveTake,
|
||||
skip: options.isNewSearch
|
||||
? 0
|
||||
: !!this.scrollPositionService.data
|
||||
? this.numberOfResultsFetched + this.scrollPositionService.data?.skip
|
||||
: this.numberOfResultsFetched - effectiveTake,
|
||||
take: hitsTake,
|
||||
filter: this.getSelecteFiltersAsDictionary(),
|
||||
})
|
||||
@@ -297,18 +301,29 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: remove that and implement inside search results component
|
||||
// if (!!this.scrollPositionService.data) {
|
||||
// this.searchResult$.next({
|
||||
// ...r,
|
||||
// hits,
|
||||
// result: [
|
||||
// ...this.scrollPositionService.data.result,
|
||||
// ...this.searchResult$.value.result,
|
||||
// ...r.result.map((a) => ({ ...a, loaded: true })),
|
||||
// ],
|
||||
// });
|
||||
// } else {
|
||||
this.searchResult$.next({
|
||||
...r,
|
||||
hits,
|
||||
result: [...this.searchResult$.value.result, ...r.result.map((a) => ({ ...a, loaded: true }))],
|
||||
});
|
||||
// }
|
||||
}
|
||||
|
||||
if (hits > 0) {
|
||||
this.filterActive$.next(false);
|
||||
}
|
||||
|
||||
this.searchCompleted.next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { CustomerSearch } from '../customer-search.service';
|
||||
@@ -23,13 +23,14 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
|
||||
public cdr: ChangeDetectorRef,
|
||||
public environmentService: EnvironmentService,
|
||||
public application: ApplicationService,
|
||||
private breadcrumb: BreadcrumbService
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private scrollPositionService: ScrollPositionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.detectDevice();
|
||||
this.initBreadcrumb();
|
||||
sessionStorage.removeItem('scrollPos');
|
||||
this.scrollPositionService.resetService();
|
||||
}
|
||||
|
||||
initBreadcrumb() {
|
||||
|
||||
@@ -2,8 +2,9 @@ import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnDestro
|
||||
import { NavigationStart, Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { filter, first, map, take } from 'rxjs/operators';
|
||||
import { CustomerSearch } from '../customer-search.service';
|
||||
import { CustomerSearchType } from '../defs';
|
||||
|
||||
@@ -18,7 +19,6 @@ export class CustomerSearchResultComponent implements OnInit, OnDestroy, AfterVi
|
||||
private _breadcrumb: Breadcrumb;
|
||||
customers$: Observable<CustomerSearchType[]>;
|
||||
scrollSubscription: Subscription;
|
||||
onLoadSubscription: Subscription;
|
||||
|
||||
protected readonly viewportEnterOptions: IntersectionObserverInit = {
|
||||
threshold: 0.75,
|
||||
@@ -28,36 +28,35 @@ export class CustomerSearchResultComponent implements OnInit, OnDestroy, AfterVi
|
||||
private application: ApplicationService,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
public search: CustomerSearch,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private scrollPositionService: ScrollPositionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.customers$ = this.search.searchResult$.pipe(
|
||||
map((response) => {
|
||||
// console.log(response);
|
||||
if (!!this.scrollPositionService.data) {
|
||||
return [...this.scrollPositionService.data.result, ...response.result];
|
||||
}
|
||||
return response.result;
|
||||
})
|
||||
);
|
||||
|
||||
// Safe current scroll position if navigating to Customer Details
|
||||
this.scrollSubscription = this.router.events.subscribe((events) => {
|
||||
if (events instanceof NavigationStart) {
|
||||
const customerId = Number.parseInt(events.url.replace(/\D/g, ''), 10);
|
||||
if (events?.url === `/customer/${customerId}`) {
|
||||
// Safe Scrollposition inside sessionStorage
|
||||
sessionStorage.setItem('scrollPos', `${this.scrollContainer.nativeElement.scrollTop}`);
|
||||
// - TESTING -
|
||||
// Safe Loaded customers
|
||||
// --> SAFE EDITED DATA TO LOADED CUSTOMERS ASWELL !!
|
||||
// this.search.searchResult$.subscribe((res) => {
|
||||
// console.log(res.result);
|
||||
// sessionStorage.setItem('preloadedCustomers', JSON.stringify(res.result));
|
||||
// });
|
||||
console.log(this.search.searchResult$.value.result);
|
||||
// sessionStorage.setItem('preloadedCustomers', JSON.stringify(this.search.searchResult$.value.result));
|
||||
} else {
|
||||
sessionStorage.removeItem('scrollPos');
|
||||
// sessionStorage.removeItem('preloadedCustomers');
|
||||
// Safe Scrollposition
|
||||
this.scrollPositionService.scrollPosition = this.scrollContainer.nativeElement.scrollTop;
|
||||
// Safe prefetched data
|
||||
if (!!this.scrollPositionService.data) {
|
||||
const oldResult = this.scrollPositionService.data.result;
|
||||
const newResult = this.search.searchResult$.value.result;
|
||||
this.scrollPositionService.data = this.search.searchResult$.value;
|
||||
this.scrollPositionService.data.result = [...oldResult, ...newResult];
|
||||
} else {
|
||||
this.scrollPositionService.data = this.search.searchResult$.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -66,25 +65,7 @@ export class CustomerSearchResultComponent implements OnInit, OnDestroy, AfterVi
|
||||
|
||||
ngAfterViewInit() {
|
||||
// Start scrolling to last remembered position
|
||||
this.scrollContainer.nativeElement.scrollTo(0, Number(sessionStorage.getItem('scrollPos')));
|
||||
|
||||
// ### SHOULD BE REMOVED IF CONTENT GETS PRELOADED ###
|
||||
// If content needs to be loaded, invoke the scroll again
|
||||
this.onLoadSubscription = this.search.searchCompleted.subscribe(() => {
|
||||
const container = this.scrollContainer.nativeElement.scrollTop;
|
||||
const storage = Number(sessionStorage.getItem('scrollPos'));
|
||||
if (container <= storage) {
|
||||
// Scroll to content
|
||||
this.scrollContainer.nativeElement.scrollTo(0, storage);
|
||||
} else if (storage <= 1100) {
|
||||
// Stop scrolling if needed content is loaded without loading more items
|
||||
this.onLoadSubscription.unsubscribe();
|
||||
} else {
|
||||
// Jump to content after items loaded and stop scrolling
|
||||
this.scrollContainer.nativeElement.scrollTo(0, storage);
|
||||
this.onLoadSubscription.unsubscribe();
|
||||
}
|
||||
});
|
||||
this.scrollPositionService.scrollToLastRememberedPosition(this.scrollContainer);
|
||||
}
|
||||
|
||||
async initBreadcrumb() {
|
||||
@@ -118,13 +99,9 @@ export class CustomerSearchResultComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.search.searchState$.next('init');
|
||||
if (!!this.scrollSubscription) {
|
||||
this.scrollSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.onLoadSubscription) {
|
||||
this.onLoadSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
checkIfReload(target: HTMLElement): void {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { ScrollPositionService } from 'apps/ui/common/src/lib/scroll-position/scroll-position.service';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer',
|
||||
templateUrl: 'page-customer.component.html',
|
||||
styleUrls: ['page-customer.component.scss'],
|
||||
providers: [ScrollPositionService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PageCustomerComponent {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { ElementRef, Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class ScrollPositionService {
|
||||
private scrollPos = 0;
|
||||
private prefetchedData: any;
|
||||
|
||||
get scrollPosition(): number {
|
||||
return this.scrollPos;
|
||||
}
|
||||
|
||||
set scrollPosition(scrollPosition: number) {
|
||||
this.scrollPos = scrollPosition;
|
||||
}
|
||||
|
||||
get data(): any {
|
||||
return this.prefetchedData;
|
||||
}
|
||||
|
||||
set data(data: any) {
|
||||
this.prefetchedData = data;
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
resetService() {
|
||||
this.scrollPosition = 0;
|
||||
this.data = undefined;
|
||||
}
|
||||
|
||||
scrollToLastRememberedPosition(elementRef: ElementRef<any>) {
|
||||
// Skip initial call
|
||||
if (!!this.scrollPosition && !!this.data) {
|
||||
elementRef.nativeElement.scrollTo(0, this.scrollPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user