Merged PR 1215: #3062 #3051 Remission Breadcrumbs contain the correct queryParams, Remission Process Remembers Filters if Remission is started

#3062 #3051 Remission Breadcrumbs contain the correct queryParams, Remission Process Remembers Filters if Remission is started. Always load available Remission
This commit is contained in:
Nino Righi
2022-05-09 11:41:50 +00:00
committed by Andreas Schickinger
parent 42199c8cda
commit 9f0c81c20f
12 changed files with 133 additions and 23 deletions

View File

@@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { Config } from '@core/config';
import { first } from 'rxjs/operators';
@@ -27,7 +26,8 @@ export class CanActivateRemissionGuard implements CanActivate {
this._applicationService.activateProcess(this._config.get('process.ids.remission'));
if (!!process?.data?.active && !state.url.includes(`/filiale/remission/${process?.data?.active}`)) {
await this._router.navigate(['/filiale', 'remission', process?.data?.active, 'list']);
const queryParams = process?.data?.queryParams ?? {};
await this._router.navigate(['/filiale', 'remission', process?.data?.active, 'list'], { queryParams });
return false;
} else {
return true;

View File

@@ -61,7 +61,7 @@
<ui-icon icon="box_return" size="24px"></ui-icon>
Abholfach
</a>
<a [routerLink]="['/filiale/remission']" routerLinkActive="active">
<a [routerLink]="[remissionUrl$ | async]" [queryParams]="remissionQueryParams$ | async" routerLinkActive="active">
<ui-icon icon="documents_refresh" size="24px"></ui-icon>
Remission
</a>

View File

@@ -5,6 +5,7 @@ import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { AuthService } from '@core/auth';
import { Config } from '@core/config';
import { BreadcrumbService } from '@core/breadcrumb';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainDashboardService } from '@domain/isa';
@@ -56,13 +57,14 @@ describe('ShellComponent', () => {
MockComponent(ShellProcessTabComponent),
MockComponent(UiIconComponent),
],
mocks: [BreadcrumbService, DomainAvailabilityService, AuthService, DomainDashboardService],
mocks: [BreadcrumbService, DomainAvailabilityService, AuthService, DomainDashboardService, Config],
});
beforeEach(() => {
applicationServiceMock = createSpyObject(ApplicationService);
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of([]));
applicationServiceMock.getProcessById$.and.returnValue(of({ id: 4000 }));
applicationServiceMock.getActivatedProcessId$.and.returnValue(of(undefined));
applicationServiceMock.getLastActivatedProcessWithSectionAndType$.and.returnValue(of({}));
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({}));
@@ -225,6 +227,63 @@ describe('ShellComponent', () => {
});
});
describe('remissionProcess$', () => {
it('should call _appService.getProcessById$() with Remission Id and return its value', async () => {
applicationServiceMock.getProcessById$.and.returnValue(of({ id: 4000 }));
await spectator.component.remissionProcess$.pipe(first()).toPromise();
expect(applicationServiceMock.getProcessById$).toHaveBeenCalled();
});
});
describe('remissionUrl$', () => {
it('should return the correct url if process.data.active is available', async () => {
const process = {
id: 4000,
data: {
active: 9999,
},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const url = await spectator.component.remissionUrl$.pipe(first()).toPromise();
expect(url).toBe('/filiale/remission/9999/list');
});
it('should return the correct url if process.data.active is not available', async () => {
const process = {
id: 4000,
data: {},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const url = await spectator.component.remissionUrl$.pipe(first()).toPromise();
expect(url).toBe('/filiale/remission');
});
});
describe('remissionQueryParams$', () => {
it('should return the correct queryParams if process.data.active and process.data.queryParams are available', async () => {
const process = {
id: 4000,
data: {
active: 9999,
queryParams: { filter: 'test' },
},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const queryParams = await spectator.component.remissionQueryParams$.pipe(first()).toPromise();
expect(queryParams).toEqual(process.data.queryParams);
});
it('should return the correct queryParams if process.data.active and process.data.queryParams are not available', async () => {
const process = {
id: 4000,
data: {},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const queryParams = await spectator.component.remissionQueryParams$.pipe(first()).toPromise();
expect(queryParams).toEqual({});
});
});
describe('setSection()', () => {
it('should call _appService.setSection() with the argument section', async () => {
await spectator.component.setSection('customer');

View File

@@ -10,6 +10,7 @@ import { combineLatest } from 'rxjs';
import { AuthService } from '@core/auth';
import { DomainAvailabilityService } from '@domain/availability';
import { ShellProcessTabComponent } from '@shell/process';
import { Config } from '@core/config';
@Component({
selector: 'app-shell',
@@ -37,6 +38,22 @@ export class ShellComponent {
return this.section$.pipe(switchMap((section) => this._appService.getProcesses$(section)));
}
get remissionProcess$() {
return this._appService.getProcessById$(this._config.get('process.ids.remission'));
}
get remissionUrl$() {
return this.remissionProcess$.pipe(
map((process) => (process?.data?.active ? `/filiale/remission/${process.data.active}/list` : '/filiale/remission'))
);
}
get remissionQueryParams$() {
return this.remissionProcess$.pipe(
map((process) => (process?.data?.active && process?.data?.queryParams ? process.data.queryParams : {}))
);
}
get addProcessLabel$() {
return combineLatest([this.section$, this.processes$]).pipe(
map(([section, processes]) => (section === 'customer' && processes.length === 0 ? 'VORGANG STARTEN' : ''))
@@ -53,6 +70,7 @@ export class ShellComponent {
constructor(
private readonly _appService: ApplicationService,
private readonly _config: Config,
private readonly _notificationsHub: NotificationsHub,
private readonly _modal: UiModalService,
private readonly _router: Router,

View File

@@ -23,6 +23,10 @@ export class AddProductComponent implements OnInit, OnDestroy {
hint$ = new Subject<string>();
get queryParams() {
return this._activatedRoute?.snapshot?.queryParams;
}
constructor(
private _remiService: DomainRemissionService,
private _modal: UiModalService,
@@ -72,7 +76,7 @@ export class AddProductComponent implements OnInit, OnDestroy {
});
modal.afterClosed$.pipe(takeUntil(this._onDestroy)).subscribe((result) => {
if (result.data) {
this._router.navigate(['..', 'list'], { relativeTo: this._activatedRoute });
this._router.navigate(['..', 'list'], { relativeTo: this._activatedRoute, queryParams: this.queryParams });
}
});
}
@@ -102,6 +106,7 @@ export class AddProductComponent implements OnInit, OnDestroy {
name: 'Wannennummer',
path: '/filiale/remission/add-product',
section: 'branch',
params: this.queryParams,
tags: ['remission', 'add-product'],
});
}

View File

@@ -26,8 +26,7 @@ export class RemissionFilterComponent implements OnDestroy {
}
applyFilter(filter: UiFilter) {
this.store.setFilter(filter);
this.store._filterChange$.next(true);
this.store.applyFilter(filter);
this.close.emit();
}

View File

@@ -38,9 +38,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
_sourceOrSupplierChange$ = new BehaviorSubject<boolean>(false);
_filterChange$ = new BehaviorSubject<boolean>(false);
scroll = new Subject<number>();
private _filterChange$ = new BehaviorSubject<boolean>(false);
get processId() {
return this._config.get('process.ids.remission');
@@ -364,17 +362,36 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
);
}
clearCache() {
this._cache.delete({ processId: String(this.processId) });
}
clearItems() {
this.setFetching(true);
this.setSearchResult({ result: [], hits: 0 });
}
async applyFilter(filter: UiFilter) {
this._filterChange$.next(true);
this.setFilter(filter);
this.clearCache();
await this._router.navigate([], {
queryParams: {
...filter.getQueryParams(),
scroll_position: 0,
},
queryParamsHandling: 'merge',
});
}
async setSupplier(supplier: SupplierDTO) {
this._sourceOrSupplierChange$.next(true);
this.setSearchResult({ result: [], hits: 0 });
this.clearCache();
await this._router.navigate([], {
queryParams: {
supplier: supplier.id,
scroll_position: 0,
},
queryParamsHandling: 'merge',
});
@@ -383,9 +400,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
async setSource(source: string) {
this._sourceOrSupplierChange$.next(true);
this.setSearchResult({ result: [], hits: 0 });
this.clearCache();
await this._router.navigate([], {
queryParams: {
source,
scroll_position: 0,
},
queryParamsHandling: 'merge',
});

View File

@@ -51,10 +51,15 @@
</div>
<p *ngIf="!(return$ | async)" class="text-center mt-4">
<a class="text-brand font-bold text-xl px-4 py-3" routerLink="../add-product">
<a class="text-brand font-bold text-xl px-4 py-3" [queryParams]="queryParams$ | async" routerLink="../add-product">
Artikel hinzufügen
</a>
<button type="button" class="text-brand font-bold text-xl px-4 py-3" routerLink="../shipping-documents">
<button
type="button"
class="text-brand font-bold text-xl px-4 py-3"
[queryParams]="queryParams$ | async"
routerLink="../shipping-documents"
>
Warenbegleitscheine <span *ngIf="returnCount$ | async; let returnCount">({{ returnCount ?? 0 }})</span>
</button>
</p>

View File

@@ -61,6 +61,7 @@ const routes: Routes = [
},
{
path: '',
pathMatch: 'full',
redirectTo: 'list',
},
],

View File

@@ -32,7 +32,6 @@ export class RemissionComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.addBreadcrumbIfNotExists();
this.clearCache();
this._router.events
?.pipe(
@@ -64,15 +63,14 @@ export class RemissionComponent implements OnInit, OnDestroy {
async updateProcess() {
const params = this._activatedRoute.snapshot.firstChild.params;
const process = await this._applicationService.getProcessById$(this.processId).pipe(first()).toPromise();
const queryParams = this._activatedRoute.snapshot.queryParams ?? {};
if (!!params?.returnId) {
if (process?.data?.active !== +params.returnId) {
this._applicationService.patchProcess(this.processId, {
closeable: false,
data: { active: +params.returnId },
});
}
this._applicationService.patchProcess(this.processId, {
closeable: false,
data: { active: +params.returnId, queryParams },
});
} else {
this.clearCache();
this._applicationService.patchProcess(this.processId, {
closeable: true,
data: {},

View File

@@ -7,7 +7,7 @@ import { DomainRemissionService } from '@domain/remission';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ReturnDTO } from '@swagger/remi';
import { NEVER, Observable } from 'rxjs';
import { catchError, filter, map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { catchError, filter, first, map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { ShortReceiptNumberPipe } from '../../pipes/short-receipt-number.pipe';
export interface ShippingDocumentDetailsState {
@@ -108,14 +108,16 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'finish-remission']);
}
navigateBack() {
async navigateBack() {
const queryParams = await this.queryParams$.pipe(first()).toPromise();
this.remissionStarted
? this._router.navigate(['../list'], { relativeTo: this._activatedRoute })
? this._router.navigate(['../list'], { relativeTo: this._activatedRoute, queryParams })
: this._router.navigate(['..'], { relativeTo: this._activatedRoute });
}
async addOrUpdateBreadcrumbIfNotExists(returnDto: ReturnDTO) {
const packageNumber = returnDto?.receipts?.find((_) => true)?.data?.receiptNumber;
const params = await this.queryParams$.pipe(first()).toPromise();
if (packageNumber) {
const shortPackageNumber = this._shortReceiptNumberPipe.transform(packageNumber);
this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
@@ -125,6 +127,7 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
? `/filiale/remission/${returnDto.id}/shipping-document`
: `/filiale/remission/shipping-documents/${returnDto.id}`,
section: 'branch',
params,
tags: ['remission', 'shipping-documents', 'details'],
});
}

View File

@@ -1,4 +1,5 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { Config } from '@core/config';
import { DomainRemissionService } from '@domain/remission';
@@ -20,6 +21,7 @@ export class ShippingDocumentListComponent implements OnInit {
private _remissionService: DomainRemissionService,
private _breadcrumb: BreadcrumbService,
private _config: Config,
private _activatedRoute: ActivatedRoute,
private readonly _dateAdapter: DateAdapter
) {}
@@ -42,6 +44,7 @@ export class ShippingDocumentListComponent implements OnInit {
name: 'Offene Warenbegleitscheine',
path: '/filiale/remission/shipping-documents',
section: 'branch',
params: this._activatedRoute?.snapshot?.queryParams,
tags: ['remission', 'shipping-documents'],
});
}