mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Compare commits
27 Commits
fix/4696-A
...
feature/47
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79906dc3ea | ||
|
|
bc3b2d9a80 | ||
|
|
43d8d220c9 | ||
|
|
e0993d9c46 | ||
|
|
82656d9b27 | ||
|
|
df36d0934d | ||
|
|
3a9820aa54 | ||
|
|
30ad99332e | ||
|
|
4b48275910 | ||
|
|
d3e3316459 | ||
|
|
4ef1bd4df6 | ||
|
|
0c2a23e5d2 | ||
|
|
36bd2c1eba | ||
|
|
a38d2eede6 | ||
|
|
f5251d9069 | ||
|
|
2bd21e168a | ||
|
|
3661bf7580 | ||
|
|
9f2a6633f7 | ||
|
|
3c4d0ea56c | ||
|
|
56bb784c83 | ||
|
|
c687570b1f | ||
|
|
afe5d3468a | ||
|
|
65f43d22ee | ||
|
|
67203a8506 | ||
|
|
8f47163627 | ||
|
|
a209d59ea9 | ||
|
|
b838f4c475 |
@@ -0,0 +1,31 @@
|
||||
import { Directive, HostListener, Input } from '@angular/core';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
|
||||
@Directive({
|
||||
selector: '[productImageNavigation]',
|
||||
standalone: true,
|
||||
})
|
||||
export class NavigateOnClickDirective {
|
||||
@Input('productImageNavigation') ean: string;
|
||||
|
||||
constructor(private readonly _productCatalogNavigation: ProductCatalogNavigationService) {}
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
async onClick(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (this.ean) {
|
||||
await this._navigateToProductSearchDetails();
|
||||
}
|
||||
}
|
||||
|
||||
private async _navigateToProductSearchDetails() {
|
||||
await this._productCatalogNavigation
|
||||
.getArticleDetailsPathByEan({
|
||||
processId: Date.now(),
|
||||
ean: this.ean,
|
||||
extras: { queryParams: { main_qs: this.ean } },
|
||||
})
|
||||
.navigate();
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,5 @@
|
||||
export * from './lib/product-image.service';
|
||||
export * from './lib/product-image.module';
|
||||
export * from './lib/product-image.pipe';
|
||||
export * from './lib/product-image-navigation.directive';
|
||||
export * from './lib/tokens';
|
||||
|
||||
@@ -35,7 +35,11 @@
|
||||
</div>
|
||||
|
||||
<div class="branch-actions">
|
||||
<button *ngIf="(branch.id | stockInfo: (inStock$ | async))?.availableQuantity > 0" class="cta-reserve" (click)="reserve(branch)">
|
||||
<button
|
||||
*ngIf="(branch.id | stockInfo: (inStock$ | async))?.availableQuantity > 0 && branch?.isShippingEnabled"
|
||||
class="cta-reserve"
|
||||
(click)="reserve(branch)"
|
||||
>
|
||||
Reservieren
|
||||
</button>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export class ModalAvailabilitiesComponent {
|
||||
(branch) =>
|
||||
branch &&
|
||||
branch?.isOnline &&
|
||||
branch?.isShippingEnabled &&
|
||||
// branch?.isShippingEnabled && ------ Rausgenommen aufgrund des Tickets #4712
|
||||
branch?.isOrderingEnabled &&
|
||||
branch?.id !== userbranch?.id &&
|
||||
branch?.branchType === 1
|
||||
|
||||
@@ -439,11 +439,10 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
async navigateToResultList() {
|
||||
const processId = this.applicationService.activatedProcessId;
|
||||
let crumbs = await this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog'])
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog', 'details'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
crumbs = crumbs.filter((crumb) => !crumb.tags?.includes('details'));
|
||||
const crumb = crumbs[crumbs.length - 1];
|
||||
if (!!crumb) {
|
||||
await this._navigationService.getArticleSearchResultsPath(processId, { queryParams: crumb.params }).navigate();
|
||||
|
||||
@@ -155,7 +155,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
|
||||
const cleanQueryParams = this.cleanupQueryParams(queryParams);
|
||||
|
||||
if (this.route.outlet === 'primary' || processChanged) {
|
||||
if (processChanged) {
|
||||
this.scrollToItem(this._getScrollIndexFromCache());
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
private _getScrollIndexFromCache(): number {
|
||||
return this.cache.get<number>({ processId: this.getProcessId(), token: this.SCROLL_INDEX_TOKEN });
|
||||
return this.cache.get<number>({ processId: this.getProcessId(), token: this.SCROLL_INDEX_TOKEN }) ?? 0;
|
||||
}
|
||||
|
||||
scrollToItem(i?: number) {
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
<ng-container *ngIf="payer$ | async; let payer">
|
||||
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between p-5 pt-0">
|
||||
<div class="flex flex-row flex-wrap pr-4" data-address-type="Rechnungsadresse">
|
||||
<div class="mr-3">Rechnungsadresse</div>
|
||||
<div class="font-bold">
|
||||
<div class="flex flex-row flex-wrap pr-4" data-address-type="Rechnungsadresse" data-which="Rechnungsadresse">
|
||||
<div class="mr-3" data-what="title">Rechnungsadresse</div>
|
||||
<div class="font-bold" data-what="address">
|
||||
{{ payer | payerAddress }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,9 +47,9 @@
|
||||
|
||||
<ng-container *ngIf="payer$ | async; let payer">
|
||||
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between px-5">
|
||||
<div class="flex flex-row flex-wrap pr-4" data-address-type="Lieferadresse">
|
||||
<div class="mr-3">Lieferadresse</div>
|
||||
<div class="font-bold">
|
||||
<div class="flex flex-row flex-wrap pr-4" data-address-type="Lieferadresse" data-which="Lieferadresse">
|
||||
<div class="mr-3" data-what="title">Lieferadresse</div>
|
||||
<div class="font-bold" data-what="address">
|
||||
{{ shippingAddress$ | async | shippingAddress }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,17 +19,14 @@
|
||||
placeholder="Eine Anmerkung hinzufügen"
|
||||
[(ngModel)]="value"
|
||||
[rows]="rows"
|
||||
(ngModelChange)="check()"
|
||||
(blur)="save()"
|
||||
(ngModelChange)="updateValue()"
|
||||
(blur)="updateValue()"
|
||||
></textarea>
|
||||
|
||||
<div class="comment-actions py-4">
|
||||
<button type="reset" class="clear pl-4" *ngIf="!disabled && !!value" (click)="clear(); triggerResize()">
|
||||
<shared-icon icon="close" [size]="24"></shared-icon>
|
||||
</button>
|
||||
<button class="cta-save ml-4" type="submit" *ngIf="!disabled && isDirty" (click)="save()">
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export class SpecialCommentComponent implements ControlValueAccessor {
|
||||
|
||||
clear() {
|
||||
this.value = '';
|
||||
this.save();
|
||||
this.updateValue();
|
||||
}
|
||||
|
||||
check() {
|
||||
@@ -80,11 +80,12 @@ export class SpecialCommentComponent implements ControlValueAccessor {
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
save() {
|
||||
updateValue() {
|
||||
this.initialValue = this.value;
|
||||
this.onChange(this.value);
|
||||
this.check();
|
||||
}
|
||||
|
||||
setIsDirty(isDirty: boolean) {
|
||||
this.isDirty = isDirty;
|
||||
this.isDirtyChange.emit(isDirty);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ChangeDetectorRef, Directive, OnDestroy, OnInit, ViewChild, inject } from '@angular/core';
|
||||
import { AbstractControl, AsyncValidatorFn, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { AbstractControl, AsyncValidatorFn, UntypedFormControl, UntypedFormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
@@ -190,6 +190,47 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
minBirthDateValidator = (): ValidatorFn => {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
const minAge = 18; // 18 years
|
||||
|
||||
if (!control.value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const controlBirthDate = new Date(control.value);
|
||||
const minBirthDate = new Date();
|
||||
minBirthDate.setFullYear(minBirthDate.getFullYear() - minAge);
|
||||
|
||||
// Check if customer is over 18 years old
|
||||
if (this._checkIfAgeOver18(controlBirthDate, minBirthDate)) {
|
||||
return null;
|
||||
} else {
|
||||
return { minBirthDate: `Teilnahme ab ${minAge} Jahren` };
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
private _checkIfAgeOver18(inputDate: Date, minBirthDate: Date): boolean {
|
||||
// Check year
|
||||
if (inputDate.getFullYear() < minBirthDate.getFullYear()) {
|
||||
return true;
|
||||
}
|
||||
// Check Year + Month
|
||||
else if (inputDate.getFullYear() === minBirthDate.getFullYear() && inputDate.getMonth() < minBirthDate.getMonth()) {
|
||||
return true;
|
||||
}
|
||||
// Check Year + Month + Day
|
||||
else if (
|
||||
inputDate.getFullYear() === minBirthDate.getFullYear() &&
|
||||
inputDate.getMonth() === minBirthDate.getMonth() &&
|
||||
inputDate.getDate() <= minBirthDate.getDate()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
emailExistsValidator: AsyncValidatorFn = (control) => {
|
||||
return of(control.value).pipe(
|
||||
tap((_) => this.customerExists$.next(false)),
|
||||
|
||||
@@ -70,7 +70,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
|
||||
|
||||
agbValidatorFns = [Validators.requiredTrue];
|
||||
|
||||
birthDateValidatorFns = [Validators.required];
|
||||
birthDateValidatorFns = [];
|
||||
|
||||
existingCustomer$: Observable<CustomerInfoDTO | null>;
|
||||
|
||||
@@ -138,6 +138,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
|
||||
|
||||
initMarksAndValidators() {
|
||||
this.asyncLoyaltyCardValidatorFn = [this.checkLoyalityCardValidator];
|
||||
this.birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()];
|
||||
if (this._customerType === 'webshop') {
|
||||
this.emailRequiredMark = true;
|
||||
this.emailValidatorFn = [Validators.required, Validators.email, validateEmail];
|
||||
|
||||
@@ -22,7 +22,7 @@ export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer im
|
||||
|
||||
agbValidatorFns = [Validators.requiredTrue];
|
||||
|
||||
birthDateValidatorFns = [Validators.required];
|
||||
birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()];
|
||||
|
||||
nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<img
|
||||
class="thumbnail"
|
||||
loading="lazy"
|
||||
[productImageNavigation]="orderItem?.product?.ean"
|
||||
*ngIf="orderItem?.product?.ean | productImage; let productImage"
|
||||
[src]="productImage"
|
||||
[alt]="orderItem?.product?.name"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ProductImageModule } from 'apps/cdn/product-image/src/public-api';
|
||||
import { NavigateOnClickDirective, ProductImageModule } from 'apps/cdn/product-image/src/public-api';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiInputModule } from '@ui/input';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
@@ -8,7 +8,7 @@ import { GoodsInListItemComponent } from './goods-in-list-item.component';
|
||||
import { PipesModule } from 'apps/shared/components/goods-in-out/src/lib/pipes/pipes.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PipesModule, UiIconModule, ProductImageModule, FormsModule, UiInputModule],
|
||||
imports: [CommonModule, PipesModule, UiIconModule, ProductImageModule, FormsModule, UiInputModule, NavigateOnClickDirective],
|
||||
exports: [GoodsInListItemComponent],
|
||||
declarations: [GoodsInListItemComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="text-right" *ngIf="!packageDetails?.package?.features?.['annotation']; else annotationTmpl">
|
||||
<div data-which="Statusmeldung" class="text-right" *ngIf="!packageDetails?.package?.features?.['annotation']; else annotationTmpl">
|
||||
<ng-container *ngIf="(packageDetails.package.arrivalStatus | arrivalStatus) === 'Fehlt'">
|
||||
<button
|
||||
class="isa-icon-button mr-2"
|
||||
@@ -52,12 +52,13 @@
|
||||
<div
|
||||
class="isa-label text-white font-bold page-package-details__arrival-status"
|
||||
[class]="packageDetails.package.arrivalStatus | arrivalStatusColorClass"
|
||||
data-what="arrival-status"
|
||||
>
|
||||
{{ packageDetails.package.arrivalStatus | arrivalStatus }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-template #annotationTmpl>
|
||||
<div class="text-right text-[#5A728A] col-span-2">
|
||||
<div class="page-package-details__annotation text-right text-[#5A728A] col-span-2" data-what="annotation">
|
||||
{{ packageDetails?.package?.features?.['annotation'] }}
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -36,12 +36,22 @@
|
||||
|
||||
<page-pickup-shelf-details-tags class="mb-px-2" *ngIf="showTagsComponent$ | async"></page-pickup-shelf-details-tags>
|
||||
|
||||
<page-pickup-shelf-details-covers
|
||||
*ngIf="(coverOrderItems$ | async)?.length > 0"
|
||||
[coverItems]="coverOrderItems$ | async"
|
||||
[selectedOrderItem]="selectedItem$ | async"
|
||||
(coverClick)="coverClick($event)"
|
||||
></page-pickup-shelf-details-covers>
|
||||
<ng-container *ngIf="fetchingCoverItems$ | async; else coverItemsTmpl">
|
||||
<div class="bg-white grid grid-flow-col gap-5 justify-center items-center h-40">
|
||||
<shared-skeleton-loader class="h-16 w-12"></shared-skeleton-loader>
|
||||
<shared-skeleton-loader class="h-16 w-12"></shared-skeleton-loader>
|
||||
<shared-skeleton-loader class="h-16 w-12"></shared-skeleton-loader>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #coverItemsTmpl>
|
||||
<page-pickup-shelf-details-covers
|
||||
*ngIf="(coverOrderItems$ | async)?.length > 0"
|
||||
[coverItems]="coverOrderItems$ | async"
|
||||
[selectedOrderItem]="selectedItem$ | async"
|
||||
(coverClick)="coverClick($event)"
|
||||
></page-pickup-shelf-details-covers>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div class="page-pickup-shelf-in-details__action-wrapper">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy, inject, OnInit, AfterViewInit, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, inject, OnInit, AfterViewInit, ViewChild } from '@angular/core';
|
||||
import { PickupShelfDetailsBaseComponent } from '../../pickup-shelf-details-base.component';
|
||||
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
|
||||
import { PickUpShelfDetailsHeaderComponent } from '../../shared/pickup-shelf-details-header/pickup-shelf-details-header.component';
|
||||
@@ -18,6 +18,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { RunCheckTrigger } from '../../trigger';
|
||||
import { PickUpShelfDetailsItemsGroupComponent } from '../../shared/pickup-shelf-details-items-group/pickup-shelf-details-items-group.component';
|
||||
import { isEqual } from 'lodash';
|
||||
import { SkeletonLoaderComponent } from '@shared/components/loader';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pickup-shelf-in-details',
|
||||
@@ -38,9 +39,10 @@ import { isEqual } from 'lodash';
|
||||
PickupShelfAddToPreviousCompartmentCodeLabelPipe,
|
||||
UiSpinnerModule,
|
||||
OnInitDirective,
|
||||
SkeletonLoaderComponent,
|
||||
],
|
||||
})
|
||||
export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseComponent implements OnInit, AfterViewInit {
|
||||
runCheckTrigger = inject(RunCheckTrigger);
|
||||
|
||||
@ViewChild(PickUpShelfDetailsTagsComponent, { static: false })
|
||||
@@ -54,12 +56,12 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
|
||||
noOrderItemsFound$ = this.store.noOrderItemsFound$;
|
||||
|
||||
fetching$ = this.store.fetchingOrder$;
|
||||
fetchingOrder$ = this.store.fetchingOrder$;
|
||||
fetchingItems$ = this.store.fetchingOrderItems$;
|
||||
fetchingCoverItems$ = this.store.fetchingCoverOrderItems$;
|
||||
|
||||
viewFetching$ = combineLatest([this.fetching$, this.fetchingItems$, this.fetchingCoverItems$]).pipe(
|
||||
map(([fetching, fetchingItems, fetchingCoverItems]) => fetching || fetchingItems || fetchingCoverItems)
|
||||
viewFetching$ = combineLatest([this.fetchingItems$, this.orderItems$]).pipe(
|
||||
map(([fetchingItems, orderItems]) => fetchingItems && orderItems.length === 0)
|
||||
);
|
||||
|
||||
selectedCompartmentInfo = this.store.selectedCompartmentInfo;
|
||||
@@ -115,15 +117,15 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
if (!!selectedItem && this.store.selectPreviousSelectedOrderItemSubsetId !== orderItemSubsetId) {
|
||||
this.store.setPreviousSelectedOrderItemSubsetId(orderItemSubsetId); // Wichtig das die ID im Store vorhanden bleibt um z.B. für die Filter eine zurücknavigation zu ermöglichen
|
||||
this.store.selectOrderItem(selectedItem, true); // Wird automatisch unselected wenn die Details Seite verlassen wird
|
||||
this.store.fetchCoverOrderItems();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// Fix #4696 - Clear the previous selected orderItemSubsetId from store after leaving Details page
|
||||
// Es gab Fälle, in denen beim erneuten Aufruf der Details Seite, die vorherige ID noch im Store vorhanden war und deshalb der code in ngOnInit nicht ausgeführt wurde
|
||||
this.store.setPreviousSelectedOrderItemSubsetId(undefined);
|
||||
// Fix #4696 - Always Fetch Cover Order Items
|
||||
this._activatedRoute.params.pipe(distinctUntilChanged(isEqual), takeUntilDestroyed(this.destroyRef)).subscribe((_) => {
|
||||
if (!this.store.coverOrderItems || this.store.coverOrderItems.length === 0) {
|
||||
this.store.fetchCoverOrderItems();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
@@ -218,6 +220,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
}
|
||||
|
||||
updateDate({ date, type }: { date: Date; type?: 'delivery' | 'pickup' | 'preferred' }) {
|
||||
this.store.updateOrderItemSubsetLoading(true);
|
||||
switch (type) {
|
||||
case 'delivery':
|
||||
this.store.selectedOrderItems.forEach((item) =>
|
||||
|
||||
@@ -97,6 +97,10 @@ export class PickupShelfInComponent extends PickupShelfBaseComponent {
|
||||
|
||||
const order = await this.detailsStore.order$.pipe(take(1)).toPromise();
|
||||
|
||||
if (!order) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (order?.orderNumber) {
|
||||
return order?.orderNumber;
|
||||
}
|
||||
@@ -111,6 +115,12 @@ export class PickupShelfInComponent extends PickupShelfBaseComponent {
|
||||
const orderItemSubsetId = this.detailsStore.orderItemSubsetId;
|
||||
const compartmentInfo = this.detailsStore.compartmentInfo;
|
||||
|
||||
// Ticket #4692 - Wenn keine Order vorhanden ist, dann soll Breadcrumb nicht erstellt werden
|
||||
// Dies kann z.B. passieren bei Datenbankproblemen wenn das Fetchen der Order sehr lange braucht
|
||||
if (!order) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._pickupShelfInNavigationService.detailRoute({
|
||||
item: {
|
||||
orderId: order?.id,
|
||||
|
||||
@@ -46,7 +46,9 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
|
||||
|
||||
order$ = this.store.order$;
|
||||
|
||||
groupedItems$: Observable<Array<{ type: string; items: DBHOrderItemListItemDTO[] }>> = this.store.orderItems$.pipe(
|
||||
orderItems$ = this.store.orderItems$;
|
||||
|
||||
groupedItems$: Observable<Array<{ type: string; items: DBHOrderItemListItemDTO[] }>> = this.orderItems$.pipe(
|
||||
map((items) => {
|
||||
const groups: Array<{ type: string; items: DBHOrderItemListItemDTO[] }> = [];
|
||||
|
||||
@@ -66,10 +68,12 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
|
||||
})
|
||||
);
|
||||
|
||||
fetching$ = this.store.fetchingOrder$;
|
||||
fetchingOrder$ = this.store.fetchingOrder$;
|
||||
fetchingItems$ = this.store.fetchingOrderItems$;
|
||||
|
||||
viewFetching$ = combineLatest([this.fetching$, this.fetchingItems$]).pipe(map(([fetching, fetchingItems]) => fetching || fetchingItems));
|
||||
viewFetching$ = combineLatest([this.orderItems$, this.fetchingItems$]).pipe(
|
||||
map(([orderItems, fetchingItems]) => orderItems?.length === 0 && fetchingItems)
|
||||
);
|
||||
|
||||
selectedCompartmentInfo = this.store.selectedCompartmentInfo;
|
||||
|
||||
@@ -148,6 +152,7 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
|
||||
}
|
||||
|
||||
updateDate({ date, type }: { date: Date; type?: 'delivery' | 'pickup' | 'preferred' }) {
|
||||
this.store.updateOrderItemSubsetLoading(true);
|
||||
switch (type) {
|
||||
case 'delivery': // vsl. Lieferdatum
|
||||
this.store.orderItems.forEach((item) =>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { PickupShelfIOService, PickupShelfOutService } from '@domain/pickup-shel
|
||||
import { GetNameForBreadcrumbData, GetPathForBreadcrumbData, PickupShelfBaseComponent } from '../pickup-shelf-base.component';
|
||||
import { NavigationRoute, PickUpShelfOutNavigationService } from '@shared/services';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { DBHOrderItemListItemDTO, ListResponseArgsOfDBHOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { DBHOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { provideActionHandlers } from '@core/command';
|
||||
@@ -212,7 +212,7 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
|
||||
*/
|
||||
const filterQueryParams = this.listStore.filter.getQueryParams();
|
||||
|
||||
if (response.hits === 1 || this._hasSameOrderNumber(response)) {
|
||||
if (response.hits === 1) {
|
||||
const detailsPath = await this.getPathForDetail(response.result[0]).pipe(take(1)).toPromise();
|
||||
await this.router.navigate(detailsPath.path, { queryParams: { ...queryParams, ...filterQueryParams, ...detailsPath.queryParams } });
|
||||
} else if (response.hits > 1) {
|
||||
@@ -224,10 +224,13 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
|
||||
});
|
||||
}
|
||||
|
||||
// Fix Ticket #4684 Navigate on Details if items contain same OrderNumber
|
||||
private _hasSameOrderNumber(response: ListResponseArgsOfDBHOrderItemListItemDTO) {
|
||||
if (response.hits === 0) return false;
|
||||
const orderNumbers = new Set(response.result.map((item) => item.orderNumber));
|
||||
return orderNumbers.size === 1;
|
||||
}
|
||||
// Ticket 4720 WA // Trefferliste wird übersprungen - Bei mehreren Bestellposten pro Bestellung soll IMMER auf Trefferliste navigiert werden
|
||||
// Damit werden #4684 und #4688 überflüssig
|
||||
|
||||
// REMOVED: Fix Ticket #4684 Navigate on Details if items contain same OrderNumber
|
||||
// private _hasSameOrderNumber(response: ListResponseArgsOfDBHOrderItemListItemDTO) {
|
||||
// if (response.hits === 0) return false;
|
||||
// const orderNumbers = new Set(response.result.map((item) => item.orderNumber));
|
||||
// return orderNumbers.size === 1;
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<ng-container *ngIf="orderItem$ | async; let orderItem">
|
||||
<div class="grid grid-flow-row gap-px-2">
|
||||
<div class="bg-[#F5F7FA] flex flex-row justify-between items-center p-4 rounded-t">
|
||||
<div class="grid grid-flow-col gap-[0.4375rem] items-center" *ngIf="features$ | async; let features; else: featureLoading">
|
||||
<shared-icon *ngIf="features?.length > 0" [size]="24" icon="person"></shared-icon>
|
||||
<div class="grid grid-flow-col gap-2 items-center font-bold text-p2" *ngFor="let feature of features">
|
||||
{{ feature?.description }}
|
||||
</div>
|
||||
<div class="grid grid-flow-col gap-[0.4375rem] items-center" *ngIf="fetchingCustomerDone$ | async; else featureLoading">
|
||||
<ng-container *ngIf="features$ | async; let features">
|
||||
<shared-icon *ngIf="features?.length > 0" [size]="24" icon="person"></shared-icon>
|
||||
<div class="grid grid-flow-col gap-2 items-center font-bold text-p2" *ngFor="let feature of features">
|
||||
{{ feature?.description }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -96,7 +98,12 @@
|
||||
</div>
|
||||
<div class="flex flex-row page-pickup-shelf-details-header__order-source" data-detail-id="Bestellkanal">
|
||||
<div class="min-w-[9rem]">Bestellkanal</div>
|
||||
<div class="flex flex-row font-bold">{{ order?.features?.orderSource }}</div>
|
||||
<div class="flex flex-row font-bold">
|
||||
<shared-skeleton-loader class="w-32" *ngIf="fetchingOrder$ | async; else orderSourceTmpl"></shared-skeleton-loader>
|
||||
<ng-template #orderSourceTmpl>
|
||||
{{ order()?.features?.orderSource }}
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-row page-pickup-shelf-details-header__change-date justify-between"
|
||||
@@ -137,24 +144,21 @@
|
||||
data-detail-id="Benachrichtigung"
|
||||
>
|
||||
<div class="min-w-[9rem]">Benachrichtigung</div>
|
||||
<div class="flex flex-row font-bold">{{ (notificationsChannel$ | async | notificationsChannel) || '-' }}</div>
|
||||
<div class="flex flex-row font-bold">
|
||||
<shared-skeleton-loader class="w-32" *ngIf="fetchingOrder$ | async; else notificationsChannelTpl"></shared-skeleton-loader>
|
||||
<ng-template #notificationsChannelTpl>
|
||||
{{ (notificationsChannel$ | async | notificationsChannel) || '-' }}
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #featureLoading>
|
||||
<div class="fetch-wrapper">
|
||||
<div class="fetching"></div>
|
||||
<div class="fetching"></div>
|
||||
<div class="fetching"></div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #abholfrist>
|
||||
<div class="min-w-[9rem]">Abholfrist</div>
|
||||
<div *ngIf="!(changeDateLoader$ | async)" class="flex flex-row font-bold">
|
||||
<div *ngIf="!(orderItemSubsetLoading$ | async); else featureLoading" class="flex flex-row font-bold">
|
||||
<button
|
||||
[uiOverlayTrigger]="deadlineDatepicker"
|
||||
#deadlineDatepickerTrigger="uiOverlayTrigger"
|
||||
@@ -178,12 +182,11 @@
|
||||
>
|
||||
</ui-datepicker>
|
||||
</div>
|
||||
<ui-spinner *ngIf="changeDateLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #preferredPickUpDate>
|
||||
<div class="min-w-[9rem]">Zurücklegen bis</div>
|
||||
<div *ngIf="!(changePreferredDateLoader$ | async)" class="flex flex-row font-bold">
|
||||
<div *ngIf="!(orderItemSubsetLoading$ | async); else featureLoading" class="flex flex-row font-bold">
|
||||
<button
|
||||
[uiOverlayTrigger]="preferredPickUpDatePicker"
|
||||
#preferredPickUpDatePickerTrigger="uiOverlayTrigger"
|
||||
@@ -210,12 +213,11 @@
|
||||
>
|
||||
</ui-datepicker>
|
||||
</div>
|
||||
<ui-spinner *ngIf="changePreferredDateLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"> </ui-spinner>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #vslLieferdatum>
|
||||
<div class="min-w-[9rem]">vsl. Lieferdatum</div>
|
||||
<div *ngIf="!(changeDateLoader$ | async)" class="flex flex-row font-bold">
|
||||
<div *ngIf="!(orderItemSubsetLoading$ | async); else featureLoading" class="flex flex-row font-bold">
|
||||
<button
|
||||
class="cta-datepicker"
|
||||
[disabled]="changeDateDisabled$ | async"
|
||||
@@ -239,6 +241,9 @@
|
||||
>
|
||||
</ui-datepicker>
|
||||
</div>
|
||||
<ui-spinner *ngIf="changeDateLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #featureLoading>
|
||||
<shared-skeleton-loader class="w-64 h-6"></shared-skeleton-loader>
|
||||
</ng-template>
|
||||
|
||||
@@ -12,6 +12,8 @@ import { PickupShelfNotificationsChannelPipe } from '../pipes/notifications-chan
|
||||
import { PickupShelfProcessingStatusPipe } from '../pipes/processing-status.pipe';
|
||||
import { UiDatepickerModule } from '@ui/datepicker';
|
||||
import { PickUpShelfDetailsHeaderNavMenuComponent } from '../pickup-shelf-details-header-nav-menu/pickup-shelf-details-header-nav-menu.component';
|
||||
import { SkeletonLoaderComponent } from '@shared/components/loader';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pickup-shelf-details-header',
|
||||
@@ -36,6 +38,7 @@ import { PickUpShelfDetailsHeaderNavMenuComponent } from '../pickup-shelf-detail
|
||||
UiCommonModule,
|
||||
UiDatepickerModule,
|
||||
PickUpShelfDetailsHeaderNavMenuComponent,
|
||||
SkeletonLoaderComponent,
|
||||
],
|
||||
})
|
||||
export class PickUpShelfDetailsHeaderComponent {
|
||||
@@ -50,13 +53,13 @@ export class PickUpShelfDetailsHeaderComponent {
|
||||
@Output()
|
||||
updateDate = new EventEmitter<{ date: Date; type?: 'delivery' | 'pickup' | 'preferred' }>();
|
||||
|
||||
get order$(): Observable<OrderDTO> {
|
||||
return this._store.order$;
|
||||
}
|
||||
orderItemSubsetLoading$ = this._store.orderItemSubsetLoading$;
|
||||
|
||||
get order(): OrderDTO {
|
||||
return this._store.order;
|
||||
}
|
||||
fetchingOrder$ = this._store.fetchingOrder$;
|
||||
|
||||
order$ = this._store.order$;
|
||||
|
||||
order = toSignal(this.order$);
|
||||
|
||||
findLatestPreferredPickUpDate$: Observable<Date> = this.order$.pipe(
|
||||
withLatestFrom(this._store.selectedOrderItemIds$),
|
||||
@@ -86,7 +89,7 @@ export class PickUpShelfDetailsHeaderComponent {
|
||||
processId?: number;
|
||||
|
||||
get isKulturpass() {
|
||||
return this.order?.features?.orderSource === 'KulturPass';
|
||||
return this.order()?.features?.orderSource === 'KulturPass';
|
||||
}
|
||||
|
||||
minDateDatepicker = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -1);
|
||||
@@ -105,6 +108,8 @@ export class PickUpShelfDetailsHeaderComponent {
|
||||
|
||||
changeDateDisabled$ = this.changeStatusDisabled$;
|
||||
|
||||
fetchingCustomerDone$ = this._store.fetchingCustomer$.pipe(map((fetchingCustomer) => !fetchingCustomer));
|
||||
|
||||
customer$ = this._store.customer$;
|
||||
|
||||
features$ = this.customer$.pipe(
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
</div>
|
||||
<div class="page-pickup-shelf-details-item__item-container">
|
||||
<div class="page-pickup-shelf-details-item__thumbnail">
|
||||
<img [src]="orderItem.product?.ean | productImage" [alt]="orderItem.product?.name" />
|
||||
<img
|
||||
[productImageNavigation]="orderItem?.product?.ean"
|
||||
[src]="orderItem.product?.ean | productImage"
|
||||
[alt]="orderItem.product?.name"
|
||||
/>
|
||||
</div>
|
||||
<div class="page-pickup-shelf-details-item__details">
|
||||
<div class="flex flex-row justify-between items-start mb-[1.3125rem]">
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { NavigateOnClickDirective, ProductImageModule } from '@cdn/product-image';
|
||||
import { DBHOrderItemListItemDTO, OrderDTO, ReceiptDTO } from '@swagger/oms';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
@@ -57,6 +57,7 @@ export interface PickUpShelfDetailsItemComponentState {
|
||||
IconModule,
|
||||
UiQuantityDropdownModule,
|
||||
NotificationTypePipe,
|
||||
NavigateOnClickDirective,
|
||||
],
|
||||
})
|
||||
export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfDetailsItemComponentState> implements OnInit {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*ngIf="historyItem$ | async; let item"
|
||||
class="self-end"
|
||||
type="button"
|
||||
(click)="store.processId !== 7000 ? navigateToShelfOutDetailsPage(item) : navigateToShelfInDetailsPage(item)"
|
||||
(click)="listStore.processId !== 7000 ? navigateToShelfOutDetailsPage(item) : navigateToShelfInDetailsPage(item)"
|
||||
>
|
||||
<shared-icon icon="close" [size]="26"></shared-icon>
|
||||
</button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { PickupShelfIOService } from '@domain/pickup-shelf';
|
||||
@@ -9,8 +9,8 @@ import { PickUpShelfOutNavigationService, PickupShelfInNavigationService } from
|
||||
import { DBHOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map, shareReplay, switchMap, take } from 'rxjs/operators';
|
||||
import { PickupShelfStore } from '../../store';
|
||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import { PickupShelfDetailsBaseComponent } from '../../pickup-shelf-details-base.component';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pickup-shelf-history',
|
||||
@@ -21,9 +21,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
host: { class: 'page-pickup-shelf-history' },
|
||||
imports: [AsyncPipe, NgIf, SharedHistoryListModule, IconModule],
|
||||
})
|
||||
export class PickUpShelfHistoryComponent {
|
||||
store = inject(PickupShelfStore);
|
||||
|
||||
export class PickUpShelfHistoryComponent extends PickupShelfDetailsBaseComponent {
|
||||
compartmentCode$: Observable<string> = this._activatedRoute.params.pipe(
|
||||
map((params) => decodeURIComponent(params?.compartmentCode ?? '') || undefined)
|
||||
);
|
||||
@@ -62,12 +60,14 @@ export class PickUpShelfHistoryComponent {
|
||||
private _shelfInNavigation: PickupShelfInNavigationService,
|
||||
private _omsService: DomainOmsService,
|
||||
private _pickupShelfIOService: PickupShelfIOService
|
||||
) {}
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async navigateToShelfOutDetailsPage(item: DBHOrderItemListItemDTO) {
|
||||
await this._router.navigate(
|
||||
this._shelfOutNavigation.detailRoute({
|
||||
processId: this.store.processId,
|
||||
processId: this.listStore.processId,
|
||||
item: {
|
||||
compartmentCode: item.compartmentCode,
|
||||
orderId: item.orderId,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[routerLink]="itemDetailsLink"
|
||||
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
|
||||
queryParamsHandling="preserve"
|
||||
(click)="isDesktopLarge ? scrollIntoView() : ''"
|
||||
(click)="onDetailsClick()"
|
||||
>
|
||||
<div
|
||||
class="page-pickup-shelf-list-item__item-grid-container"
|
||||
@@ -15,6 +15,7 @@
|
||||
class="page-pickup-shelf-list-item__item-image w-[3.125rem] max-h-[4.9375rem]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.product?.ean | productImage; let productImage"
|
||||
[productImageNavigation]="item?.product?.ean"
|
||||
[src]="productImage"
|
||||
[alt]="item?.product?.name"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CurrencyPipe, DatePipe, NgFor, NgIf } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, Input, inject } from '@angular/core';
|
||||
import { RouterLink, RouterLinkActive } from '@angular/router';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { NavigateOnClickDirective, ProductImageModule } from '@cdn/product-image';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { IconModule } from '@shared/components/icon';
|
||||
import { DBHOrderItemListItemDTO } from '@swagger/oms';
|
||||
@@ -10,6 +10,7 @@ import { PickupShelfProcessingStatusPipe } from '../pipes/processing-status.pipe
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { PickupShelfStore } from '../../store';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { CacheService } from '@core/cache';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pickup-shelf-list-item',
|
||||
@@ -30,10 +31,13 @@ import { map } from 'rxjs/operators';
|
||||
ProductImageModule,
|
||||
UiCommonModule,
|
||||
PickupShelfProcessingStatusPipe,
|
||||
NavigateOnClickDirective,
|
||||
],
|
||||
providers: [PickupShelfProcessingStatusPipe],
|
||||
})
|
||||
export class PickUpShelfListItemComponent {
|
||||
private cache = inject(CacheService);
|
||||
|
||||
store = inject(PickupShelfStore);
|
||||
|
||||
@Input() item: DBHOrderItemListItemDTO;
|
||||
@@ -85,6 +89,45 @@ export class PickUpShelfListItemComponent {
|
||||
private _processingStatusPipe: PickupShelfProcessingStatusPipe
|
||||
) {}
|
||||
|
||||
onDetailsClick() {
|
||||
if (this.isDesktopLarge) {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
|
||||
if (!this.hasOrderItemInCache()) {
|
||||
this.addOrderItemIntoCache();
|
||||
}
|
||||
}
|
||||
|
||||
hasOrderItemInCache() {
|
||||
const items =
|
||||
this.cache.get<DBHOrderItemListItemDTO[]>({
|
||||
name: 'orderItems',
|
||||
orderId: this.item.orderId,
|
||||
compartmentCode: this.item.compartmentCode,
|
||||
compartmentInfo: this.item.compartmentInfo,
|
||||
orderItemProcessingStatus: this.item.processingStatus,
|
||||
store: 'PickupShelfDetailsStore',
|
||||
}) ?? [];
|
||||
|
||||
return items.some((i) => i.orderItemSubsetId === this.item.orderItemSubsetId);
|
||||
}
|
||||
|
||||
addOrderItemIntoCache() {
|
||||
this.cache.set(
|
||||
{
|
||||
name: 'orderItems',
|
||||
orderId: this.item.orderId,
|
||||
compartmentCode: this.item.compartmentCode,
|
||||
compartmentInfo: this.item.compartmentInfo,
|
||||
orderItemProcessingStatus: this.item.processingStatus,
|
||||
store: 'PickupShelfDetailsStore',
|
||||
},
|
||||
[this.item],
|
||||
{ persist: false, ttl: 1000 }
|
||||
);
|
||||
}
|
||||
|
||||
scrollIntoView() {
|
||||
this._elRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
@@ -89,6 +89,8 @@ export const selectSelectedOrderItemIds = (s: PickupShelfDetailsState) => s.sele
|
||||
|
||||
export const selectPreviousSelectedOrderItemSubsetId = (s: PickupShelfDetailsState) => s.previousSelectedOrderItemSubsetId;
|
||||
|
||||
export const selectOrderItemSubsetLoading = (s: PickupShelfDetailsState) => s.orderItemSubsetLoading;
|
||||
|
||||
export const selectDisableHeaderStatusDropdown = (s: PickupShelfDetailsState) => s.disableHeaderStatusDropdown;
|
||||
|
||||
export const selectedOrderItems = (s: PickupShelfDetailsState) => {
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface PickupShelfDetailsState {
|
||||
|
||||
fetchingOrderItemSubsetTasks: { [orderItemSubsetId: number]: boolean };
|
||||
orderItemSubsetTasks: { [orderItemSubsetId: number]: OrderItemSubsetTaskListItemDTO[] };
|
||||
orderItemSubsetLoading?: boolean;
|
||||
|
||||
coverOrderItems?: DBHOrderItemListItemDTO[];
|
||||
fetchingCoverOrderItems?: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { PickupShelfDetailsState } from './pickup-shelf-details.state';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import {
|
||||
DBHOrderItemListItemDTO,
|
||||
EntityDTOContainerOfOrderItemSubsetDTO,
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '@swagger/oms';
|
||||
import { PickupShelfIOService, PickupShelfService } from '@domain/pickup-shelf';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { debounceTime, delayWhen, distinctUntilChanged, filter, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { delayWhen, filter, map, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import * as Selectors from './pickup-shelf-details.selectors';
|
||||
@@ -27,7 +27,6 @@ import { CacheService } from '@core/cache';
|
||||
import { RunCheckTrigger } from '../trigger';
|
||||
import { DomainReceiptService } from '@domain/oms';
|
||||
import { PickupShelfStore } from './pickup-shelf.store';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Injectable()
|
||||
export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsState> {
|
||||
@@ -57,10 +56,20 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
return this.get(Selectors.selectFetchingOrder);
|
||||
}
|
||||
|
||||
orderItems$ = this.select(Selectors.selectOrderItems);
|
||||
// orderItems$ = this.select(Selectors.selectOrderItems);
|
||||
|
||||
// get orderItems() {
|
||||
// return this.get(Selectors.selectOrderItems);
|
||||
// }
|
||||
|
||||
orderItems$ = combineLatest([
|
||||
this.select(Selectors.selectOrderItems),
|
||||
this.select((s) => s).pipe(switchMap((s) => this._listStore.itemsForPreview$(s))),
|
||||
]).pipe(map(([orderItems, itemsForPreview]) => (orderItems?.length ? orderItems : itemsForPreview)));
|
||||
|
||||
get orderItems() {
|
||||
return this.get(Selectors.selectOrderItems);
|
||||
const orderItems = this.get(Selectors.selectOrderItems);
|
||||
return orderItems?.length ? orderItems : this.get((s) => this._listStore.itemsForPreview(s));
|
||||
}
|
||||
|
||||
fetchingOrderItems$ = this.select(Selectors.selectFetchingOrderItems);
|
||||
@@ -236,6 +245,12 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
return this.get(Selectors.selectCoverOrderItems);
|
||||
}
|
||||
|
||||
orderItemSubsetLoading$ = this.select(Selectors.selectOrderItemSubsetLoading);
|
||||
|
||||
get orderItemSubsetLoading() {
|
||||
return this.get(Selectors.selectOrderItemSubsetLoading);
|
||||
}
|
||||
|
||||
// Wird benöitgt um das Status Dropdown in der Details Header Komponente zu disablen wenn eine Action gehandled wird
|
||||
disableHeaderStatusDropdown$ = this.select(Selectors.selectDisableHeaderStatusDropdown);
|
||||
|
||||
@@ -340,6 +355,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
fetchOrder = this.effect((trigger$: Observable<{ orderId: number }>) =>
|
||||
trigger$.pipe(
|
||||
tap(({ orderId }) => this.beforeFetchOrder(orderId)),
|
||||
// delay(10000),
|
||||
switchMap(({ orderId }) =>
|
||||
this._pickupShelfService.getOrderByOrderId(orderId).pipe(tapResponse(this.fetchOrderSuccess, this.fetchOrderFailed))
|
||||
)
|
||||
@@ -347,7 +363,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
);
|
||||
|
||||
private beforeFetchOrder = (orderId) => {
|
||||
const order = this._cacheService.get<OrderDTO>({ name: 'order', orderId, store: 'PickupShelfDetailsStore' });
|
||||
const order = this._cacheService.get<OrderDTO>({ name: 'order', orderId, store: 'PickupShelfDetailsStore' }) ?? { id: orderId };
|
||||
const customer = this._cacheService.get<CustomerInfoDTO>({
|
||||
name: 'customer',
|
||||
orderId,
|
||||
@@ -480,7 +496,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
fetchCustomer = this.effect((trigger$: Observable<{ buyerNumber: string }>) =>
|
||||
trigger$.pipe(
|
||||
filter(({ buyerNumber }) => this.customer?.customerNumber !== buyerNumber),
|
||||
tap(this.beforeFetchCustomer),
|
||||
tap(() => this.beforeFetchCustomer()),
|
||||
switchMap(({ buyerNumber }) =>
|
||||
this._customerService.getCustomers(buyerNumber).pipe(tapResponse(this.fetchCustomerSuccess, this.fetchCustomerFailed))
|
||||
)
|
||||
@@ -493,7 +509,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
orderId: this.order.id,
|
||||
store: 'PickupShelfDetailsStore',
|
||||
});
|
||||
this.patchState({ fetchingCustomer: true, customer });
|
||||
this.patchState({ fetchingCustomer: !customer, customer: customer });
|
||||
};
|
||||
|
||||
fetchCustomerSuccess = (res: ListResponseArgsOfCustomerInfoDTO) => {
|
||||
@@ -502,6 +518,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
// check if response contains exactly one customer
|
||||
if (customers.length > 1) {
|
||||
this._modal.error('Fehler beim Laden des Kunden', new Error('Es wurde mehr als ein Kunde gefunden.'));
|
||||
this.patchState({ fetchingCustomer: false });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -518,6 +535,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
// also check if the order is a KulturPass order, then there may be no customer
|
||||
if (!isKulturpass && customer?.customerNumber !== this.order.buyer.buyerNumber) {
|
||||
this._modal.error('Fehler beim Laden des Kunden', new Error('Der Kunde ist nicht der Bestellung zugeordnet.'));
|
||||
this.patchState({ fetchingCustomer: false });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -567,6 +585,8 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
if (res.result.preferredPickUpDate) {
|
||||
this.patchPreferredPickUpDateOnOrderSubsetItemInState({ item, newPreferredPickUpDate: res.result.preferredPickUpDate });
|
||||
}
|
||||
|
||||
this.updateOrderItemSubsetLoading(false);
|
||||
};
|
||||
|
||||
private patchOrderItemSubsetError = (err: any) => {
|
||||
@@ -711,6 +731,10 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
this.patchState({ fetchingCoverOrderItems: true });
|
||||
};
|
||||
|
||||
updateOrderItemSubsetLoading(orderItemSubsetLoading: boolean) {
|
||||
this.patchState({ orderItemSubsetLoading });
|
||||
}
|
||||
|
||||
private fetchCoverOrderItemsDone = (res: ListResponseArgsOfDBHOrderItemListItemDTO) => {
|
||||
this.patchState({ fetchingCoverOrderItems: false, coverOrderItems: res.result });
|
||||
};
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { Filter } from '@shared/components/filter';
|
||||
import { PickupShelfState } from './pickup-shelf.state';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { PickupShelfDetailsState } from './pickup-shelf-details.state';
|
||||
import {
|
||||
selectDisplayedCompartmentCode,
|
||||
selectDisplayedCompartmentInfo,
|
||||
selectDisplayedOrderItemProcessingStatus,
|
||||
selectOrder,
|
||||
} from './pickup-shelf-details.selectors';
|
||||
|
||||
export function selectProcessId(state: PickupShelfState) {
|
||||
return state.processId;
|
||||
@@ -64,3 +71,27 @@ export function selectListHits(state: PickupShelfState) {
|
||||
export function selectSelectedListItems(state: PickupShelfState) {
|
||||
return state.selectedListItems ?? [];
|
||||
}
|
||||
|
||||
export const selectItemsForPreview = (detailsState: PickupShelfDetailsState) => (state: PickupShelfState) => {
|
||||
const orderId = selectOrder(detailsState)?.id;
|
||||
|
||||
let items = state.list.filter((item) => item.orderId === orderId);
|
||||
|
||||
const processingStatus = selectDisplayedOrderItemProcessingStatus(detailsState);
|
||||
if (processingStatus) {
|
||||
items = items?.filter((oi) => oi.processingStatus === processingStatus);
|
||||
}
|
||||
|
||||
const compartmentCode = selectDisplayedCompartmentCode(detailsState);
|
||||
if (compartmentCode) {
|
||||
items = items?.filter((oi) => oi.compartmentCode === compartmentCode);
|
||||
|
||||
const compartmentInfo = selectDisplayedCompartmentInfo(detailsState);
|
||||
|
||||
if (compartmentInfo) {
|
||||
items = items?.filter((oi) => oi.compartmentInfo === compartmentInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ import * as Selectors from './pickup-shelf.selectors';
|
||||
import { Observable, Subject, combineLatest } from 'rxjs';
|
||||
import { CacheService } from '@core/cache';
|
||||
import { Filter } from '@shared/components/filter';
|
||||
import { PickupShelfDetailsState } from './pickup-shelf-details.state';
|
||||
|
||||
@Injectable()
|
||||
export class PickupShelfStore extends ComponentStore<PickupShelfState> implements OnStoreInit {
|
||||
@@ -104,6 +105,10 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
return this.get(Selectors.selectSelectedListItems);
|
||||
}
|
||||
|
||||
itemsForPreview$ = (state: PickupShelfDetailsState) => this.select(Selectors.selectItemsForPreview(state));
|
||||
|
||||
itemsForPreview = (state: PickupShelfDetailsState) => this.get(Selectors.selectItemsForPreview(state));
|
||||
|
||||
constructor() {
|
||||
// Nicht entfernen sonst wird der Store nicht initialisiert
|
||||
super({});
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiDropdownModule } from '@ui/dropdown';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -25,6 +26,7 @@ import { UiIconModule } from '@ui/icon';
|
||||
UiTooltipModule,
|
||||
UiDropdownModule,
|
||||
UiIconModule,
|
||||
SharedProductGroupPipe,
|
||||
],
|
||||
exports: [AddProductModalComponent],
|
||||
declarations: [AddProductModalComponent],
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './product-group.pipe';
|
||||
export * from './remission-pipe.module';
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AssortmentPipe } from './assortment.pipe';
|
||||
import { ProductGroupPipe } from './product-group.pipe';
|
||||
import { ShortReceiptNumberPipe } from './short-receipt-number.pipe';
|
||||
import { SupplierPipe } from './supplier.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProductGroupPipe, AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
|
||||
exports: [ProductGroupPipe, AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
|
||||
declarations: [AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
|
||||
exports: [AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
|
||||
})
|
||||
export class RemissionPipeModule {}
|
||||
|
||||
@@ -21,15 +21,17 @@
|
||||
</div>
|
||||
<div class="product-data-grid grid gap-6 items-start">
|
||||
<div>
|
||||
<img class="max-w-full max-h-full shadow rounded" src="{{ item.ean | productImage }}" alt="item.dto.product.name" />
|
||||
<img
|
||||
[productImageNavigation]="item?.ean"
|
||||
class="max-w-full max-h-full shadow rounded"
|
||||
src="{{ item.ean | productImage }}"
|
||||
alt="item.dto.product.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row gap-1 w-48">
|
||||
<div
|
||||
class="overflow-hidden overflow-ellipsis whitespace-nowrap"
|
||||
*ngIf="!!item.format && !!item.formatDetail && item.format !== 'UNKNOWN'"
|
||||
>
|
||||
<img class="inline" src="/assets/images/Icon_{{ item.dto.product.format }}.svg" [alt]="item.formatDetail" />
|
||||
<div class="overflow-hidden overflow-ellipsis whitespace-nowrap" *ngIf="checkFormatAvailable()">
|
||||
<img *ngIf="iconExists()" class="inline" [src]="formatIconUrl" [alt]="item.formatDetail" />
|
||||
<span class="ml-1 font-bold format-detail">{{ item.formatDetail }}</span>
|
||||
</div>
|
||||
<div class="font-bold ean">
|
||||
|
||||
@@ -10,11 +10,12 @@ import {
|
||||
} from '@swagger/remi';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { mapFromReturnItemDTO, mapFromReturnSuggestionDTO } from 'apps/domain/remission/src/lib/mappings';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { Subject } from 'rxjs';
|
||||
import { first, takeUntil } from 'rxjs/operators';
|
||||
import { AddProductToShippingDocumentModalComponent } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.component';
|
||||
import { RemissionListComponentStore } from '../remission-list.component-store';
|
||||
import { RemissionListComponent } from '../remission-list.component';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Component({
|
||||
selector: 'page-remission-list-item',
|
||||
@@ -55,10 +56,15 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
|
||||
loading$ = this._listComponent.remittingItem$.asObservable();
|
||||
|
||||
get formatIconUrl() {
|
||||
return `/assets/images/Icon_${this.item.dto.product.format}.svg`;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _modal: UiModalService,
|
||||
private _remissionService: DomainRemissionService,
|
||||
private _store: RemissionListComponentStore,
|
||||
private readonly _http: HttpClient,
|
||||
@Host() private _listComponent: RemissionListComponent
|
||||
) {}
|
||||
|
||||
@@ -67,6 +73,19 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
checkFormatAvailable() {
|
||||
return !!this.item.format && !!this.item.formatDetail && this.item.format !== 'UNKNOWN';
|
||||
}
|
||||
|
||||
async iconExists(): Promise<boolean> {
|
||||
try {
|
||||
const response = await this._http.head(this.formatIconUrl, { observe: 'response' }).pipe(first()).toPromise();
|
||||
return response?.status === 200;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
addProductToShippingDocument() {
|
||||
const modal = this._modal.open({
|
||||
content: AddProductToShippingDocumentModalComponent,
|
||||
|
||||
@@ -2,12 +2,13 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { RemissionListItemComponent } from './remission-list-item.component';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { NavigateOnClickDirective, ProductImageModule } from '@cdn/product-image';
|
||||
import { RemissionPipeModule } from '../../pipes';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { AddProductToShippingDocumentModalModule } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.module';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -18,6 +19,8 @@ import { UiSpinnerModule } from '@ui/spinner';
|
||||
RemissionPipeModule,
|
||||
UiTooltipModule,
|
||||
AddProductToShippingDocumentModalModule,
|
||||
SharedProductGroupPipe,
|
||||
NavigateOnClickDirective,
|
||||
],
|
||||
exports: [RemissionListItemComponent],
|
||||
declarations: [RemissionListItemComponent],
|
||||
|
||||
@@ -5,9 +5,10 @@ import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { RemissionPipeModule } from '../../pipes';
|
||||
import { SharedShippingDocumentDetailsItemComponent } from './shipping-document-details-item/shipping-document-details-item.component';
|
||||
import { SharedShippingDocumentDetailsComponent } from './shipping-document-details.component';
|
||||
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RemissionPipeModule, ProductImageModule, UiSpinnerModule],
|
||||
imports: [CommonModule, RemissionPipeModule, ProductImageModule, UiSpinnerModule, SharedProductGroupPipe],
|
||||
exports: [SharedShippingDocumentDetailsComponent, SharedShippingDocumentDetailsItemComponent],
|
||||
declarations: [SharedShippingDocumentDetailsComponent, SharedShippingDocumentDetailsItemComponent],
|
||||
providers: [],
|
||||
|
||||
@@ -16,9 +16,29 @@
|
||||
</div>
|
||||
<div class="goods-in-out-order-group-item-details">
|
||||
<div class="goods-in-out-order-group-item-details-thumbnail">
|
||||
<img loading="lazy" *ngIf="item?.product?.ean | productImage; let productImage" [src]="productImage" [alt]="item?.product?.name" />
|
||||
<img
|
||||
[productImageNavigation]="item?.product?.ean"
|
||||
loading="lazy"
|
||||
*ngIf="item?.product?.ean | productImage; let productImage"
|
||||
[src]="productImage"
|
||||
[alt]="item?.product?.name"
|
||||
/>
|
||||
</div>
|
||||
<div class="goods-in-out-order-group-item-details-data">
|
||||
<div data-which="item-details-data" class="goods-in-out-order-group-item-details-data">
|
||||
<div
|
||||
data-what="product-group"
|
||||
*ngIf="item?.product?.productGroup"
|
||||
class="goods-in-out-order-group-item-details__product-group flex flex-row justify-end items-center text-p3"
|
||||
>
|
||||
{{ item?.product?.productGroup }}: {{ item?.product?.productGroup | productGroup }}
|
||||
</div>
|
||||
<div
|
||||
*ngIf="compartmentFromStock"
|
||||
data-what="compartment"
|
||||
class="goods-in-out-order-group-item-details__compartment flex flex-row justify-end items-center text-p3"
|
||||
>
|
||||
{{ compartmentFromStock }}
|
||||
</div>
|
||||
<div class="item-top-row">
|
||||
<div class="item-title">{{ [item.product.contributors, item.product.name] | title }}</div>
|
||||
<div class="item-processing-status">
|
||||
|
||||
@@ -78,7 +78,15 @@ export class GoodsInOutOrderGroupItemComponent extends ComponentStore<GoodsInOut
|
||||
showSupplier: boolean;
|
||||
|
||||
@Input()
|
||||
showInStock: StockInfoDTO[];
|
||||
showInStock?: StockInfoDTO[];
|
||||
|
||||
get stockInfoForItem() {
|
||||
return this.showInStock?.find((stock) => stock?.ean === this.item?.product?.ean);
|
||||
}
|
||||
|
||||
get compartmentFromStock() {
|
||||
return this.stockInfoForItem?.compartment;
|
||||
}
|
||||
|
||||
get cruda() {
|
||||
return (this.item as any)?.cruda;
|
||||
|
||||
@@ -4,12 +4,13 @@ import { CommonModule } from '@angular/common';
|
||||
import { GoodsInOutOrderGroupComponent } from './goods-in-out-order-group.component';
|
||||
import { GoodsInOutOrderGroupItemComponent } from './goods-in-out-order-group-item.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { NavigateOnClickDirective, ProductImageModule } from '@cdn/product-image';
|
||||
import { PipesModule } from '../pipes/pipes.module';
|
||||
import { UiSelectBulletModule } from '@ui/select-bullet';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -21,6 +22,8 @@ import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
FormsModule,
|
||||
UiQuantityDropdownModule,
|
||||
UiSpinnerModule,
|
||||
SharedProductGroupPipe,
|
||||
NavigateOnClickDirective,
|
||||
],
|
||||
exports: [GoodsInOutOrderGroupComponent, GoodsInOutOrderGroupItemComponent],
|
||||
declarations: [GoodsInOutOrderGroupComponent, GoodsInOutOrderGroupItemComponent],
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
:host {
|
||||
@apply inline-block min-h-[1rem] min-w-[2rem] bg-gray-500;
|
||||
@apply inline-block min-h-[1rem] min-w-[2rem] overflow-hidden rounded;
|
||||
background: rgb(238, 238, 238);
|
||||
}
|
||||
|
||||
.gr-bar {
|
||||
@apply w-full h-full;
|
||||
animation: load 1s ease-in-out infinite;
|
||||
|
||||
background: linear-gradient(75deg, rgba(238, 238, 238, 1) 0%, rgba(190, 190, 190, 1) 50%, rgba(238, 238, 238, 1) 100%);
|
||||
}
|
||||
|
||||
@keyframes load {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
30% {
|
||||
opacity: 0.5;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<div class="gr-bar"></div>
|
||||
|
||||
@@ -11,15 +11,18 @@
|
||||
{{ package?.estimatedDeliveryDate | date }}
|
||||
</div>
|
||||
<div class="w-32 page-package-list-item__items-count">{{ package?.items ?? '-' }} <span class="font-normal">Exemplare</span></div>
|
||||
<div class="text-right grow">
|
||||
<div data-which="Statusmeldung" class="text-right grow">
|
||||
<div
|
||||
*ngIf="!hasAnnotation; else annotationTmpl"
|
||||
class="rounded inline-block px-4 text-white page-package-list-item__arrival-status whitespace-nowrap"
|
||||
data-what="arrival-status"
|
||||
[class]="package?.arrivalStatus | arrivalStatusColorClass"
|
||||
>
|
||||
{{ package?.arrivalStatus | arrivalStatus }}
|
||||
</div>
|
||||
<ng-template #annotationTmpl>
|
||||
{{ annotation }}
|
||||
<div data-what="annotation" class="page-package-list-item__annotation">
|
||||
{{ annotation }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
6
apps/shared/pipes/product-group/ng-package.json
Normal file
6
apps/shared/pipes/product-group/ng-package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,9 @@ import { distinctUntilChanged, map, switchMap } from 'rxjs/operators';
|
||||
@Pipe({
|
||||
name: 'productGroup',
|
||||
pure: false,
|
||||
standalone: true,
|
||||
})
|
||||
export class ProductGroupPipe implements PipeTransform, OnDestroy {
|
||||
export class SharedProductGroupPipe implements PipeTransform, OnDestroy {
|
||||
result: string;
|
||||
|
||||
productGroup$ = new Subject<string>();
|
||||
1
apps/shared/pipes/product-group/src/public-api.ts
Normal file
1
apps/shared/pipes/product-group/src/public-api.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './lib/product-group.pipe';
|
||||
@@ -230,11 +230,36 @@ export class ShellSideMenuComponent {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// #4692 Return Fallback if Values contain undefined or null values, regardless if path is from type string or array
|
||||
if (typeof lastCrumb?.path === 'string') {
|
||||
if (lastCrumb?.path?.includes('undefined') || lastCrumb?.path?.includes('null')) {
|
||||
return fallback;
|
||||
}
|
||||
} else {
|
||||
let valuesToCheck = [];
|
||||
|
||||
for (const value of lastCrumb?.path) {
|
||||
if (value?.outlets && value?.outlets?.primary && value?.outlets?.side) {
|
||||
valuesToCheck.push(...Object.values(value?.outlets?.primary), ...Object.values(value?.outlets?.side));
|
||||
} else {
|
||||
valuesToCheck.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.checkIfArrayContainsUndefinedOrNull(valuesToCheck)) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
return { path: lastCrumb.path, queryParams: lastCrumb.params };
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
checkIfArrayContainsUndefinedOrNull(array: any[]) {
|
||||
return array?.includes(undefined) || array?.includes('undefined') || array?.includes(null) || array?.includes('null');
|
||||
}
|
||||
|
||||
getLastActivatedCustomerProcessId$() {
|
||||
return this._app.getProcesses$('customer').pipe(
|
||||
map((processes) => {
|
||||
|
||||
Reference in New Issue
Block a user