Merge branch 'feature/#3265-Scroll-Position-Bug' into develop

This commit is contained in:
Lorenz Hilpert
2022-07-11 16:13:05 +02:00
5 changed files with 26764 additions and 250 deletions

View File

@@ -63,7 +63,6 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
}
async applyFilter() {
this._goodsOutSearchStore.clearResults();
this._goodsOutSearchStore.setFilter(this.filter);
this.message = undefined;
@@ -91,7 +90,7 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
}
});
this._goodsOutSearchStore.search({});
this._goodsOutSearchStore.search({ clear: true });
}
async updateBreadcrumb() {

View File

@@ -6,8 +6,8 @@ import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QuerySettingsDTO } from '@swagger/oms';
import { UiFilter } from '@ui/filter';
import { isResponseArgs } from '@utils/object';
import { Observable, Subject } from 'rxjs';
import { switchMap, mergeMap, withLatestFrom, filter, take, tap } from 'rxjs/operators';
import { combineLatest, Observable, Subject } from 'rxjs';
import { switchMap, mergeMap, withLatestFrom, filter, take, tap, debounceTime, first, map } from 'rxjs/operators';
export interface GoodsOutSearchState {
defaultSettings?: QuerySettingsDTO;
@@ -17,7 +17,6 @@ export interface GoodsOutSearchState {
fetching: boolean;
hits: number;
results: OrderItemListItemDTO[];
searchOptions?: { take?: number; skip?: number };
}
@Injectable()
@@ -58,13 +57,6 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
readonly queryParams$ = this.select((s) => s.queryParams);
get searchOptions() {
return this.get((s) => s.searchOptions);
}
set searchOptions(searchOptions: { take?: number; skip?: number }) {
this.patchState({ searchOptions });
}
private _searchResultSubject = new Subject<ListResponseArgsOfOrderItemListItemDTO>();
readonly searchResult$ = this._searchResultSubject.asObservable();
@@ -125,15 +117,15 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
this.setFilter(filter);
}
clearResults() {
this.patchState({
fetching: false,
hits: 0,
message: undefined,
results: [],
});
this._searchResultClearedSubject.next();
}
// clearResults() {
// this.patchState({
// fetching: false,
// hits: 0,
// message: undefined,
// results: [],
// });
// this._searchResultClearedSubject.next();
// }
setQueryParams(queryParams: Record<string, string>) {
this.patchState({ queryParams });
@@ -143,60 +135,92 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
}
}
searchRequest(options?: { take?: number; skip?: number; reload?: boolean }) {
return this.filter$.pipe(
filter((f) => f instanceof UiFilter),
take(1),
mergeMap((filter) =>
this._domainGoodsInService.searchWarenausgabe({
...filter.getQueryToken(),
skip: options.reload ? 0 : options?.skip ?? this.results.length,
take: options.reload ? this.results.length : options?.take ?? 50,
})
)
);
}
// searchRequest(options: { skip?: number; take?: number }) {
// console.log('GoodsInSearchStore.searchRequest()', options);
// return this.filter$.pipe(
// filter((f) => f instanceof UiFilter),
// take(1),
// mergeMap((filter) => {
// console.log('GoodsInSearchStore.searchRequest()', filter);
// return this._domainGoodsInService.searchWarenausgabe({
// ...filter.getQueryToken(),
// skip: options.skip,
// take: options.take,
// });
// })
// );
// }
search = this.effect((options$: Observable<{ siletReload?: boolean }>) =>
search = this.effect((options$: Observable<{ clear?: boolean; siletReload?: boolean }>) =>
options$.pipe(
tap((options) => {
switchMap((options) => {
return this.results$.pipe(
map((results) => [options, results]),
first()
);
}),
switchMap(([options, results]) => {
return this.filter$.pipe(
filter((f) => f instanceof UiFilter),
map((filter) => [options, results, filter]),
first()
);
}),
tap(([options, results, filter]: [{ clear?: boolean; siletReload?: boolean }, OrderItemListItemDTO[], UiFilter]) => {
if (!options?.siletReload) {
this.patchState({ fetching: true });
}
if (options?.clear) {
this._searchResultClearedSubject.next();
}
}),
withLatestFrom(this.results$),
switchMap(([_options, _results]) => {
const queryToken = this.filter?.getQueryToken();
switchMap(([options, results, filter]) => {
const queryToken = filter?.getQueryToken() ?? {};
if (queryToken && this._cache.get(queryToken)) {
const cached = this._cache.get(queryToken);
let cachedResultCount: number;
this.patchState(cached);
if (options?.siletReload && this._cache.get(filter?.getQueryToken())) {
const cachedResults = this._cache.get(queryToken);
if (cachedResults?.results?.length > 0) {
this.patchState(cachedResults);
cachedResultCount = cachedResults.results.length;
}
}
return this.searchRequest({ ...this.searchOptions, reload: _options.siletReload }).pipe(
if (options.clear) {
queryToken.skip = 0;
queryToken.take = 50;
} else if (options.siletReload) {
queryToken.skip = 0;
queryToken.take = cachedResultCount || results.length || 50;
} else {
queryToken.skip = results.length;
queryToken.take = 50;
}
return this._domainGoodsInService.searchWarenausgabe(queryToken).pipe(
tapResponse(
(res) => {
let results: OrderItemListItemDTO[] = [];
if (_options.siletReload) {
results = res.result;
let _results: OrderItemListItemDTO[] = [];
if (options.siletReload) {
_results = res.result;
} else if (options.clear) {
_results = res.result;
} else {
results = [...(_results ?? []), ...(res.result ?? [])];
_results = [...results, ...(res.result ?? [])];
}
this.patchState({
hits: res.hits,
results,
results: _results,
fetching: false,
});
if (queryToken) {
this._cache.set(queryToken, {
hits: res.hits,
results,
fetching: false,
});
}
this._cache.set(filter?.getQueryToken(), {
hits: res.hits,
results: _results,
fetching: false,
});
this._searchResultSubject.next(res);
},
@@ -218,37 +242,37 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
)
);
reload = this.effect(($) =>
$.pipe(
tap((_) => this.patchState({ fetching: true })),
withLatestFrom(this.results$),
switchMap(([_, results]) =>
this.searchRequest({ take: results?.length ?? 0, skip: 0 }).pipe(
tapResponse(
(res) => {
this.patchState({
hits: res.hits,
results: res.result,
fetching: false,
});
// reload = this.effect(($) =>
// $.pipe(
// tap((_) => this.patchState({ fetching: true })),
// withLatestFrom(this.results$),
// switchMap(([_, results]) =>
// this.searchRequest({ reload: true }).pipe(
// tapResponse(
// (res) => {
// this.patchState({
// hits: res.hits,
// results: res.result,
// fetching: false,
// });
this._searchResultSubject.next(res);
},
(err: Error) => {
if (err instanceof HttpErrorResponse && isResponseArgs(err.error)) {
this._searchResultSubject.next(err.error);
} else {
this._searchResultSubject.next({
error: true,
message: err.message,
});
}
this.patchState({ fetching: false });
console.error('GoodsInSearchStore.reload()', err);
}
)
)
)
)
);
// this._searchResultSubject.next(res);
// },
// (err: Error) => {
// if (err instanceof HttpErrorResponse && isResponseArgs(err.error)) {
// this._searchResultSubject.next(err.error);
// } else {
// this._searchResultSubject.next({
// error: true,
// message: err.message,
// });
// }
// this.patchState({ fetching: false });
// console.error('GoodsInSearchStore.reload()', err);
// }
// )
// )
// )
// )
// );
}

View File

@@ -79,7 +79,6 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
}
async search() {
this._goodsOutSearchStore.clearResults();
await this.updateQueryParams(this.processId);
this.message = undefined;
@@ -103,8 +102,7 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
this._cdr.markForCheck();
});
this._goodsOutSearchStore.searchOptions = { take: 50, skip: 0 };
this._goodsOutSearchStore.search({});
this._goodsOutSearchStore.search({ clear: true });
}
async updateBreadcrumb(processId: number, params: Record<string, string>) {

View File

@@ -87,23 +87,48 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
});
}
saveScrollPosition(processId: number, scrollPosition: number) {
// console.log('saveScrollPosition', processId, scrollPosition);
localStorage.setItem(`SCROLL_POSITION_${processId}`, JSON.stringify(scrollPosition));
}
getScrollPosition(processId: number): number | undefined {
// try {
// throw new Error('test');
// } catch (error) {
// console.error(error);
// }
const scroll_position = localStorage.getItem(`SCROLL_POSITION_${processId}`);
console.log('getScrollPosition', processId, scroll_position ? JSON.parse(scroll_position) : undefined);
return scroll_position ? JSON.parse(scroll_position) : undefined;
}
// removeScrollPosition(processId: number) {
// console.log('removeScrollPosition', processId);
// localStorage.removeItem(`SCROLL_POSITION_${processId}`);
// }
ngOnInit() {
this.processId$
.pipe(takeUntil(this._onDestroy$), debounceTime(1), withLatestFrom(this._activatedRoute.queryParams))
.pipe(takeUntil(this._onDestroy$), debounceTime(10), withLatestFrom(this._activatedRoute.queryParams))
.subscribe(([processId, params]) => {
if (this.previousProcessId && this.previousProcessId !== processId) {
this.saveScrollPosition(this.previousProcessId, this.scrollContainer.scrollPos);
}
this._goodsOutSearchStore.setQueryParams(params);
this.updateBreadcrumb(processId, params);
this.initInitialSearch(processId, params);
this.createBreadcrumb(processId, params);
this.removeBreadcrumbs(processId);
if (this.previousProcessId !== processId) {
this.initInitialSearch(processId, params);
this.createBreadcrumb(processId, params);
this.removeBreadcrumbs(processId);
this.previousProcessId = processId;
if (this.previousProcessId && processId !== this.previousProcessId) {
this._goodsOutSearchStore.clearResults();
this._goodsOutSearchStore.search({ siletReload: true });
}
this.previousProcessId = processId;
});
this._goodsOutSearchStore.searchResultCleared.pipe(takeUntil(this._onDestroy$)).subscribe((_) => this.clearSelectedItems());
@@ -114,6 +139,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
this._onDestroy$.complete();
this.updateBreadcrumb(this.previousProcessId, this._goodsOutSearchStore.filter?.getQueryParams());
this.saveScrollPosition(this.previousProcessId, this.scrollContainer.scrollPos);
}
async removeBreadcrumbs(processId: number) {
@@ -141,10 +167,22 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
});
}
async updateBreadcrumb(processId: number, queryParams: Record<string, string>) {
const scroll_position = this.scrollContainer?.scrollPos;
const take = this._goodsOutSearchStore.results?.length;
// async updateScrollPosition(processId: number) {
// const scroll_position = this.scrollContainer?.scrollPos;
// const crumbs = await this._breadcrumb
// .getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'results', 'filter'])
// .pipe(first())
// .toPromise();
// crumbs.forEach((crumb) => {
// const params: Record<string, string> = { ...((crumb.params as Record<string, string>) ?? {}) };
// params.scroll_position = String(scroll_position);
// this._breadcrumb.patchBreadcrumb(crumb.id, { params });
// });
// }
async updateBreadcrumb(processId: number, queryParams: Record<string, string>) {
if (queryParams) {
const crumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'results', 'filter'])
@@ -152,7 +190,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
.toPromise();
const name = queryParams.main_qs ? queryParams.main_qs : 'Alle Artikel';
const params = { ...queryParams, scroll_position, take };
const params = { ...queryParams };
for (const crumb of crumbs) {
this._breadcrumb.patchBreadcrumb(crumb.id, {
@@ -181,24 +219,24 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
if (result.hits === 1) {
await this.navigateToDetails(processId, result.result[0]);
} else {
if (!!this._goodsOutSearchStore.searchOptions?.take) {
this._goodsOutSearchStore.searchOptions = undefined;
this.scrollContainer.scrollTo(Number(scroll_position ?? 0));
const scrollPos = this.getScrollPosition(processId);
if (scrollPos) {
this.scrollContainer?.scrollTo(scrollPos);
}
}
}
});
this._goodsOutSearchStore.search({});
}
const { scroll_position, take } = this._goodsOutSearchStore.queryParams;
if (!!take && !!scroll_position) {
this._goodsOutSearchStore.searchOptions = { take: Number(take) };
}
// const { scroll_position, take } = this._goodsOutSearchStore.queryParams;
// if (!!take && !!scroll_position) {
// this._goodsOutSearchStore.searchOptions = { take: Number(take) };
// }
}
async loadMore() {
if (this._goodsOutSearchStore.hits > this._goodsOutSearchStore.results.length && !this._goodsOutSearchStore.fetching) {
this.saveScrollPosition(this.previousProcessId, this.scrollContainer.scrollPos);
this._goodsOutSearchStore.search({});
}
}
@@ -249,7 +287,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
};
try {
await this._commandService.handleCommand(action.command, commandData);
this._goodsOutSearchStore.reload();
this._goodsOutSearchStore.search({ siletReload: true });
this.clearSelectedItems();
this.loadingFetchedActionButton$.next(false);
} catch (error) {

26733
package-lock.json generated
View File

File diff suppressed because it is too large Load Diff