mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Compare commits
4 Commits
hotfix/453
...
performanc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc949e27b9 | ||
|
|
ed110b443c | ||
|
|
f188ece61e | ||
|
|
14cc3f4895 |
@@ -1,386 +1,3 @@
|
||||
<div class="page-article-details__wrapper">
|
||||
<div #detailsContainer class="page-article-details__container px-5" *ngIf="store.item$ | async; let item">
|
||||
<div class="page-article-details__product-details mb-3">
|
||||
<div class="page-article-details__product-bookmark justify-self-end">
|
||||
<div *ngIf="showArchivBadge$ | async" class="archiv-badge">
|
||||
<button [uiOverlayTrigger]="archivTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-[0.3125rem]">
|
||||
<img src="/assets/images/bookmark_benachrichtigung_archiv.svg" alt="Archiv Badge" />
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #archivTooltip [closeable]="true">
|
||||
<ng-container *ngIf="isAvailable$ | async; else notAvailable">
|
||||
Archivtitel. Wird nicht mehr gedruckt. Artikel ist bestellbar, weil lieferbar.
|
||||
</ng-container>
|
||||
<ng-template #notAvailable>
|
||||
Archivtitel. Wird nicht mehr gedruckt. Nicht bestellbar.
|
||||
</ng-template>
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showSubscriptionBadge$ | async">
|
||||
<button
|
||||
[uiOverlayTrigger]="subscribtionTooltip"
|
||||
class="p-0 m-0 outline-none border-none bg-transparent relative -top-[0.3125rem]"
|
||||
>
|
||||
<img src="/assets/images/bookmark_subscription.svg" alt="Fortsetzungsartikel Badge" />
|
||||
</button>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #subscribtionTooltip [closeable]="true"
|
||||
>Artikel ist ein Fortsetzungsartikel,<br />
|
||||
Artikel muss über eine Aboabteilung<br />
|
||||
bestellt werden.
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div *ngIf="showPromotionBadge$ | async" class="promotion-badge">
|
||||
<button [uiOverlayTrigger]="promotionTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-[0.3125rem]">
|
||||
<ui-icon-badge icon="gift" alt="Prämienkatalog Badge"></ui-icon-badge>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #promotionTooltip [closeable]="true">
|
||||
Dieser Artikel befindet sich im Prämienkatalog.
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-image-recessions flex flex-col items-center">
|
||||
<div class="page-article-details__product-image">
|
||||
<button class="border-none outline-none bg-transparent relative" (click)="showImages()">
|
||||
<img
|
||||
class="max-h-[19.6875rem] max-w-[12.1875rem] rounded"
|
||||
(load)="loadImage()"
|
||||
[src]="item.imageId | productImage: 195:315:true"
|
||||
alt="product image"
|
||||
/>
|
||||
<ui-icon
|
||||
class="absolute text-[#A7B9CB] inline-block bottom-[0.875rem] right-[1.125rem]"
|
||||
*ngIf="imageLoaded$ | async"
|
||||
icon="search_add"
|
||||
size="25px"
|
||||
></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
(click)="showReviews()"
|
||||
class="page-article-details__product-recessions flex flex-col mt-2 items-center bg-transparent border-none outline-none"
|
||||
*ngIf="item.reviews?.length > 0"
|
||||
>
|
||||
<ui-stars [rating]="store.reviewRating$ | async"></ui-stars>
|
||||
|
||||
<div class="text-p2 text-[#0556B4] font-bold">{{ item.reviews.length }} Rezensionen</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-contributors">
|
||||
<a
|
||||
*ngFor="let contributor of contributors$ | async; let last = last"
|
||||
class="text-[#0556B4] font-semibold no-underline text-p2"
|
||||
[routerLink]="resultsPath"
|
||||
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
|
||||
>
|
||||
{{ contributor }}{{ last ? '' : ';' }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-print justify-self-end" [class.mt-4]="isBadgeVisible$ | async">
|
||||
<button class="bg-transparent text-brand font-bold text-lg outline-none border-none p-0" (click)="print()">Drucken</button>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-title text-h3 font-bold mb-6">
|
||||
{{ item.product?.name }}
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-misc flex flex-col mb-4">
|
||||
<div
|
||||
class="page-article-details__product-format flex items-center font-bold text-p3"
|
||||
*ngIf="item?.product?.format && item?.product?.formatDetail"
|
||||
>
|
||||
<img
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
class="flex mr-2 h-[1.125rem]"
|
||||
[src]="'/assets/images/Icon_' + item.product?.format + '.svg'"
|
||||
[alt]="item.product?.formatDetail"
|
||||
/>
|
||||
{{ item.product?.formatDetail }}
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-volume" *ngIf="item?.product?.volume">Band/Reihe {{ item?.product?.volume }}</div>
|
||||
|
||||
<div class="page-article-details__product-publication">{{ publicationDate$ | async }}</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-price-info flex flex-col mb-4 flex-nowrap self-end">
|
||||
<div class="page-article-details__product-price font-bold text-xl self-end" *ngIf="price$ | async; let price">
|
||||
{{ price?.value?.value | currency: price?.value?.currency:'code' }}
|
||||
</div>
|
||||
<div *ngIf="price$ | async; let price" class="page-article-details__product-price-bound self-end">
|
||||
{{ price?.vat?.vatType | vat: (priceMaintained$ | async) }}
|
||||
</div>
|
||||
<div class="page-article-details__product-points self-end" *ngIf="store.promotionPoints$ | async; let promotionPoints">
|
||||
{{ promotionPoints }} Lesepunkte
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-origin-infos flex flex-col mb-4">
|
||||
<div class="page-article-details__product-manufacturer" data-name="product-manufacturer">{{ item.product?.manufacturer }}</div>
|
||||
|
||||
<div class="page-article-details__product-language" *ngIf="item?.product?.locale" data-name="product-language">
|
||||
{{ item?.product?.locale }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-stock flex justify-end items-center">
|
||||
<div class="h-5 w-16 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]" *ngIf="store.fetchingTakeAwayAvailability$ | async"></div>
|
||||
<button
|
||||
class="flex flex-row py-4 pl-4"
|
||||
type="button"
|
||||
[uiOverlayTrigger]="tooltip"
|
||||
[overlayTriggerDisabled]="!(stockTooltipText$ | async)"
|
||||
(click)="showTooltip()"
|
||||
*ngIf="!(store.fetchingTakeAwayAvailability$ | async)"
|
||||
>
|
||||
<ng-container *ngIf="store.takeAwayAvailability$ | async; let takeAwayAvailability">
|
||||
<ui-icon class="mr-2 mb-1" icon="home" size="15px"></ui-icon>
|
||||
<span class="font-bold text-p3">{{ takeAwayAvailability.inStock || 0 }}x</span>
|
||||
</ng-container>
|
||||
</button>
|
||||
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-12" [closeable]="true">
|
||||
{{ stockTooltipText$ | async }}
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-ean-specs flex flex-col">
|
||||
<div class="page-article-details__product-ean" data-name="product-ean">{{ item.product?.ean }}</div>
|
||||
|
||||
<div class="page-article-details__product-specs">
|
||||
<ng-container *ngIf="item?.specs?.length > 0">
|
||||
{{ (item?.specs)[0]?.value }}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-availabilities flex flex-row items-center justify-end mt-4">
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingTakeAwayAvailability$ | async; else showAvailabilityTakeAwayIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityTakeAwayIcon>
|
||||
<div
|
||||
*ngIf="store.isTakeAwayAvailabilityAvailable$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center"
|
||||
>
|
||||
<ui-icon class="mx-1" icon="shopping_bag" size="18px"> </ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingPickUpAvailability$ | async; else showAvailabilityPickUpIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityPickUpIcon>
|
||||
<div
|
||||
#uiOverlayTrigger="uiOverlayTrigger"
|
||||
[uiOverlayTrigger]="orderDeadlineTooltip"
|
||||
*ngIf="store.isPickUpAvailabilityAvailable$ | async"
|
||||
class="page-article-details__product-pick-up-availability w-[2.25rem] h-[2.25rem] cursor-pointer bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
[class.tooltip-active]="uiOverlayTrigger.opened"
|
||||
>
|
||||
<shared-icon icon="isa-box-out" [size]="24"></shared-icon>
|
||||
</div>
|
||||
|
||||
<ui-tooltip [warning]="true" yPosition="above" xPosition="after" [yOffset]="-12" #orderDeadlineTooltip [closeable]="true">
|
||||
<b>{{ (store.pickUpAvailability$ | async)?.orderDeadline | orderDeadline }}</b>
|
||||
</ui-tooltip>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingDeliveryAvailability$ | async; else showAvailabilityDeliveryIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityDeliveryIcon>
|
||||
<div
|
||||
*ngIf="showDeliveryTruck$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="-mb-[0.3125rem] -mt-[0.3125rem] mx-1" icon="truck" size="30px"></ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div
|
||||
class="h-5 w-6 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]"
|
||||
*ngIf="store.fetchingDeliveryB2BAvailability$ | async; else showAvailabilityDeliveryB2BIcon"
|
||||
></div>
|
||||
<ng-template #showAvailabilityDeliveryB2BIcon>
|
||||
<div
|
||||
*ngIf="showDeliveryB2BTruck$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="-mb-[0.625rem] -mt-[0.625rem] mx-1" icon="truck_b2b" size="30px"> </ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<span *ngIf="store.isDownload$ | async" class="flex flex-row items-center">
|
||||
<div class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3">
|
||||
<ui-icon class="mx-1" icon="download" size="18px"></ui-icon>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__shelf-ssc">
|
||||
<div class="page-article-details__ssc flex justify-end my-2 font-bold text-lg">
|
||||
<div class="w-52 h-5 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]" *ngIf="fetchingAvailabilities$ | async"></div>
|
||||
<ng-container *ngIf="!(fetchingAvailabilities$ | async)">
|
||||
<div class="text-right" *ngIf="store.sscText$ | async; let sscText">
|
||||
{{ sscText }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__shelfinfo text-right" *ngIf="store.isDownload$ | async">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
item?.stockInfos && item?.shelfInfos && (item?.stockInfos)[0]?.compartment && (item?.shelfInfos)[0]?.label;
|
||||
else stockInfos
|
||||
"
|
||||
>
|
||||
<span data-name="compartment">
|
||||
{{ (item?.stockInfos)[0]?.compartment }}
|
||||
</span>
|
||||
/
|
||||
<br />
|
||||
<span data-name="shelf-info-label">
|
||||
{{ (item?.shelfInfos)[0]?.label }}
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-template #stockInfos>
|
||||
<ng-container *ngIf="item?.stockInfos && (item?.stockInfos)[0]?.compartment; else shelfInfos">
|
||||
{{ (item?.stockInfos)[0]?.compartment }}
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
<ng-template #shelfInfos>
|
||||
<ng-container *ngIf="item?.shelfInfos && (item?.shelfInfos)[0]?.label">
|
||||
<span data-name="shelf-info-label">{{ (item?.shelfInfos)[0]?.label }}</span>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="page-article-details__shelfinfo text-right" *ngIf="!(store.isDownload$ | async)">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
item?.stockInfos && item?.shelfInfos && (item?.stockInfos)[0]?.compartment && (item?.shelfInfos)[0]?.label;
|
||||
else stockInfos2
|
||||
"
|
||||
>
|
||||
<span data-name="compartment">{{ (item?.stockInfos)[0]?.compartment }}</span>
|
||||
/
|
||||
<br />
|
||||
<span data-name="shelf-info-label">{{ (item?.shelfInfos)[0]?.label }}</span>
|
||||
</ng-container>
|
||||
<ng-template #stockInfos2>
|
||||
<ng-container *ngIf="item?.stockInfos && (item?.stockInfos)[0]?.compartment; else shelfInfos2">
|
||||
{{ (item?.stockInfos)[0]?.compartment }}
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
<ng-template #shelfInfos2>
|
||||
<ng-container *ngIf="item?.shelfInfos && (item?.shelfInfos)[0]?.label">
|
||||
{{ (item?.shelfInfos)[0]?.label }}
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-article-details__product-formats-container mt-3" *ngIf="item.family?.length > 0">
|
||||
<hr class="bg-[#E6EFF9] border-t-2" />
|
||||
<div class="pt-3">
|
||||
<div class="page-article-details__product-formats">
|
||||
<span class="mr-2">Auch verfügbar als</span>
|
||||
|
||||
<ui-slider [scrollDistance]="250">
|
||||
<a
|
||||
class="mr-4 text-[#0556B4] font-bold no-underline px-2"
|
||||
*ngFor="let format of item.family"
|
||||
[routerLink]="getDetailsPath(format.product.ean)"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<img
|
||||
class="mr-2"
|
||||
*ngIf="!!format.product?.format"
|
||||
[src]="'/assets/images/OF_Icon_' + format.product?.format + '.svg'"
|
||||
alt="format icon"
|
||||
/>
|
||||
{{ format.product?.formatDetail }}
|
||||
<span class="ml-1">{{ format.catalogAvailability?.price?.value?.value | currency: '€' }}</span>
|
||||
</span>
|
||||
</a>
|
||||
</ui-slider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="bg-[#E6EFF9] border-t-2 my-3" />
|
||||
<div #description class="page-article-details__product-description flex flex-col flex-grow mb-6" *ngIf="item.texts?.length > 0">
|
||||
<page-article-details-text class="block box-border" [text]="item.texts[0]"> </page-article-details-text>
|
||||
<div class="box-border">
|
||||
<button
|
||||
class="font-bold flex flex-row text-[#0556B4] items-center mt-2"
|
||||
*ngIf="!showMore && item?.texts?.length > 1"
|
||||
(click)="showMore = !showMore"
|
||||
>
|
||||
Mehr <ui-icon class="ml-2" size="15px" icon="arrow"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="showMore" class="page-article-details__product-description-text flex flex-col whitespace-pre-line break-words box-border">
|
||||
<span *ngFor="let text of item.texts | slice: 1">
|
||||
<h3 class="my-4 text-p2 font-bold">{{ text.label }}</h3>
|
||||
{{ text.value }}
|
||||
</span>
|
||||
|
||||
<button class="font-bold flex flex-row text-[#0556B4] items-center mt-2" (click)="showMore = !showMore">
|
||||
<ui-icon class="transform ml-0 mr-2 rotate-180" size="15px" icon="arrow"></ui-icon> Weniger
|
||||
</button>
|
||||
|
||||
<button class="page-article-details__scroll-top-cta" (click)="scrollTop(description)">
|
||||
<ui-icon class="text-[#0556B4]" icon="arrow" size="20px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="h-28 box-border"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__product-recommendations relative">
|
||||
<button
|
||||
*ngIf="store.item$ | async; let item"
|
||||
class="shadow-[#dce2e9_0px_-2px_18px_0px] mb-5 border-none outline-none flex items-center px-5 h-14 min-h-[3.5rem] bg-white w-full"
|
||||
(click)="showRecommendations = true"
|
||||
>
|
||||
<span class="uppercase text-[#0556B4] font-bold text-p3">Empfehlungen</span>
|
||||
<img class="absolute right-5 -top-[0.125rem] h-12" src="assets/images/recommendation_tag.png" alt="recommendation icon" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-article-details__actions absolute bottom-32 left-1/2 -translate-x-1/2 whitespace-nowrap"
|
||||
*ngIf="store.item$ | async; let item"
|
||||
>
|
||||
<button
|
||||
*ngIf="!(store.isDownload$ | async)"
|
||||
class="text-brand border-2 border-brand bg-white font-bold text-lg px-[1.375rem] py-4 rounded-full mr-[1.875rem]"
|
||||
(click)="showAvailabilities()"
|
||||
>
|
||||
Bestände in anderen Filialen
|
||||
</button>
|
||||
<button
|
||||
class="text-white bg-brand border-brand font-bold text-lg px-[1.375rem] py-4 rounded-full border-none no-underline"
|
||||
(click)="showPurchasingModal()"
|
||||
[disabled]="!(isAvailable$ | async) || (fetchingAvailabilities$ | async) || (item?.features && (item?.features)[0]?.key === 'PFO')"
|
||||
>
|
||||
In den Warenkorb
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="page-article-details__recommendations-overlay absolute top-0 inset-x-0" @slideYAnimation *ngIf="showRecommendations">
|
||||
<page-article-recommendations (close)="showRecommendations = false"></page-article-recommendations>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<ng-container *ngIf="!showRecommendations">
|
||||
<div #detailsContainer class="page-article-details__container px-5 relative">
|
||||
<ng-container *ngIf="store.item$ | async; let item">
|
||||
@@ -768,4 +385,4 @@
|
||||
|
||||
<div class="page-article-details__recommendations-overlay absolute rounded-t" @slideYAnimation *ngIf="showRecommendations">
|
||||
<page-article-recommendations (close)="showRecommendations = false"></page-article-recommendations>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
:host {
|
||||
@apply box-border block relative;
|
||||
}
|
||||
|
||||
.page-article-details__wrapper {
|
||||
@apply grid grid-rows-[1fr_auto] h-split-screen-tablet max-h-split-screen-tablet desktop-small:h-split-screen-desktop desktop-small:max-h-split-screen-desktop;
|
||||
@apply box-border block h-split-screen-tablet desktop-small:h-split-screen-desktop;
|
||||
}
|
||||
|
||||
.page-article-details__container {
|
||||
@apply overflow-scroll bg-white rounded shadow-card flex flex-col;
|
||||
@apply h-full w-full overflow-y-scroll overflow-hidden bg-white rounded shadow-card flex flex-col;
|
||||
}
|
||||
|
||||
.page-article-details__product-details {
|
||||
|
||||
@@ -43,6 +43,26 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
this.removeBreadcrumbs(processId);
|
||||
this.addOrUpdateBreadcrumbs(processId, queryParams);
|
||||
});
|
||||
|
||||
this._articleSearch.searchCompleted
|
||||
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this._processId$))
|
||||
.subscribe(async ([searchCompleted, processId]) => {
|
||||
if (searchCompleted.state.searchState === '') {
|
||||
const params = searchCompleted.state.filter.getQueryParams();
|
||||
if (searchCompleted.state.hits === 1) {
|
||||
const item = searchCompleted.state.items.find((f) => f);
|
||||
await this._navigationService
|
||||
.getArticleDetailsPath({
|
||||
processId,
|
||||
itemId: item.id,
|
||||
extras: { queryParams: params },
|
||||
})
|
||||
.navigate();
|
||||
} else {
|
||||
await this._navigationService.getArticleSearchResultsPath(processId, { queryParams: params }).navigate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cleanupQueryParams(params: Record<string, string> = {}) {
|
||||
|
||||
@@ -6,10 +6,12 @@ import { ArticleSearchComponent } from './article-search.component';
|
||||
import { SearchResultsModule } from './search-results/search-results.module';
|
||||
import { SearchMainModule } from './search-main/search-main.module';
|
||||
import { SearchFilterModule } from './search-filter/search-filter.module';
|
||||
import { ArticleSearchService } from './article-search.store';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, UiIconModule, SearchResultsModule, SearchMainModule, SearchFilterModule],
|
||||
exports: [ArticleSearchComponent],
|
||||
declarations: [ArticleSearchComponent],
|
||||
providers: [ArticleSearchService],
|
||||
})
|
||||
export class ArticleSearchModule {}
|
||||
|
||||
@@ -9,7 +9,6 @@ import { ArticleSearchService } from '../article-search.store';
|
||||
import { isEqual } from 'lodash';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { Filter, FilterInputGroupMainComponent } from 'apps/shared/components/filter/src/lib';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-search-main',
|
||||
@@ -53,8 +52,7 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
private route: ActivatedRoute,
|
||||
private application: ApplicationService,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private _environment: EnvironmentService,
|
||||
private _navigationService: ProductCatalogNavigationService
|
||||
private _environment: EnvironmentService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -82,14 +80,6 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
this.removeResultsAndDetailsBreadcrumbs(processId);
|
||||
|
||||
// #4519 und #4520 Durch den Performance Umbau, wird auf allen größen kleiner als der Splitscreen die Article-Search Komponente nicht geladen
|
||||
// Stattdessen werden die Komponenten search-main und search-filter geladen. Einige Funktionen von Article-Search müssen trotzdem aufgerufen werden
|
||||
if (!this._environment.matchDesktopLarge()) {
|
||||
this.resetFilter(queryParams);
|
||||
this.removeCheckoutBreadcrumb(processId);
|
||||
this.addOrUpdateBreadcrumbs(processId, queryParams);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -173,27 +163,6 @@ export class ArticleSearchMainComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
resetFilter(queryParams: Record<string, string>) {
|
||||
if (Object.keys(queryParams).length === 0) {
|
||||
this.searchService.resetFilter();
|
||||
}
|
||||
}
|
||||
|
||||
async removeCheckoutBreadcrumb(processId: number) {
|
||||
this.breadcrumb.removeBreadcrumbsByKeyAndTags(processId, ['checkout']);
|
||||
}
|
||||
|
||||
async addOrUpdateBreadcrumbs(processId: number, queryParams: Record<string, string>) {
|
||||
await this.breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name: 'Artikelsuche',
|
||||
path: this._navigationService.getArticleSearchBasePath(processId).path,
|
||||
params: queryParams,
|
||||
tags: ['catalog', 'main'],
|
||||
section: 'customer',
|
||||
});
|
||||
}
|
||||
|
||||
async removeResultsAndDetailsBreadcrumbs(processId: number) {
|
||||
const resultsCrumbs = await this.breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['catalog', 'results']).pipe(first()).toPromise();
|
||||
const detailCrumbs = await this.breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['catalog', 'details']).pipe(first()).toPromise();
|
||||
|
||||
@@ -47,69 +47,73 @@
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="primaryOutletActive$ | async; else sideOutlet">
|
||||
<cdk-virtual-scroll-viewport class="product-list" [itemSize]="103 * (scale$ | async)" (scrolledIndexChange)="scrolledIndexChange($event)">
|
||||
<a
|
||||
*cdkVirtualFor="let item of results$ | async; let i = index; trackBy: trackByItemId"
|
||||
[routerLink]="getDetailsPath(item.id)"
|
||||
routerLinkActive
|
||||
#rla="routerLinkActive"
|
||||
queryParamsHandling="preserve"
|
||||
(click)="scrollToItem(i)"
|
||||
>
|
||||
<search-result-item
|
||||
class="page-search-results__result-item page-search-results__result-item-primary"
|
||||
(selectedChange)="addToCart($event)"
|
||||
[selected]="isSelected(item)"
|
||||
[selectable]="isSelectable(item)"
|
||||
[item]="item"
|
||||
[primaryOutletActive]="true"
|
||||
[isActive]="rla.isActive"
|
||||
></search-result-item>
|
||||
</a>
|
||||
<page-search-result-item-loading [primaryOutletActive]="true" *ngIf="fetching$ | async"></page-search-result-item-loading>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
<div class="actions z-sticky h-0">
|
||||
<button
|
||||
[disabled]="loading$ | async"
|
||||
*ngIf="(selectedItemIds$ | async)?.length > 0"
|
||||
class="cta-cart cta-action-primary"
|
||||
(click)="addToCart()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
|
||||
</button>
|
||||
<div class="h-full relative">
|
||||
<cdk-virtual-scroll-viewport class="product-list h-full" itemSize="98" (scrolledIndexChange)="scrolledIndexChange($event)">
|
||||
<a
|
||||
*cdkVirtualFor="let item of results$ | async; let i = index; trackBy: trackByItemId"
|
||||
[routerLink]="getDetailsPath(item.id)"
|
||||
routerLinkActive
|
||||
#rla="routerLinkActive"
|
||||
queryParamsHandling="preserve"
|
||||
(click)="scrollToItem(i)"
|
||||
>
|
||||
<search-result-item
|
||||
class="page-search-results__result-item page-search-results__result-item-primary"
|
||||
(selectedChange)="addToCart($event)"
|
||||
[selected]="isSelected(item)"
|
||||
[selectable]="isSelectable(item)"
|
||||
[item]="item"
|
||||
[primaryOutletActive]="true"
|
||||
[isActive]="rla.isActive"
|
||||
></search-result-item>
|
||||
</a>
|
||||
<page-search-result-item-loading [primaryOutletActive]="true" *ngIf="fetching$ | async"></page-search-result-item-loading>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
<div class="actions z-sticky h-0">
|
||||
<button
|
||||
[disabled]="loading$ | async"
|
||||
*ngIf="(selectedItemIds$ | async)?.length > 0"
|
||||
class="cta-cart cta-action-primary"
|
||||
(click)="addToCart()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #sideOutlet>
|
||||
<cdk-virtual-scroll-viewport class="product-list" [itemSize]="191 * (scale$ | async)" (scrolledIndexChange)="scrolledIndexChange($event)">
|
||||
<a
|
||||
*cdkVirtualFor="let item of results$ | async; let i = index; trackBy: trackByItemId"
|
||||
[routerLink]="getDetailsPath(item.id)"
|
||||
routerLinkActive
|
||||
#rla="routerLinkActive"
|
||||
queryParamsHandling="preserve"
|
||||
(click)="scrollToItem(i)"
|
||||
>
|
||||
<search-result-item
|
||||
class="page-search-results__result-item"
|
||||
(selectedChange)="addToCart($event)"
|
||||
[selected]="isSelected(item)"
|
||||
[selectable]="isSelectable(item)"
|
||||
[item]="item"
|
||||
[primaryOutletActive]="false"
|
||||
[isActive]="rla.isActive"
|
||||
></search-result-item>
|
||||
</a>
|
||||
<page-search-result-item-loading [primaryOutletActive]="false" *ngIf="fetching$ | async"></page-search-result-item-loading>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
<div class="actions z-sticky h-0">
|
||||
<button
|
||||
[disabled]="loading$ | async"
|
||||
*ngIf="(selectedItemIds$ | async)?.length > 0"
|
||||
class="cta-cart cta-action-primary"
|
||||
(click)="addToCart()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
|
||||
</button>
|
||||
<div class="h-full relative">
|
||||
<cdk-virtual-scroll-viewport class="product-list h-full" itemSize="181" (scrolledIndexChange)="scrolledIndexChange($event)">
|
||||
<a
|
||||
*cdkVirtualFor="let item of results$ | async; let i = index; trackBy: trackByItemId"
|
||||
[routerLink]="getDetailsPath(item.id)"
|
||||
routerLinkActive
|
||||
#rla="routerLinkActive"
|
||||
queryParamsHandling="preserve"
|
||||
(click)="scrollToItem(i)"
|
||||
>
|
||||
<search-result-item
|
||||
class="page-search-results__result-item"
|
||||
(selectedChange)="addToCart($event)"
|
||||
[selected]="isSelected(item)"
|
||||
[selectable]="isSelectable(item)"
|
||||
[item]="item"
|
||||
[primaryOutletActive]="false"
|
||||
[isActive]="rla.isActive"
|
||||
></search-result-item>
|
||||
</a>
|
||||
<page-search-result-item-loading [primaryOutletActive]="false" *ngIf="fetching$ | async"></page-search-result-item-loading>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
<div class="actions z-sticky h-0">
|
||||
<button
|
||||
[disabled]="loading$ | async"
|
||||
*ngIf="(selectedItemIds$ | async)?.length > 0"
|
||||
class="cta-cart cta-action-primary"
|
||||
(click)="addToCart()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
:host {
|
||||
@apply box-border grid h-split-screen-tablet desktop-small:h-split-screen-desktop relative;
|
||||
@apply box-border grid h-split-screen-tablet desktop-small:h-split-screen-desktop;
|
||||
grid-template-rows: auto auto 1fr;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
.page-search-results__result-item {
|
||||
@apply mb-[0.625rem];
|
||||
@apply mb-px-10;
|
||||
}
|
||||
|
||||
.page-search-results__result-item-primary {
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
QueryList,
|
||||
TrackByFunction,
|
||||
AfterViewInit,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
@@ -20,7 +19,7 @@ import { ItemDTO } from '@swagger/cat';
|
||||
import { AddToShoppingCartDTO } from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { CacheService } from 'apps/core/cache/src/public-api';
|
||||
import { debounce, isEqual } from 'lodash';
|
||||
import { isEqual } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
|
||||
import { debounceTime, first, map, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from '../article-search.store';
|
||||
@@ -30,7 +29,6 @@ import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { Filter, FilterInputGroupMainComponent } from 'apps/shared/components/filter/src/lib';
|
||||
import { DomainAvailabilityService, ItemData } from '@domain/availability';
|
||||
import { asapScheduler } from 'rxjs';
|
||||
import { ShellService } from '@shared/shell';
|
||||
|
||||
@Component({
|
||||
selector: 'page-search-results',
|
||||
@@ -101,10 +99,6 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
|
||||
private readonly SCROLL_INDEX_TOKEN = 'CATALOG_RESULTS_LIST_SCROLL_INDEX';
|
||||
|
||||
shellService = inject(ShellService);
|
||||
|
||||
scale$ = this.shellService.scale$;
|
||||
|
||||
constructor(
|
||||
public searchService: ArticleSearchService,
|
||||
public route: ActivatedRoute,
|
||||
@@ -289,9 +283,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
scrolledIndexChange(index: number) {
|
||||
const completeListFetched = this.searchService.items.length === this.searchService.hits;
|
||||
|
||||
if (index && !completeListFetched && this.searchService.items.length <= this.scrollContainer?.getRenderedRange()?.end) {
|
||||
if (index && this.searchService.items.length <= this.scrollContainer?.getRenderedRange()?.end) {
|
||||
this.search({ clear: false });
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,12 @@ import { combineLatest, fromEvent, Observable, Subject } from 'rxjs';
|
||||
import { first, map, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { ActionsSubject } from '@ngrx/store';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { ArticleSearchService } from './article-search/article-search.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-catalog',
|
||||
templateUrl: 'page-catalog.component.html',
|
||||
styleUrls: ['page-catalog.component.scss'],
|
||||
providers: [provideComponentStore(ArticleSearchService)],
|
||||
providers: [],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Directive, HostListener, Input, Output, EventEmitter, OnInit } from '@angular/core';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { PurchasingOptionsModalStore } from '../../modals/purchasing-options-modal/purchasing-options-modal.store';
|
||||
|
||||
/* tslint:disable: directive-selector */
|
||||
@Directive({ selector: '[keyNavigation]' })
|
||||
export class KeyNavigationDirective implements OnInit {
|
||||
@Input() element: any;
|
||||
@Input('keyNavigation') data: BranchDTO[];
|
||||
@Output() closeDropdown = new EventEmitter<void>();
|
||||
@Output() preselectBranch = new EventEmitter<BranchDTO>();
|
||||
selectedData: BranchDTO;
|
||||
position = 0;
|
||||
posMarker = 0;
|
||||
|
||||
@HostListener('window:keyup', ['$event'])
|
||||
keyEvent(event: KeyboardEvent) {
|
||||
if (event.key === 'ArrowUp') {
|
||||
if (this.position > 0) {
|
||||
this.position--;
|
||||
}
|
||||
|
||||
if (this.position <= this.posMarker - 4) {
|
||||
this.element.scrollTop -= 44;
|
||||
}
|
||||
|
||||
this.selectedData = this.data[this.position];
|
||||
this.preselectBranch.emit(this.selectedData);
|
||||
}
|
||||
|
||||
if (event.key === 'ArrowDown') {
|
||||
if (this.position < this.data.length - 1) {
|
||||
this.position++;
|
||||
}
|
||||
|
||||
if (this.position >= 4) {
|
||||
this.posMarker = this.position;
|
||||
this.element.scrollTop += 44;
|
||||
}
|
||||
|
||||
this.selectedData = this.data[this.position];
|
||||
this.preselectBranch.emit(this.selectedData);
|
||||
}
|
||||
|
||||
if (event.key === 'Enter') {
|
||||
this.purchasingOptionsModalStore.setBranch(this.selectedData);
|
||||
this.position = 0;
|
||||
this.closeDropdown.emit();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private purchasingOptionsModalStore: PurchasingOptionsModalStore) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.selectedData = this.data[this.position];
|
||||
this.preselectBranch.emit(this.selectedData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { KeyNavigationDirective } from './key-navigation.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
exports: [KeyNavigationDirective],
|
||||
declarations: [KeyNavigationDirective],
|
||||
providers: [],
|
||||
})
|
||||
export class KeyNavigationModule {}
|
||||
@@ -5,6 +5,7 @@ import { CustomerOrderSearchComponent } from './customer-order-search.component'
|
||||
import { CustomerOrderSearchFilterComponent, OrderBranchIdInputComponent } from './customer-order-search-filter';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { CustomerOrderSearchStore } from './customer-order-search.store';
|
||||
import { IconComponent, IconModule } from '@shared/components/icon';
|
||||
import { FilterModule } from '@shared/components/filter';
|
||||
import { CustomerOrderSearchMainModule } from './search-main';
|
||||
@@ -21,6 +22,7 @@ import { CustomerOrderSearchMainModule } from './search-main';
|
||||
CustomerOrderSearchMainModule,
|
||||
],
|
||||
exports: [CustomerOrderSearchComponent],
|
||||
providers: [CustomerOrderSearchStore],
|
||||
declarations: [CustomerOrderSearchComponent, CustomerOrderSearchFilterComponent],
|
||||
})
|
||||
export class CustomerOrderSearchModule {}
|
||||
|
||||
@@ -3,21 +3,18 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { BranchSelectorComponent } from '@shared/components/branch-selector';
|
||||
import { BreadcrumbComponent } from '@shared/components/breadcrumb';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { Observable, Subject, fromEvent } from 'rxjs';
|
||||
import { first, map, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { CustomerOrderSearchStore } from './customer-order-search';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order',
|
||||
templateUrl: 'customer-order.component.html',
|
||||
styleUrls: ['customer-order.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [provideComponentStore(CustomerOrderSearchStore)],
|
||||
})
|
||||
export class CustomerOrderComponent implements OnInit {
|
||||
@ViewChild(BreadcrumbComponent, { read: ElementRef }) breadcrumbRef: ElementRef<HTMLElement>;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="customer-details-customer-main-data px-5 py-3 grid grid-flow-row gap-3">
|
||||
<div class="flex flex-row">
|
||||
<div class="data-label">Erstellungsdatum</div>
|
||||
<div class="data-value">{{ created$ | async | date: 'dd.MM.yyyy' }} | {{ created$ | async | date: 'HH:mm' }} Uhr</div>
|
||||
<div class="data-value">{{ created$ | async | date: 'dd.MM.yyyy' }} | {{ created$ | async | date: 'hh:mm' }} Uhr</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="data-label">Kundennummer</div>
|
||||
|
||||
@@ -120,7 +120,7 @@ export abstract class PickupShelfBaseComponent implements OnInit {
|
||||
|
||||
// Only Update QueryParams if the user is already on the details, edit or history page
|
||||
const view: string = this.activatedRoute.snapshot.data.view;
|
||||
if (['filter', 'details', 'edit', 'history'].includes(view)) {
|
||||
if (['details', 'edit', 'history'].includes(view)) {
|
||||
await this.router.navigate([], { queryParams: { ...queryParams, ...filterQueryParams }, skipLocationChange: true });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,6 @@ export abstract class PickupShelfDetailsBaseComponent {
|
||||
|
||||
constructor() {
|
||||
this.activatedRoute.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
|
||||
// // Fix #4508 - Always Reset Cover Items before fetching new ones inside pickup-shelf-in-details.component
|
||||
if (!!this.store.coverOrderItems?.length) {
|
||||
this.store.resetCoverItems();
|
||||
}
|
||||
this.store.fetchOrder({ orderId: Number(params.orderId) });
|
||||
this.store.fetchOrderItems({
|
||||
orderNumber: params.orderNumber ? decodeURIComponent(params.orderNumber) : undefined,
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
:host {
|
||||
@apply box-border overflow-y-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop;
|
||||
}
|
||||
|
||||
.page-pickup-shelf-in-details__container {
|
||||
@apply box-border grid overflow-y-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,67 +1,56 @@
|
||||
<div class="grid overflow-y-scroll h-full" [class.page-pickup-shelf-in-details__container]="!(viewFetching$ | async)">
|
||||
<div *ngIf="noOrderItemsFound$ | async" class="text-center text-2xl font-bold bg-white rounded px-4 py-8">
|
||||
<h4>Posten wurde nicht gefunden</h4>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="viewFetching$ | async; else showView">
|
||||
<div class="w-full flex flex-col justify-center items-center">
|
||||
<ui-spinner [show]="true"></ui-spinner>
|
||||
<div class="mt-6">Daten werden geladen ...</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #showView>
|
||||
<div class="mb-4">
|
||||
<page-pickup-shelf-details-header
|
||||
(handleAction)="handleAction({ action: $event })"
|
||||
(updateDate)="updateDate($event)"
|
||||
(editClick)="navigateToEditPage($event)"
|
||||
></page-pickup-shelf-details-header>
|
||||
<page-pickup-shelf-details-item
|
||||
*ngIf="selectedItem$ | async; let item"
|
||||
class="mb-px-2"
|
||||
[orderItem]="item"
|
||||
[selected]="true"
|
||||
(historyClick)="navigateToHistoryPage($event)"
|
||||
[order]="order$ | async"
|
||||
(specialCommentChanged)="updateSpecialComment(item, $event)"
|
||||
(sharedOnInit)="fetchNotifications(item)"
|
||||
></page-pickup-shelf-details-item>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="page-pickup-shelf-in-details__action-wrapper">
|
||||
<button
|
||||
[disabled]="actionsDisabled$ | async"
|
||||
class="cta-action shadow-action"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
*ngFor="let action of mainActions$ | async"
|
||||
(click)="handleAction({action})"
|
||||
>
|
||||
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
|
||||
</button>
|
||||
|
||||
<ng-container *ngIf="latestCompartmentInfos$ | async; let latestCompartmentInfos">
|
||||
<button
|
||||
[disabled]="addToPreviousCompartmentActionDisabled$ | async"
|
||||
*ngIf="addToPreviousCompartmentAction$ | async; let action"
|
||||
class="cta-action shadow-action"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
(click)="handleAction({action, latestCompartmentCode: latestCompartmentInfos?.latestCompartmentCode, latestCompartmentInfo: latestCompartmentInfos?.latestCompartmentInfo })"
|
||||
>
|
||||
<ui-spinner [show]="(changeActionLoader$ | async) === action.command"
|
||||
>{{ latestDisplayedCompartmentInfos$ | async | addToPreviousCompartmentCodeLabelPipe }} zubuchen</ui-spinner
|
||||
>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div *ngIf="noOrderItemsFound$ | async" class="text-center text-2xl font-bold bg-white rounded px-4 py-8">
|
||||
<h4>Posten wurde nicht gefunden</h4>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<page-pickup-shelf-details-header
|
||||
(handleAction)="handleAction({ action: $event })"
|
||||
(updateDate)="updateDate($event)"
|
||||
(editClick)="navigateToEditPage($event)"
|
||||
></page-pickup-shelf-details-header>
|
||||
<page-pickup-shelf-details-item
|
||||
*ngIf="selectedItem$ | async; let item"
|
||||
class="mb-px-2"
|
||||
[orderItem]="item"
|
||||
[selected]="true"
|
||||
(historyClick)="navigateToHistoryPage($event)"
|
||||
[order]="order$ | async"
|
||||
(specialCommentChanged)="updateSpecialComment(item, $event)"
|
||||
(sharedOnInit)="fetchNotifications(item)"
|
||||
></page-pickup-shelf-details-item>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="page-pickup-shelf-in-details__action-wrapper">
|
||||
<button
|
||||
[disabled]="actionsDisabled$ | async"
|
||||
class="cta-action shadow-action"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
*ngFor="let action of mainActions$ | async"
|
||||
(click)="handleAction({action})"
|
||||
>
|
||||
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
|
||||
</button>
|
||||
|
||||
<ng-container *ngIf="latestCompartmentInfos$ | async; let latestCompartmentInfos">
|
||||
<button
|
||||
[disabled]="addToPreviousCompartmentActionDisabled$ | async"
|
||||
*ngIf="addToPreviousCompartmentAction$ | async; let action"
|
||||
class="cta-action shadow-action"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
(click)="handleAction({action, latestCompartmentCode: latestCompartmentInfos?.latestCompartmentCode, latestCompartmentInfo: latestCompartmentInfos?.latestCompartmentInfo })"
|
||||
>
|
||||
<ui-spinner [show]="(changeActionLoader$ | async) === action.command"
|
||||
>{{ latestDisplayedCompartmentInfos$ | async | addToPreviousCompartmentCodeLabelPipe }} zubuchen</ui-spinner
|
||||
>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -52,12 +52,6 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
noOrderItemsFound$ = this.store.noOrderItemsFound$;
|
||||
|
||||
fetching$ = 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)
|
||||
);
|
||||
|
||||
selectedCompartmentInfo = this.store.selectedCompartmentInfo;
|
||||
|
||||
|
||||
@@ -34,3 +34,14 @@ page-pickup-shelf-list-item {
|
||||
.cta-action-secondary {
|
||||
@apply bg-white text-brand;
|
||||
}
|
||||
|
||||
::ng-deep page-pickup-shelf-in-list ui-scroll-container {
|
||||
height: 100% !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
::ng-deep page-pickup-shelf-in-list ui-scroll-container .scroll-container {
|
||||
height: 100% !important;
|
||||
max-height: 100% !important;
|
||||
gap: 0.625rem !important;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
die bearbeitet werden können.
|
||||
</div>
|
||||
<div
|
||||
class="page-pickup-shelf-in-list__items-list mb-[0.625rem]"
|
||||
class="page-pickup-shelf-in-list__items-list"
|
||||
*ngFor="let bueryNumberGroup of list$ | async | groupBy: byBuyerNumberFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
|
||||
@@ -80,3 +80,42 @@
|
||||
</div>
|
||||
<page-pickup-shelf-list-item-loader *ngIf="fetching$ | async"></page-pickup-shelf-list-item-loader>
|
||||
</div>
|
||||
|
||||
<!-- <div class="h-full relative overflow-hidden overflow-y-scroll" sharedScrollContainer>
|
||||
<div *ngIf="!(listEmpty$ | async); else emptyMessage" class="page-pickup-shelf-in-list__scroll-container m-0 p-0" (reachEnd)="loadMore()">
|
||||
<div
|
||||
class="page-pickup-shelf-in-list__items-list w-full"
|
||||
*ngFor="let bueryNumberGroup of list$ | async | groupBy: byBuyerNumberFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
|
||||
<div
|
||||
class="page-pickup-shelf-in-list__item-header-group w-full grid grid-flow-col gap-x-4 items-center justify-between bg-white text-xl rounded-t p-4 font-bold mb-px-2"
|
||||
>
|
||||
<h3>
|
||||
{{ firstItem?.organisation }}
|
||||
<ng-container *ngIf="!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)"> - </ng-container>
|
||||
{{ firstItem?.lastName }}
|
||||
{{ firstItem?.firstName }}
|
||||
</h3>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; trackBy: trackByGroupFn">
|
||||
<ng-container *ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; trackBy: trackByGroupFn">
|
||||
<ng-container
|
||||
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<page-pickup-shelf-list-item
|
||||
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
|
||||
class="page-pickup-shelf-in-list__result-item mb-[0.125rem]"
|
||||
[item]="item"
|
||||
[primaryOutletActive]="primaryOutletActive$ | async"
|
||||
[itemDetailsLink]="getItemDetailsLink(item)"
|
||||
></page-pickup-shelf-list-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
<page-pickup-shelf-list-item-loader *ngIf="fetching$ | async"></page-pickup-shelf-list-item-loader>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
@@ -18,7 +18,7 @@ import { PickUpShelfListItemComponent } from '../../shared/pickup-shelf-list-ite
|
||||
import { Group, GroupByPipe } from '@ui/common';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { PickupShelfInNavigationService } from '@shared/services';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { debounceTime, map } from 'rxjs/operators';
|
||||
import { DBHOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { PickupShelfDetailsStore, PickupShelfStore } from '../../store';
|
||||
@@ -121,22 +121,19 @@ export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
combineLatest([this.store.processId$, this._activatedRoute.queryParams])
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(([_, queryParams]) => {
|
||||
if (!this.store.list.length || !isEqual(queryParams, this.cleanupQueryParams(this.store.filter.getQueryParams()))) {
|
||||
this.store.setQueryParams(queryParams);
|
||||
this.store.fetchList();
|
||||
}
|
||||
this.store.processId$.pipe(takeUntilDestroyed(this.destroyRef), debounceTime(150)).subscribe((_) => {
|
||||
if (!this.store.list.length) {
|
||||
this.store.fetchList();
|
||||
}
|
||||
|
||||
const scrollPos = this._getScrollPositionFromCache();
|
||||
if (!!scrollPos && this._activatedRoute.outlet === 'primary') {
|
||||
setTimeout(() => {
|
||||
this.scrollContainer?.scrollTo(scrollPos);
|
||||
this._removeScrollPositionFromCache();
|
||||
}, 150);
|
||||
}
|
||||
});
|
||||
const scrollPos = this._getScrollPositionFromCache();
|
||||
if (!!scrollPos && this._activatedRoute.outlet === 'primary') {
|
||||
setTimeout(() => {
|
||||
this.scrollContainer?.scrollTo(scrollPos);
|
||||
this._removeScrollPositionFromCache();
|
||||
}, 150);
|
||||
}
|
||||
});
|
||||
|
||||
this._router.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
||||
if (event instanceof NavigationStart) {
|
||||
@@ -149,20 +146,6 @@ export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
|
||||
this.scrollItemIntoView();
|
||||
}
|
||||
|
||||
cleanupQueryParams(params: Record<string, string> = {}) {
|
||||
const clean = { ...params };
|
||||
|
||||
for (const key in clean) {
|
||||
if (Object.prototype.hasOwnProperty.call(clean, key)) {
|
||||
if (clean[key] == undefined) {
|
||||
delete clean[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
private _removeScrollPositionFromCache(): void {
|
||||
this._cache.delete({ processId: this.store.processId, token: this.SCROLL_POSITION_TOKEN });
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
:host {
|
||||
@apply box-border overflow-y-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop;
|
||||
}
|
||||
|
||||
.page-pickup-shelf-out-details__container {
|
||||
@apply box-border grid overflow-y-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +1,36 @@
|
||||
<div class="grid overflow-y-scroll h-full" [class.page-pickup-shelf-out-details__container]="!(viewFetching$ | async)">
|
||||
<ng-container *ngIf="viewFetching$ | async; else showView">
|
||||
<div class="w-full flex flex-col justify-center items-center">
|
||||
<ui-spinner [show]="true"></ui-spinner>
|
||||
<div class="mt-6">Daten werden geladen ...</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #showView>
|
||||
<div class="mb-4">
|
||||
<page-pickup-shelf-details-header
|
||||
[processId]="processId"
|
||||
(handleAction)="handleAction($event)"
|
||||
(updateDate)="updateDate($event)"
|
||||
(editClick)="navigateToEditPage($event)"
|
||||
></page-pickup-shelf-details-header>
|
||||
<page-pickup-shelf-details-item
|
||||
class="mb-px-2"
|
||||
*ngFor="let item of orderItems$ | async; trackBy: trackByFnDBHOrderItemListItemDTO"
|
||||
[orderItem]="item"
|
||||
[selected]="true"
|
||||
(historyClick)="navigateToHistoryPage($event)"
|
||||
[order]="order$ | async"
|
||||
(specialCommentChanged)="updateSpecialComment(item, $event)"
|
||||
(sharedOnInit)="fetchNotifications(item)"
|
||||
></page-pickup-shelf-details-item>
|
||||
<page-pickup-shelf-details-tags
|
||||
*ngIf="showTagsComponent$ | async"
|
||||
[ngModel]="selectedCompartmentInfo$ | async"
|
||||
(ngModelChange)="setSelectedCompartmentInfo($event)"
|
||||
></page-pickup-shelf-details-tags>
|
||||
</div>
|
||||
|
||||
<div class="page-pickup-shelf-out-details__action-wrapper">
|
||||
<button
|
||||
[disabled]="actionsDisabled$ | async"
|
||||
class="cta-action shadow-action"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
*ngFor="let action of mainActions$ | async"
|
||||
(click)="handleAction(action)"
|
||||
>
|
||||
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="mb-4">
|
||||
<page-pickup-shelf-details-header
|
||||
[processId]="processId"
|
||||
(handleAction)="handleAction($event)"
|
||||
(updateDate)="updateDate($event)"
|
||||
(editClick)="navigateToEditPage($event)"
|
||||
></page-pickup-shelf-details-header>
|
||||
<page-pickup-shelf-details-item
|
||||
class="mb-px-2"
|
||||
*ngFor="let item of orderItems$ | async; trackBy: trackByFnDBHOrderItemListItemDTO"
|
||||
[orderItem]="item"
|
||||
[selected]="true"
|
||||
(historyClick)="navigateToHistoryPage($event)"
|
||||
[order]="order$ | async"
|
||||
(specialCommentChanged)="updateSpecialComment(item, $event)"
|
||||
(sharedOnInit)="fetchNotifications(item)"
|
||||
></page-pickup-shelf-details-item>
|
||||
<page-pickup-shelf-details-tags
|
||||
*ngIf="showTagsComponent$ | async"
|
||||
[ngModel]="selectedCompartmentInfo$ | async"
|
||||
(ngModelChange)="setSelectedCompartmentInfo($event)"
|
||||
></page-pickup-shelf-details-tags>
|
||||
</div>
|
||||
|
||||
<div class="page-pickup-shelf-out-details__action-wrapper">
|
||||
<button
|
||||
[disabled]="actionsDisabled$ | async"
|
||||
class="cta-action shadow-action"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
*ngFor="let action of mainActions$ | async"
|
||||
(click)="handleAction(action)"
|
||||
>
|
||||
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PickUpShelfDetailsHeaderComponent } from '../../shared/pickup-shelf-det
|
||||
import { PickUpShelfDetailsItemComponent } from '../../shared/pickup-shelf-details-item/pickup-shelf-details-item.component';
|
||||
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString, OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
import { PickUpShelfOutNavigationService } from '@shared/services';
|
||||
import { BehaviorSubject, asapScheduler, combineLatest } from 'rxjs';
|
||||
import { BehaviorSubject, asapScheduler } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PickUpShelfDetailsTagsComponent } from '../../shared/pickup-shelf-details-tags/pickup-shelf-details-tags.component';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
@@ -47,9 +47,6 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
|
||||
orderItems$ = this.store.orderItems$;
|
||||
|
||||
fetching$ = this.store.fetchingOrder$;
|
||||
fetchingItems$ = this.store.fetchingOrderItems$;
|
||||
|
||||
viewFetching$ = combineLatest([this.fetching$, this.fetchingItems$]).pipe(map(([fetching, fetchingItems]) => fetching || fetchingItems));
|
||||
|
||||
selectedCompartmentInfo = this.store.selectedCompartmentInfo;
|
||||
|
||||
|
||||
@@ -34,3 +34,14 @@ page-pickup-shelf-list-item {
|
||||
.cta-action-secondary {
|
||||
@apply bg-white text-brand;
|
||||
}
|
||||
|
||||
::ng-deep page-pcikup-shelf-out-list ui-scroll-container {
|
||||
height: 100% !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
::ng-deep page-pcikup-shelf-out-list ui-scroll-container .scroll-container {
|
||||
height: 100% !important;
|
||||
max-height: 100% !important;
|
||||
gap: 0.625rem !important;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
die bearbeitet werden können.
|
||||
</div>
|
||||
<div
|
||||
class="page-pickup-shelf-out-list__items-list w-full mb-[0.625rem]"
|
||||
class="page-pickup-shelf-out-list__items-list w-full"
|
||||
*ngFor="let bueryNumberGroup of list$ | async | groupBy: byBuyerNumberFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
|
||||
@@ -94,3 +94,76 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="h-full relative overflow-hidden overflow-y-scroll">
|
||||
<ui-scroll-container
|
||||
*ngIf="!(listEmpty$ | async); else emptyMessage"
|
||||
class="page-pickup-shelf-out-list__scroll-container m-0 p-0"
|
||||
(reachEnd)="loadMore()"
|
||||
[deltaEnd]="150"
|
||||
[showScrollbar]="false"
|
||||
[containerHeight]="25"
|
||||
[showScrollArrow]="false"
|
||||
[showSpacer]="(primaryOutletActive$ | async) || (isTablet$ | async) || (isDesktopSmall$ | async)"
|
||||
>
|
||||
<ng-container *ngIf="processId$ | async; let processId">
|
||||
<div
|
||||
class="page-pickup-shelf-out-list__items-list w-full"
|
||||
*ngFor="let bueryNumberGroup of list$ | async | groupBy: byBuyerNumberFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
|
||||
<div
|
||||
class="page-pickup-shelf-out-list__item-header-group w-full grid grid-flow-col gap-x-4 items-center justify-between bg-white text-xl rounded-t p-4 font-bold mb-px-2"
|
||||
>
|
||||
<h3>
|
||||
{{ firstItem?.organisation }}
|
||||
<ng-container *ngIf="!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)"> - </ng-container>
|
||||
{{ firstItem?.lastName }}
|
||||
{{ firstItem?.firstName }}
|
||||
</h3>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; trackBy: trackByGroupFn">
|
||||
<ng-container
|
||||
*ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; trackBy: trackByGroupFn"
|
||||
>
|
||||
<page-pickup-shelf-list-item
|
||||
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
|
||||
class="page-pickup-shelf-out-list__result-item mb-[0.125rem]"
|
||||
[item]="item"
|
||||
[primaryOutletActive]="primaryOutletActive$ | async"
|
||||
[itemDetailsLink]="getItemDetailsLink(item)"
|
||||
[selectedItem]="getSelectedItem$(item) | async"
|
||||
[isItemSelectable]="getIsItemSelectable$(item) | async"
|
||||
></page-pickup-shelf-list-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
<page-pickup-shelf-list-item-loader *ngIf="fetching$ | async"></page-pickup-shelf-list-item-loader>
|
||||
</ui-scroll-container>
|
||||
<div class="actions z-sticky h-0 gap-4" *ngIf="actions$ | async; let actions">
|
||||
<button
|
||||
[disabled]="(loadingFetchedActionButton$ | async) || (fetching$ | async)"
|
||||
class="cta-action"
|
||||
*ngFor="let action of actions"
|
||||
[class.cta-action-primary]="action.selected"
|
||||
[class.cta-action-secondary]="!action.selected"
|
||||
(click)="handleAction(action)"
|
||||
>
|
||||
<ui-spinner [show]="(loadingFetchedActionButton$ | async) || (fetching$ | async)">{{ action.label }}</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #emptyMessage>
|
||||
<div class="empty-message">
|
||||
Es sind im Moment keine Bestellposten vorhanden,<br />
|
||||
die bearbeitet werden können.
|
||||
</div>
|
||||
</ng-template> -->
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'notificationType',
|
||||
standalone: true,
|
||||
})
|
||||
export class NotificationTypePipe implements PipeTransform {
|
||||
transform(notificationType: string): string {
|
||||
switch (notificationType) {
|
||||
case 'NOTIFICATION_EMAIL':
|
||||
return 'Benachrichtigung';
|
||||
case 'REMINDER_EMAIL':
|
||||
return 'Erinnerung';
|
||||
case 'ORDERCONFIRMATION_EMAIL':
|
||||
return 'Bestellbestätigung';
|
||||
case 'NOTIFICATION_SMS':
|
||||
return 'Benachrichtigung';
|
||||
default:
|
||||
return notificationType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,8 @@
|
||||
<img [uiOverlayTrigger]="emailTooltip" src="/assets/images/email_bookmark.svg" />
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #emailTooltip [closeable]="true">
|
||||
Per E-Mail benachrichtigt <br />
|
||||
<ng-container *ngFor="let notifications of emailNotificationDates$ | async">
|
||||
<ng-container *ngFor="let notificationDate of notifications.dates">
|
||||
{{ notifications.type | notificationType }} {{ notificationDate | date: 'dd.MM.yyyy | HH:mm' }} Uhr<br />
|
||||
</ng-container>
|
||||
<ng-container *ngFor="let notification of emailNotificationDates$ | async">
|
||||
{{ notification | date: 'dd.MM.yyyy | HH:mm' }} Uhr<br />
|
||||
</ng-container>
|
||||
</ui-tooltip>
|
||||
</ng-container>
|
||||
@@ -22,10 +20,8 @@
|
||||
<img [uiOverlayTrigger]="smsTooltip" src="/assets/images/sms_bookmark.svg" />
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #smsTooltip [closeable]="true">
|
||||
Per SMS benachrichtigt <br />
|
||||
<ng-container *ngFor="let notifications of smsNotificationDates$ | async">
|
||||
<ng-container *ngFor="let notificationDate of notifications.dates">
|
||||
{{ notificationDate | date: 'dd.MM.yyyy | HH:mm' }} Uhr<br />
|
||||
</ng-container>
|
||||
<ng-container *ngFor="let notification of smsNotificationDates$ | async">
|
||||
{{ notification | date: 'dd.MM.yyyy | HH:mm' }} Uhr<br />
|
||||
</ng-container>
|
||||
</ui-tooltip>
|
||||
</ng-container>
|
||||
|
||||
@@ -24,7 +24,6 @@ import { map, switchMap } from 'rxjs/operators';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { PickupShelfDetailsStore } from '../../store';
|
||||
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
|
||||
import { NotificationTypePipe } from './notification-type.pipe';
|
||||
|
||||
export interface PickUpShelfDetailsItemComponentState {
|
||||
orderItem?: DBHOrderItemListItemDTO;
|
||||
@@ -56,7 +55,6 @@ export interface PickUpShelfDetailsItemComponentState {
|
||||
PickupShelfPaymentTypePipe,
|
||||
IconModule,
|
||||
UiQuantityDropdownModule,
|
||||
NotificationTypePipe,
|
||||
],
|
||||
})
|
||||
export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfDetailsItemComponentState> implements OnInit {
|
||||
|
||||
@@ -166,33 +166,22 @@ export const selectNotifications = (orderItemSubsetId: number) => (s: PickupShel
|
||||
}, {} as Record<string, Date[]>);
|
||||
};
|
||||
|
||||
export const selectLatestNotificationDatesFor = (orderItemSubsetId: number, keys: string[]) => (s: PickupShelfDetailsState) => {
|
||||
export const selectLatestNotificationDatesFor = (orderItemSubsetId: number, key: string) => (s: PickupShelfDetailsState) => {
|
||||
const notifications = selectNotifications(orderItemSubsetId)(s);
|
||||
let dates: Array<{ type: string; dates: Date[] }> = [];
|
||||
|
||||
for (const key of keys) {
|
||||
const notification = notifications?.[key] ?? [];
|
||||
|
||||
const validDates = notification.filter((date) => {
|
||||
return (
|
||||
notifications?.[key]?.filter((date) => {
|
||||
// check if curr is an invalid date
|
||||
return !isNaN(date.getTime());
|
||||
});
|
||||
|
||||
const mappedDates = { type: key, dates: validDates };
|
||||
|
||||
if (mappedDates.dates?.length > 0) {
|
||||
dates.push(mappedDates);
|
||||
}
|
||||
}
|
||||
return dates;
|
||||
}) ?? []
|
||||
);
|
||||
};
|
||||
|
||||
export const selectLatestEmailNotificationDates = (orderItemSubsetId: number) => (s: PickupShelfDetailsState) => {
|
||||
return selectLatestNotificationDatesFor(orderItemSubsetId, ['NOTIFICATION_EMAIL', 'REMINDER_EMAIL', 'ORDERCONFIRMATION_EMAIL'])(s);
|
||||
return selectLatestNotificationDatesFor(orderItemSubsetId, 'NOTIFICATION_EMAIL')(s);
|
||||
};
|
||||
|
||||
export const selectLatestSmsNotificationDate2 = (orderItemSubsetId: number) => (s: PickupShelfDetailsState) => {
|
||||
return selectLatestNotificationDatesFor(orderItemSubsetId, ['NOTIFICATION_SMS'])(s);
|
||||
return selectLatestNotificationDatesFor(orderItemSubsetId, 'NOTIFICATION_SMS')(s);
|
||||
};
|
||||
|
||||
export const selectCanSelectAction = (s: PickupShelfDetailsState) => {
|
||||
|
||||
@@ -251,10 +251,6 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
this.patchState({ fetchPartial });
|
||||
}
|
||||
|
||||
resetCoverItems() {
|
||||
this.patchState({ coverOrderItems: [] });
|
||||
}
|
||||
|
||||
resetSelectedOrderItems() {
|
||||
this.patchState({ selectedOrderItemIds: [] });
|
||||
}
|
||||
|
||||
@@ -100,11 +100,11 @@ export class SharedNotificationChannelControlComponent extends ComponentStore<Sh
|
||||
}
|
||||
|
||||
showChannelActionNameForEmailControl() {
|
||||
return (!!this.channelActionName && this.emailControl?.dirty) || this.showSendAgainActionForEmail();
|
||||
return !!this.channelActionName && this.emailControl?.dirty;
|
||||
}
|
||||
|
||||
showChannelActionNameForMobileControl() {
|
||||
return (!!this.channelActionName && this.mobileControl?.dirty) || this.showSendAgainActionForMobile();
|
||||
return !!this.channelActionName && this.mobileControl?.dirty;
|
||||
}
|
||||
|
||||
clear(control: FormControl) {
|
||||
@@ -142,7 +142,7 @@ export class SharedNotificationChannelControlComponent extends ComponentStore<Sh
|
||||
}
|
||||
|
||||
setNotificationChannels(notificationChannels: NotificationChannel[]) {
|
||||
const notificationChannel = this.getNotificationChannel(notificationChannels);
|
||||
const notificationChannel = notificationChannels.reduce((val, current) => val | current, 0) as NotificationChannel;
|
||||
this.notificationChannelControl.setValue(notificationChannel);
|
||||
this.notificationChannelControl.markAsDirty();
|
||||
if (this.communicationDetails) {
|
||||
@@ -150,24 +150,6 @@ export class SharedNotificationChannelControlComponent extends ComponentStore<Sh
|
||||
}
|
||||
}
|
||||
|
||||
getNotificationChannel(notificationChannels?: NotificationChannel[]) {
|
||||
let nfc = notificationChannels ?? this.notificationChannels;
|
||||
return nfc.reduce((val, current) => val | current, 0) as NotificationChannel;
|
||||
}
|
||||
|
||||
// Ticket #4526 RD // Bearbeiten - erneut senden Button fehlt
|
||||
// Auf den Pickup Shelf Edit Seiten soll der Erneut senden button immer ersichtlich sein
|
||||
showSendAgainActionForEmail() {
|
||||
return this.channelActionName === 'Erneut senden' && (this.getNotificationChannel() as Number) !== 3;
|
||||
}
|
||||
|
||||
// Ticket #4526 RD // Bearbeiten - erneut senden Button fehlt
|
||||
// Auf den Pickup Shelf Edit Seiten soll der Erneut senden button immer ersichtlich sein
|
||||
// Wenn die Felder Email und SMS angehakt wurden, soll der Button nur einmal angezeigt werden
|
||||
showSendAgainActionForMobile() {
|
||||
return this.channelActionName === 'Erneut senden' && (this.getNotificationChannel() === 2 || this.getNotificationChannel() !== 1);
|
||||
}
|
||||
|
||||
toggle(value?: boolean) {
|
||||
this.patchState({ open: value ?? !this.get((s) => s.open) });
|
||||
}
|
||||
|
||||
@@ -23,16 +23,7 @@ export function getPurchaseOption(state: PurchaseOptionsState): PurchaseOption {
|
||||
return options[0];
|
||||
}
|
||||
|
||||
if (state.purchaseOption) {
|
||||
return state.purchaseOption;
|
||||
}
|
||||
|
||||
// #4380 Abholung als Standard wenn möglich und keine Auswahl getroffen wurde
|
||||
if (options.includes('pickup')) {
|
||||
return 'pickup';
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return state.purchaseOption;
|
||||
}
|
||||
|
||||
export function getSelectedItemIds(state: PurchaseOptionsState): number[] {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -15,32 +14,6 @@ export class ShellService {
|
||||
return this._fontSize$.value;
|
||||
}
|
||||
|
||||
get scale() {
|
||||
if (this._fontSize$.value === 'small') {
|
||||
return 13 / 16;
|
||||
} else if (this._fontSize$.value === 'normal') {
|
||||
return 1;
|
||||
} else if (this._fontSize$.value === 'large') {
|
||||
return 19 / 16;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
scale$ = this._fontSize$.pipe(
|
||||
map((size) => {
|
||||
if (size === 'small') {
|
||||
return 13 / 16;
|
||||
} else if (size === 'normal') {
|
||||
return 1;
|
||||
} else if (size === 'large') {
|
||||
return 19 / 16;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
private _sideMenuOpen$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
sideMenuOpen$ = this._sideMenuOpen$.asObservable();
|
||||
|
||||
@@ -107,14 +107,10 @@ export class ShellSideMenuComponent {
|
||||
})
|
||||
);
|
||||
|
||||
taskCalenderNavigation$ = this.getLastNavigationByProcessId(
|
||||
this._config.get('process.ids.taskCalendar'),
|
||||
{
|
||||
path: ['/filiale', 'task-calendar'],
|
||||
queryParams: {},
|
||||
},
|
||||
'/filiale/task-calendar'
|
||||
);
|
||||
taskCalenderNavigation$ = this.getLastNavigationByProcessId(this._config.get('process.ids.taskCalendar'), {
|
||||
path: ['/filiale', 'task-calendar'],
|
||||
queryParams: {},
|
||||
});
|
||||
|
||||
assortmentNavigation$ = this.getLastNavigationByProcessId(this._config.get('process.ids.assortment'), {
|
||||
path: ['/filiale', 'assortment'],
|
||||
@@ -123,8 +119,7 @@ export class ShellSideMenuComponent {
|
||||
|
||||
pickUpShelfInRoutePath$ = this.getLastNavigationByProcessId(
|
||||
this._config.get('process.ids.pickupShelf'),
|
||||
this._pickUpShelfInNavigation.defaultRoute(),
|
||||
'/filiale/pickup-shelf'
|
||||
this._pickUpShelfInNavigation.defaultRoute()
|
||||
);
|
||||
|
||||
// #4478 - RD // Abholfach - Routing löst Suche aus
|
||||
@@ -193,24 +188,10 @@ export class ShellSideMenuComponent {
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
|
||||
getLastNavigationByProcessId(id: number, fallback?: { path: string[]; queryParams: any }, pathContainsString?: string) {
|
||||
getLastNavigationByProcessId(id: number, fallback?: { path: string[]; queryParams: any }) {
|
||||
return this._breadcrumbService.getBreadcrumbByKey$(id)?.pipe(
|
||||
map((breadcrumbs) => {
|
||||
const lastCrumb = breadcrumbs
|
||||
.filter((breadcrumb) => {
|
||||
/**
|
||||
* #4532 - Der optionale Filter wurde hinzugefügt Breadcrumbs mit fehlerhaften Pfad auszuschließen.
|
||||
* Dieser Filter kann entfernt werden, sobald die Breadcrumbs korrekt gesetzt werden. Jedoch konnte man bisher nicht feststellen,
|
||||
* woher die fehlerhaften Breadcrumbs kommen.
|
||||
*/
|
||||
if (!pathContainsString) {
|
||||
// Wenn kein Filter gesetzt ist, dann wird der letzte Breadcrumb zurückgegeben
|
||||
return true;
|
||||
}
|
||||
|
||||
const pathStr = Array.isArray(breadcrumb.path) ? breadcrumb.path.join('/') : breadcrumb.path;
|
||||
return pathStr.includes(pathContainsString);
|
||||
})
|
||||
.filter((breadcrumb) => !breadcrumb?.params?.hasOwnProperty('view'))
|
||||
.filter((breadcrumb) => !breadcrumb?.tags?.includes('reservation'))
|
||||
.filter((breadcrumb) => !breadcrumb?.tags?.includes('cleanup'))
|
||||
|
||||
14
package.json
14
package.json
@@ -5,10 +5,10 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve isa-app --ssl",
|
||||
"test": "npm-run-all --serial \"test:* -- --watch=false --browsers=ChromeHeadlessNoSandbox --code-coverage\" --continue-on-error --print-label",
|
||||
"*test:isa-app": "ng test isa-app",
|
||||
"test:isa-app": "ng test isa-app",
|
||||
"test:adapter-scan": "ng test @adapter/scan",
|
||||
"test:cdn-product-image": "ng test @cdn/product-image",
|
||||
"*test:core": "ng test core",
|
||||
"test:core": "ng test core",
|
||||
"*test:domain-availability": "ng test @domain/availability",
|
||||
"*test:domain-cart": "ng test @domain/cart",
|
||||
"*test:domain-catalog": "ng test @domain/catalog",
|
||||
@@ -19,22 +19,22 @@
|
||||
"*test:domain-oms": "ng test @domain/oms",
|
||||
"*test:domain-package-inspection": "ng test @domain/package-inspection",
|
||||
"*test:domain-printer": "ng test @domain/printer",
|
||||
"*test:domain-remission": "ng test @domain/remission",
|
||||
"test:domain-remission": "ng test @domain/remission",
|
||||
"*test:domain-task-calendar": "ng test @domain/task-calendar",
|
||||
"test:external": "ng test external",
|
||||
"*test:hub-notifications": "ng test @hub/notifications",
|
||||
"*test:isa-remission": "ng test @isa/remission",
|
||||
"*test:modal-availabilities": "ng test @modal/availabilities",
|
||||
"*test:modal-history": "ng test @modal/history",
|
||||
"test:modal-history": "ng test @modal/history",
|
||||
"*test:modal-images": "ng test @modal/images",
|
||||
"test:modal-notifications": "ng test @modal/notifications",
|
||||
"*test:modal-printer": "ng test @modal/printer",
|
||||
"*test:modal-reorder": "ng test @modal/reorder",
|
||||
"*test:modal-reviews": "ng test @modal/reviews",
|
||||
"*test:page": "ng test page",
|
||||
"*test:shared": "ng test shared",
|
||||
"test:page": "ng test page",
|
||||
"test:shared": "ng test shared",
|
||||
"*test:shell-breadcrumb": "ng test @shell/breadcrumb",
|
||||
"*test:store-search-component-store": "ng test @store/search-component-store",
|
||||
"test:store-search-component-store": "ng test @store/search-component-store",
|
||||
"*test:ui": "ng test ui",
|
||||
"*test:utils": "ng test utils",
|
||||
"*test:native-container": "ng test native-container",
|
||||
|
||||
Reference in New Issue
Block a user