mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1295: Merge Develop into Release2.0
Related work items: #905, #3040, #3175, #3179, #3189, #3212
This commit is contained in:
@@ -140,17 +140,21 @@ export class DomainRemissionService {
|
||||
)
|
||||
);
|
||||
} else if (arg.source === 'Abteilungsremission') {
|
||||
result$ = this.getCurrentStock().pipe(
|
||||
switchMap((stock) =>
|
||||
this.getItemsForAbteilungsremission({
|
||||
queryToken: {
|
||||
stockId: stock.id,
|
||||
supplierId: arg.supplierId,
|
||||
...arg.queryToken,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
if (!arg.queryToken.filter.abteilungen) {
|
||||
result$ = of({ hits: 0, result: [] });
|
||||
} else {
|
||||
result$ = this.getCurrentStock().pipe(
|
||||
switchMap((stock) =>
|
||||
this.getItemsForAbteilungsremission({
|
||||
queryToken: {
|
||||
stockId: stock.id,
|
||||
supplierId: arg.supplierId,
|
||||
...arg.queryToken,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this._logger.error('Unbekannte Quelle', arg.source);
|
||||
return throwError(new Error(`Unknown source: ${arg.source}`));
|
||||
@@ -226,18 +230,14 @@ export class DomainRemissionService {
|
||||
|
||||
let { remainingQuantity, remissionQuantity } = item;
|
||||
|
||||
if (!remissionQuantity) {
|
||||
remissionQuantity = inStock - (remainingQuantity || 0);
|
||||
if (remissionQuantity < 0) {
|
||||
remissionQuantity = 0;
|
||||
}
|
||||
remissionQuantity = inStock - (remainingQuantity || 0);
|
||||
if (remissionQuantity < 0) {
|
||||
remissionQuantity = 0;
|
||||
}
|
||||
|
||||
if (!remainingQuantity) {
|
||||
remainingQuantity = inStock - (remissionQuantity || 0);
|
||||
if (remainingQuantity < 0) {
|
||||
remainingQuantity = 0;
|
||||
}
|
||||
remainingQuantity = inStock - (remissionQuantity || 0);
|
||||
if (remainingQuantity < 0) {
|
||||
remainingQuantity = 0;
|
||||
}
|
||||
|
||||
return { ...item, remainingQuantity, remissionQuantity, inStock };
|
||||
|
||||
@@ -8,6 +8,7 @@ import { NotificationsHub } from '@hub/notifications';
|
||||
import packageInfo from 'package';
|
||||
import { interval, Observable, Subscription } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -36,7 +37,8 @@ export class AppComponent implements OnInit {
|
||||
@Inject(DOCUMENT) private readonly _document: Document,
|
||||
private readonly _renderer: Renderer2,
|
||||
private readonly _swUpdate: SwUpdate,
|
||||
private readonly _notifications: NotificationsHub
|
||||
private readonly _notifications: NotificationsHub,
|
||||
private readonly _platform: Platform
|
||||
) {
|
||||
this.updateClient();
|
||||
}
|
||||
@@ -44,6 +46,7 @@ export class AppComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.setTitle();
|
||||
this.logVersion();
|
||||
this.determinePlatform();
|
||||
|
||||
this._appService.getSection$().subscribe(this.sectionChangeHandler.bind(this));
|
||||
}
|
||||
@@ -56,6 +59,18 @@ export class AppComponent implements OnInit {
|
||||
console.log(`%c${this._config.get('title')}\r\nVersion: ${packageInfo.version}`, 'font-weight: bold; font-size: 20px;');
|
||||
}
|
||||
|
||||
determinePlatform() {
|
||||
if (this._platform.IOS && !this._platform.SAFARI) {
|
||||
this._renderer.addClass(this._document.body, 'tablet');
|
||||
this._renderer.addClass(this._document.body, 'tablet-native');
|
||||
} else if (this._platform.IOS && this._platform.SAFARI) {
|
||||
this._renderer.addClass(this._document.body, 'tablet');
|
||||
this._renderer.addClass(this._document.body, 'tablet-browser');
|
||||
} else if (this._platform.isBrowser) {
|
||||
this._renderer.addClass(this._document.body, 'desktop');
|
||||
}
|
||||
}
|
||||
|
||||
sectionChangeHandler(section: string) {
|
||||
if (section === 'customer') {
|
||||
this._renderer.removeClass(this._document.body, 'branch');
|
||||
|
||||
@@ -2,6 +2,7 @@ import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { APP_INITIALIZER, ErrorHandler, Injector, LOCALE_ID, NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { PlatformModule } from '@angular/cdk/platform';
|
||||
|
||||
import { Config, ConfigModule, JsonConfigLoader } from '@core/config';
|
||||
import { AuthModule, AuthService } from '@core/auth';
|
||||
@@ -81,6 +82,7 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
registrationStrategy: 'registerWhenStable:30000',
|
||||
}),
|
||||
ScanAdapterModule.forRoot(!environment.production),
|
||||
PlatformModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
body.branch {
|
||||
--bg-color: #edeff0;
|
||||
|
||||
// @isa-app/scrollbar
|
||||
--scrollbar-color: #596470;
|
||||
|
||||
// @shell/header
|
||||
--shell-header-button-color: #89949e;
|
||||
--shell-header-button-color-active: #586470;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
body.customer {
|
||||
--bg-color: #e6eff9;
|
||||
|
||||
// @isa-app/scrollbar
|
||||
--scrollbar-color: #1f466c;
|
||||
|
||||
// @shell/header
|
||||
--shell-header-button-color: #9db2c6;
|
||||
--shell-header-button-color-active: #557596;
|
||||
|
||||
@@ -21,3 +21,23 @@ body {
|
||||
width: 0; // remove scrollbar space
|
||||
background: transparent; // optional: just make scrollbar invisible */
|
||||
}
|
||||
|
||||
.desktop .scroll-bar::-webkit-scrollbar,
|
||||
.desktop pdf-viewer ::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.desktop .scroll-bar::-webkit-scrollbar-thumb,
|
||||
.desktop pdf-viewer ::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 0 0 6px rgb(0 0 0 / 10%);
|
||||
background-color: var(--scrollbar-color);
|
||||
}
|
||||
|
||||
.desktop .scroll-bar::-webkit-scrollbar-track,
|
||||
.desktop pdf-viewer ::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 4px rgb(0 0 0 / 10%);
|
||||
border-radius: 10px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport
|
||||
#scrollContainer
|
||||
class="product-list scroll-bar"
|
||||
class="product-list scroll-bar scroll-bar-margin"
|
||||
[itemSize]="187"
|
||||
minBufferPx="1200"
|
||||
maxBufferPx="1200"
|
||||
|
||||
@@ -44,3 +44,9 @@
|
||||
@apply bg-brand text-white;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-search-results {
|
||||
.scroll-bar-margin::-webkit-scrollbar-track {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import { AddToShoppingCartDTO } from '@swagger/checkout';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { UiErrorModalComponent, UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { CacheService } from 'apps/core/cache/src/public-api';
|
||||
import { isEqual } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
|
||||
|
||||
@@ -1,132 +1,145 @@
|
||||
<div class="tags">
|
||||
<img
|
||||
*ngIf="hasPrebooked"
|
||||
[uiOverlayTrigger]="prebookedTooltip"
|
||||
class="tag preorder"
|
||||
src="/assets/images/tag_icon_preorder.svg"
|
||||
alt="Vorbesteller"
|
||||
/>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #prebookedTooltip [closeable]="true">
|
||||
Artikel wird für Sie vorgemerkt.
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="picture">
|
||||
<img src="{{ imageUrl | async }}" alt="book" class="thumbnail" />
|
||||
<div *ngFor="let subsetItem of subsetItems; index as i">
|
||||
<div class="tags">
|
||||
<img
|
||||
*ngIf="subsetItem.isPrebooked"
|
||||
[uiOverlayTrigger]="prebookedTooltip"
|
||||
class="tag preorder"
|
||||
src="/assets/images/tag_icon_preorder.svg"
|
||||
alt="Vorbesteller"
|
||||
/>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #prebookedTooltip [closeable]="true">
|
||||
Artikel wird für Sie vorgemerkt.
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="row title">
|
||||
<span class="name">
|
||||
{{ orderItem.product.contributors }}
|
||||
<span *ngIf="orderItem.product.contributors && orderItem.product.name">-</span>
|
||||
{{ orderItem.product.name }}</span
|
||||
>
|
||||
<div class="row">
|
||||
<div class="picture">
|
||||
<img src="{{ imageUrl | async }}" alt="book" class="thumbnail" />
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Status</span>
|
||||
<span>{{ subsetItem.processingStatus | orderStatus }} </span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Menge</span>
|
||||
<span>{{ orderItem.quantity?.quantity }}x</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Preis</span>
|
||||
<span>{{ orderItem.grossPrice?.value?.value | currency: ' ' }} {{ orderItem.grossPrice?.value?.currency }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row" *ngIf="subsetItem.estimatedShippingDate">
|
||||
<span
|
||||
class="label"
|
||||
*ngIf="
|
||||
orderItem.features.orderType === 'Versand' ||
|
||||
orderItem.features.orderType === 'B2B-Versand' ||
|
||||
orderItem.features.orderType === 'DIG-Versand'
|
||||
"
|
||||
>Lieferung ab</span
|
||||
>
|
||||
<span class="label" *ngIf="orderItem.features.orderType === 'Abholung' || orderItem.features.orderType === 'Rücklage'"
|
||||
>Abholung ab</span
|
||||
>
|
||||
<span>{{ subsetItem.estimatedShippingDate | date: 'dd.MM.yyyy' }}</span>
|
||||
</div>
|
||||
|
||||
<span *ngIf="!expand" class="expand">
|
||||
<button class="arrow-button" (click)="expand = true">
|
||||
Mehr
|
||||
<ui-icon icon="arrow" size="16px"></ui-icon>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="expand">
|
||||
<div class="row">
|
||||
<span class="label">Abholfachnummer</span>
|
||||
<span>{{ subsetItem.compartmentCode || '-' }} </span>
|
||||
<div class="details">
|
||||
<div class="row title">
|
||||
<span class="name">
|
||||
{{ orderItem.product.contributors }}
|
||||
<span *ngIf="orderItem.product.contributors && orderItem.product.name">-</span>
|
||||
{{ orderItem.product.name }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">ISBN</span>
|
||||
<span>{{ orderItem.product.ean }}</span>
|
||||
<span class="label">Status</span>
|
||||
<span>{{ subsetItem.processingStatus | orderStatus }} </span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Lieferant</span>
|
||||
<span>{{ subsetItem.supplier?.data?.name || '-' }} </span>
|
||||
<span class="label">Menge</span>
|
||||
<span>{{ subsetItem.quantity }}x</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">MwSt</span>
|
||||
<span>{{ orderItem.grossPrice?.vat?.inPercent }}%</span>
|
||||
<span class="label">Preis</span>
|
||||
<span>{{ orderItem.grossPrice?.value?.value | currency: ' ' }} {{ orderItem.grossPrice?.value?.currency }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Zahlungsart</span>
|
||||
<span>{{ order.paymentType | paymentType }}</span>
|
||||
<div class="row" *ngIf="subsetItem.estimatedShippingDate">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
orderItem.features.orderType === 'Versand' ||
|
||||
orderItem.features.orderType === 'B2B-Versand' ||
|
||||
orderItem.features.orderType === 'DIG-Versand'
|
||||
"
|
||||
>
|
||||
<span class="label">Lieferung ab</span><span>{{ subsetItem.estimatedShippingDate | date: 'dd.MM.yyyy' }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="orderItem.features.orderType === 'Abholung' || orderItem.features.orderType === 'Rücklage'">
|
||||
<span class="label">Abholung ab</span>
|
||||
<span>{{ subsetItem.estimatedShippingDate | date: 'dd.MM.yyyy' }}</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<ng-container
|
||||
*ngIf="
|
||||
orderItem.features.orderType === 'Versand' ||
|
||||
orderItem.features.orderType === 'B2B-Versand' ||
|
||||
orderItem.features.orderType === 'DIG-Versand'
|
||||
"
|
||||
>
|
||||
<div class="row">
|
||||
<span class="label">Rechnungsadresse</span>
|
||||
<span>{{ order?.billing?.data | address }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Lieferadresse</span>
|
||||
<span>{{ order.shipping?.data | address }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="row" *ngIf="ssc">
|
||||
<span class="label">Meldenummer</span>
|
||||
<span>{{ ssc }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Anmerkung</span>
|
||||
<span>{{ subsetItem.specialComment || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<span class="collapse">
|
||||
<button class="arrow-button" (click)="expand = false">
|
||||
<ui-icon icon="arrow" size="16px" rotate="180deg"></ui-icon>
|
||||
Weniger
|
||||
<span *ngIf="!expand[i]" class="expand">
|
||||
<button class="arrow-button" (click)="expand[i] = true">
|
||||
<span class="relative top-px-3">Mehr</span>
|
||||
<ui-icon icon="arrow" size="16px"></ui-icon>
|
||||
</button>
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<div class="history-wrapper">
|
||||
<button class="cta-history" (click)="openHistory()">Historie</button>
|
||||
<ng-container *ngIf="expand[i]">
|
||||
<div class="row">
|
||||
<span class="label">Abholfachnummer</span>
|
||||
<span>{{ subsetItem.compartmentCode || '-' }} </span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">ISBN</span>
|
||||
<span>{{ orderItem.product.ean }}</span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="orderItem?.product?.formatDetail" class="row item-format">
|
||||
<span class="label">Format</span>
|
||||
<img
|
||||
*ngIf="orderItem?.product?.format !== '--'"
|
||||
loading="lazy"
|
||||
src="assets/images/Icon_{{ orderItem?.product?.format }}.svg"
|
||||
[alt]="orderItem?.product?.formatDetail"
|
||||
/>
|
||||
<span>{{ orderItem?.product?.formatDetail }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Lieferant</span>
|
||||
<span>{{ subsetItem.supplier?.data?.name || '-' }} </span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">MwSt</span>
|
||||
<span>{{ orderItem.grossPrice?.vat?.inPercent }}%</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Zahlungsart</span>
|
||||
<span>{{ order.paymentType | paymentType }}</span>
|
||||
</div>
|
||||
|
||||
<ng-container
|
||||
*ngIf="
|
||||
orderItem.features.orderType === 'Versand' ||
|
||||
orderItem.features.orderType === 'B2B-Versand' ||
|
||||
orderItem.features.orderType === 'DIG-Versand'
|
||||
"
|
||||
>
|
||||
<div class="row">
|
||||
<span class="label">Rechnungsadresse</span>
|
||||
<span>{{ order?.billing?.data | address }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Lieferadresse</span>
|
||||
<span>{{ order.shipping?.data | address }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="row" *ngIf="ssc(subsetItem)">
|
||||
<span class="label">Meldenummer</span>
|
||||
<span>{{ ssc(subsetItem) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="label">Anmerkung</span>
|
||||
<span>{{ subsetItem.specialComment || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<span class="collapse">
|
||||
<button class="arrow-button" (click)="expand[i] = false">
|
||||
<ui-icon icon="arrow" size="16px" rotate="180deg"></ui-icon>
|
||||
<span class="relative top-px-3">Weniger</span>
|
||||
</button>
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<div class="history-wrapper">
|
||||
<button class="cta-history" (click)="openHistory(subsetItem.id)">Historie</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
@apply mt-1 -ml-2;
|
||||
}
|
||||
|
||||
img {
|
||||
.picture img {
|
||||
@apply rounded-md;
|
||||
box-shadow: 0 0 18px 0 #b8b3b7;
|
||||
height: 100px;
|
||||
@@ -68,6 +68,14 @@ img {
|
||||
@apply text-base font-bold text-brand outline-none border-none bg-transparent mr-1;
|
||||
}
|
||||
|
||||
.item-format {
|
||||
@apply flex flex-row items-center whitespace-nowrap;
|
||||
|
||||
img {
|
||||
@apply mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
// .row:first-child {
|
||||
// @apply flex-grow;
|
||||
// }
|
||||
|
||||
@@ -17,38 +17,18 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
||||
@Input()
|
||||
orderItem: OrderItemDTO;
|
||||
|
||||
get hasPrebooked() {
|
||||
return this.orderItem?.subsetItems.some((si) => si?.data?.isPrebooked);
|
||||
}
|
||||
|
||||
imageUrl: Observable<string>;
|
||||
|
||||
expand: boolean;
|
||||
expand: boolean[];
|
||||
|
||||
get subsetItem(): OrderItemSubsetDTO {
|
||||
if (this.orderItem.subsetItems?.length > 0) {
|
||||
return this.orderItem.subsetItems[0]?.data;
|
||||
}
|
||||
}
|
||||
|
||||
get ssc(): string {
|
||||
if (this.subsetItem) {
|
||||
if (this.subsetItem.ssc) {
|
||||
return `${this.subsetItem.ssc} - ${this.subsetItem.sscText}`;
|
||||
} else {
|
||||
return this.subsetItem.sscText;
|
||||
}
|
||||
}
|
||||
get subsetItems(): OrderItemSubsetDTO[] {
|
||||
return this.orderItem.subsetItems.map((subsetItem) => subsetItem.data);
|
||||
}
|
||||
|
||||
constructor(private imageService: ProductImageService, private _modal: UiModalService) {}
|
||||
|
||||
ngOnInit() {
|
||||
// this.imageUrl = this.imageService.getImageUrl(this.orderItem.product.ean, {
|
||||
// width: 60,
|
||||
// height: 100,
|
||||
// });
|
||||
|
||||
this.expand = new Array(this.subsetItems.length);
|
||||
this.imageUrl = of(
|
||||
this.imageService.getImageUrl({
|
||||
imageId: this.orderItem.product.ean,
|
||||
@@ -58,7 +38,15 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
openHistory() {
|
||||
ssc(subsetItem: OrderItemSubsetDTO) {
|
||||
if (subsetItem.ssc) {
|
||||
return `${subsetItem.ssc} - ${subsetItem.sscText}`;
|
||||
} else {
|
||||
return subsetItem.sscText;
|
||||
}
|
||||
}
|
||||
|
||||
openHistory(orderItemSubsetId: number) {
|
||||
this._modal.open({
|
||||
content: HistoryComponent,
|
||||
title: 'Historie',
|
||||
@@ -67,7 +55,7 @@ export class CustomerOrderItemCardComponent implements OnInit {
|
||||
mode: 'order',
|
||||
item: {
|
||||
order: this.order,
|
||||
orderItemSubsetId: this.subsetItem.id,
|
||||
orderItemSubsetId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -18,3 +18,9 @@ a {
|
||||
@apply text-lg text-brand font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-customer-search-result ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,3 +60,9 @@
|
||||
shared-goods-in-out-order-group-item {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-goods-in-cleanup-list ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,3 +77,9 @@ hr {
|
||||
@apply bg-white text-brand;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-goods-in-list ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,3 +60,9 @@ shared-goods-in-out-order-group-item {
|
||||
::ng-deep page-goods-in-remission-preview ui-scroll-container .cta-scroll {
|
||||
bottom: 35px !important;
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-goods-in-remission-preview ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,3 +60,9 @@ shared-goods-in-out-order-group-item {
|
||||
::ng-deep page-goods-in-reservation ui-scroll-container .cta-scroll {
|
||||
bottom: 35px !important;
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-goods-in-reservation ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,3 +34,9 @@ shared-goods-in-out-order-group-item {
|
||||
::ng-deep page-goods-in-search-results ui-scroll-container .cta-scroll {
|
||||
bottom: 35px !important;
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-goods-in-search-results ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
|
||||
this._goodsOutSearchStore.search();
|
||||
this._goodsOutSearchStore.search({});
|
||||
}
|
||||
|
||||
async updateBreadcrumb() {
|
||||
|
||||
@@ -55,15 +55,15 @@ export class GoodsOutSearchComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnInit() {
|
||||
this._goodsOutSearchStore.loadSettings();
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
|
||||
// Reset Filter when query params are empty
|
||||
|
||||
this.processId$.pipe(takeUntil(this._onDestroy$), withLatestFrom(this._activatedRoute.queryParams)).subscribe(([processId, params]) => {
|
||||
if (params && Object.keys(params).length === 0) {
|
||||
this._goodsOutSearchStore.setQueryParams(params);
|
||||
this._goodsOutSearchStore.loadSettings();
|
||||
} else {
|
||||
// this._goodsOutSearchStore.resetFilter(params);
|
||||
}
|
||||
});
|
||||
|
||||
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
|
||||
this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name: 'Warenausgabe',
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CacheService } from '@core/cache';
|
||||
import { DomainGoodsService } from '@domain/oms';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QuerySettingsDTO } from '@swagger/oms';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { isResponseArgs } from '@utils/object';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { switchMap, mergeMap, withLatestFrom, filter, take, tap } from 'rxjs/operators';
|
||||
|
||||
export interface GoodsOutSearchState {
|
||||
@@ -72,7 +73,7 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
|
||||
|
||||
readonly searchResultCleared = this._searchResultClearedSubject.asObservable();
|
||||
|
||||
constructor(private _domainGoodsInService: DomainGoodsService) {
|
||||
constructor(private _domainGoodsInService: DomainGoodsService, private _cache: CacheService) {
|
||||
super({
|
||||
fetching: false,
|
||||
hits: 0,
|
||||
@@ -142,29 +143,46 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
|
||||
}
|
||||
}
|
||||
|
||||
searchRequest(options?: { take?: number; skip?: number }) {
|
||||
searchRequest(options?: { take?: number; skip?: number; reload?: boolean }) {
|
||||
return this.filter$.pipe(
|
||||
filter((f) => f instanceof UiFilter),
|
||||
take(1),
|
||||
mergeMap((filter) =>
|
||||
this._domainGoodsInService.searchWarenausgabe({
|
||||
...filter.getQueryToken(),
|
||||
skip: options?.skip ?? this.results.length,
|
||||
take: options?.take ?? 50,
|
||||
skip: options.reload ? 0 : options?.skip ?? this.results.length,
|
||||
take: options.reload ? this.results.length : options?.take ?? 50,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
search = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.patchState({ fetching: true })),
|
||||
search = this.effect((options$: Observable<{ siletReload?: boolean }>) =>
|
||||
options$.pipe(
|
||||
tap((options) => {
|
||||
if (options.siletReload) {
|
||||
this.patchState({ fetching: true });
|
||||
}
|
||||
}),
|
||||
withLatestFrom(this.results$),
|
||||
switchMap(([_, _results]) =>
|
||||
this.searchRequest(this.searchOptions).pipe(
|
||||
switchMap(([_options, _results]) => {
|
||||
const queryToken = this.filter?.getQueryToken();
|
||||
|
||||
if (queryToken && this._cache.get(queryToken)) {
|
||||
const cached = this._cache.get(queryToken);
|
||||
|
||||
this.patchState(cached);
|
||||
}
|
||||
|
||||
return this.searchRequest({ ...this.searchOptions, reload: _options.siletReload }).pipe(
|
||||
tapResponse(
|
||||
(res) => {
|
||||
const results = [...(_results ?? []), ...(res.result ?? [])];
|
||||
let results: OrderItemListItemDTO[] = [];
|
||||
if (_options.siletReload) {
|
||||
results = res.result;
|
||||
} else {
|
||||
results = [...(_results ?? []), ...(res.result ?? [])];
|
||||
}
|
||||
|
||||
this.patchState({
|
||||
hits: res.hits,
|
||||
@@ -172,6 +190,14 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
|
||||
fetching: false,
|
||||
});
|
||||
|
||||
if (queryToken) {
|
||||
this._cache.set(queryToken, {
|
||||
hits: res.hits,
|
||||
results,
|
||||
fetching: false,
|
||||
});
|
||||
}
|
||||
|
||||
this._searchResultSubject.next(res);
|
||||
},
|
||||
(err: Error) => {
|
||||
@@ -187,8 +213,8 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
|
||||
console.error('GoodsInSearchStore.search()', err);
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
|
||||
this._cdr.markForCheck();
|
||||
});
|
||||
|
||||
this._goodsOutSearchStore.search();
|
||||
this._goodsOutSearchStore.search({});
|
||||
}
|
||||
|
||||
async updateBreadcrumb(processId: number) {
|
||||
|
||||
@@ -6,30 +6,32 @@
|
||||
[deltaEnd]="150"
|
||||
[itemLength]="itemLength$ | async"
|
||||
>
|
||||
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
|
||||
<ng-container
|
||||
*ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; let lastProcessingStatus = last"
|
||||
>
|
||||
<ng-container *ngIf="processId$ | async; let processId">
|
||||
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
|
||||
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
|
||||
<ng-container
|
||||
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; let lastCompartmentCode = last"
|
||||
*ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; let lastProcessingStatus = last"
|
||||
>
|
||||
<shared-goods-in-out-order-group-item
|
||||
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first"
|
||||
[item]="item"
|
||||
[showCompartmentCode]="firstItem"
|
||||
(click)="navigateToDetails(item)"
|
||||
[selectable]="item | goodsOutItemSelectable: selectionRules:selectedItems"
|
||||
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
|
||||
(selectedChange)="setSelectedItem(item, $event)"
|
||||
></shared-goods-in-out-order-group-item>
|
||||
<div class="divider" *ngIf="!lastCompartmentCode"></div>
|
||||
<ng-container
|
||||
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; let lastCompartmentCode = last"
|
||||
>
|
||||
<shared-goods-in-out-order-group-item
|
||||
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
|
||||
[item]="item"
|
||||
[showCompartmentCode]="firstItem"
|
||||
(click)="navigateToDetails(processId, item)"
|
||||
[selectable]="item | goodsOutItemSelectable: selectionRules:selectedItems"
|
||||
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
|
||||
(selectedChange)="setSelectedItem(item, $event)"
|
||||
></shared-goods-in-out-order-group-item>
|
||||
<div class="divider" *ngIf="!lastCompartmentCode"></div>
|
||||
</ng-container>
|
||||
<div class="divider" *ngIf="!lastProcessingStatus"></div>
|
||||
</ng-container>
|
||||
<div class="divider" *ngIf="!lastProcessingStatus"></div>
|
||||
<div class="divider" *ngIf="!lastOrderNumber"></div>
|
||||
</ng-container>
|
||||
<div class="divider" *ngIf="!lastOrderNumber"></div>
|
||||
</ng-container>
|
||||
</shared-goods-in-out-order-group>
|
||||
</shared-goods-in-out-order-group>
|
||||
</ng-container>
|
||||
</ui-scroll-container>
|
||||
|
||||
<ng-template #emptyMessage>
|
||||
|
||||
@@ -39,3 +39,9 @@ shared-goods-in-out-order-group-item {
|
||||
@apply bg-white text-brand;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .desktop page-goods-out-search-results ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 7.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { debounceTime, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { GoodsOutSearchStore } from '../goods-out-search.store';
|
||||
@@ -10,7 +10,6 @@ import { CommandService } from '@core/command';
|
||||
import { OrderItemsContext } from '@domain/oms';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { UiScrollContainerComponent } from '@ui/scroll-container';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
export interface GoodsOutSearchResultsState {
|
||||
selectedOrderItemSubsetIds: number[];
|
||||
@@ -67,14 +66,12 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
|
||||
byCompartmentCodeFn = (item: OrderItemListItemDTO) => item.compartmentCode;
|
||||
|
||||
get processId() {
|
||||
return +this._activatedRoute.snapshot.parent.data.processId;
|
||||
}
|
||||
|
||||
processId$ = this._activatedRoute.parent.data.pipe(map((data) => +data.processId));
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
trackByFn = (item: OrderItemListItemDTO) => `${item.orderId}${item.orderItemId}${item.orderItemSubsetId}`;
|
||||
|
||||
constructor(
|
||||
private _goodsOutSearchStore: GoodsOutSearchStore,
|
||||
private _router: Router,
|
||||
@@ -89,16 +86,22 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
|
||||
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((queryParams) => {
|
||||
this.updateBreadcrumb(queryParams);
|
||||
});
|
||||
this.processId$
|
||||
.pipe(takeUntil(this._onDestroy$), debounceTime(1), withLatestFrom(this._activatedRoute.queryParams))
|
||||
.subscribe(([processId, params]) => {
|
||||
console.log('processId', processId);
|
||||
console.log('params', params);
|
||||
|
||||
this.initInitialSearch(processId);
|
||||
this.createBreadcrumb(processId);
|
||||
this.removeBreadcrumbs(processId);
|
||||
});
|
||||
this._goodsOutSearchStore.setQueryParams(params);
|
||||
this.updateBreadcrumb(processId, params);
|
||||
|
||||
this.initInitialSearch(processId, params);
|
||||
this.createBreadcrumb(processId, params);
|
||||
this.removeBreadcrumbs(processId);
|
||||
|
||||
this._goodsOutSearchStore.clearResults();
|
||||
this._goodsOutSearchStore.search({ siletReload: true });
|
||||
});
|
||||
|
||||
this._goodsOutSearchStore.searchResultCleared.pipe(takeUntil(this._onDestroy$)).subscribe((_) => this.clearSelectedItems());
|
||||
}
|
||||
@@ -107,10 +110,10 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
|
||||
this.updateBreadcrumb(this._goodsOutSearchStore.filter?.getQueryParams());
|
||||
// this.updateBreadcrumb(this._goodsOutSearchStore.filter?.getQueryParams());
|
||||
}
|
||||
|
||||
async removeBreadcrumbs(processId) {
|
||||
async removeBreadcrumbs(processId: number) {
|
||||
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'details']).pipe(first()).toPromise();
|
||||
|
||||
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'edit']).pipe(first()).toPromise();
|
||||
@@ -124,24 +127,24 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
});
|
||||
}
|
||||
|
||||
async createBreadcrumb(processId: number) {
|
||||
async createBreadcrumb(processId: number, params: Record<string, string>) {
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
key: processId,
|
||||
name: this.getBreadcrumbName(),
|
||||
name: this.getBreadcrumbName(params),
|
||||
path: `/kunde/${processId}/goods/out/results`,
|
||||
section: 'customer',
|
||||
params: this._goodsOutSearchStore.filter?.getQueryParams(),
|
||||
params,
|
||||
tags: ['goods-out', 'results', 'filter'],
|
||||
});
|
||||
}
|
||||
|
||||
async updateBreadcrumb(queryParams: Record<string, string> = this._goodsOutSearchStore.filter?.getQueryParams()) {
|
||||
async updateBreadcrumb(processId: number, queryParams: Record<string, string>) {
|
||||
const scroll_position = this.scrollContainer?.scrollPos;
|
||||
const take = this._goodsOutSearchStore.results?.length;
|
||||
|
||||
if (queryParams) {
|
||||
const crumbs = await this._breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.processId, ['goods-out', 'results', 'filter'])
|
||||
.getBreadcrumbsByKeyAndTags$(processId, ['goods-out', 'results', 'filter'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
@@ -157,23 +160,23 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
}
|
||||
}
|
||||
|
||||
getBreadcrumbName() {
|
||||
const input = this._goodsOutSearchStore.filter?.getQueryParams()?.main_qs;
|
||||
getBreadcrumbName(params: Record<string, string>) {
|
||||
const input = params?.main_qs;
|
||||
|
||||
return input?.replace('ORD:', '') ?? 'Alle';
|
||||
}
|
||||
|
||||
initInitialSearch(processId: number) {
|
||||
initInitialSearch(processId: number, params: Record<string, string>) {
|
||||
if (this._goodsOutSearchStore.hits === 0) {
|
||||
this._goodsOutSearchStore.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
|
||||
if (result.hits === 0) {
|
||||
await this._router.navigate([`/kunde/${this.processId}/goods/out`], {
|
||||
await this._router.navigate([`/kunde/${processId}/goods/out`], {
|
||||
queryParams: this._goodsOutSearchStore.filter.getQueryParams(),
|
||||
});
|
||||
} else {
|
||||
await this.createBreadcrumb(processId);
|
||||
await this.createBreadcrumb(processId, params);
|
||||
if (result.hits === 1) {
|
||||
await this.navigateToDetails(result.result[0]);
|
||||
await this.navigateToDetails(processId, result.result[0]);
|
||||
} else {
|
||||
if (!!this._goodsOutSearchStore.searchOptions?.take) {
|
||||
this._goodsOutSearchStore.searchOptions = undefined;
|
||||
@@ -182,7 +185,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
}
|
||||
}
|
||||
});
|
||||
this._goodsOutSearchStore.search();
|
||||
this._goodsOutSearchStore.search({});
|
||||
}
|
||||
|
||||
const { scroll_position, take } = this._goodsOutSearchStore.queryParams;
|
||||
@@ -193,21 +196,22 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
|
||||
|
||||
async loadMore() {
|
||||
if (this._goodsOutSearchStore.hits > this._goodsOutSearchStore.results.length && !this._goodsOutSearchStore.fetching) {
|
||||
this._goodsOutSearchStore.search();
|
||||
this._goodsOutSearchStore.search({});
|
||||
}
|
||||
}
|
||||
|
||||
navigateToDetails(orderItem: OrderItemListItemDTO) {
|
||||
navigateToDetails(processId: number, orderItem: OrderItemListItemDTO) {
|
||||
console.log('navigateToDetails', orderItem);
|
||||
const orderNumber = orderItem.orderNumber;
|
||||
const processingStatus = orderItem.processingStatus;
|
||||
const compartmentCode = orderItem.compartmentCode;
|
||||
|
||||
if (compartmentCode) {
|
||||
this._router.navigate([
|
||||
`/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
|
||||
`/kunde/${processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
|
||||
]);
|
||||
} else {
|
||||
this._router.navigate([`/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
|
||||
this._router.navigate([`/kunde/${processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { UiModalService } from '@ui/modal';
|
||||
import { NEVER, Subject } from 'rxjs';
|
||||
import { catchError, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { AddProductModalComponent, AddProductModalData } from '../modals/add-product-modal';
|
||||
import { RemissionListComponentStore } from '../remission-list/remission-list.component-store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-remission-add-product',
|
||||
@@ -28,6 +29,7 @@ export class AddProductComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _remissionListStore: RemissionListComponentStore,
|
||||
private _remiService: DomainRemissionService,
|
||||
private _modal: UiModalService,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
@@ -76,6 +78,7 @@ export class AddProductComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
modal.afterClosed$.pipe(takeUntil(this._onDestroy)).subscribe((result) => {
|
||||
if (result.data) {
|
||||
this._remissionListStore._triggerReload$.next(true);
|
||||
this._router.navigate(['..', 'list'], { relativeTo: this._activatedRoute, queryParams: this.queryParams });
|
||||
}
|
||||
});
|
||||
@@ -103,7 +106,7 @@ export class AddProductComponent implements OnInit, OnDestroy {
|
||||
addBreadcrumbIfNotExists() {
|
||||
this._breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: this._config.get('process.ids.remission'),
|
||||
name: 'Wannennummer',
|
||||
name: 'Artikel hinzufügen',
|
||||
path: '/filiale/remission/add-product',
|
||||
section: 'branch',
|
||||
params: this.queryParams,
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
<p class="text-xl mt-4">
|
||||
Um einen Warenbegleitschein zu <br />
|
||||
eröffnen,
|
||||
<ng-container *ngIf="supplierId === 2">
|
||||
<ng-container *ngIf="supplierId === 2; else defaultText">
|
||||
scannen Sie die Packstück-ID <br />
|
||||
oder
|
||||
oder lassen Sie diese automatisch generieren.
|
||||
</ng-container>
|
||||
lassen Sie diese automatisch generieren.
|
||||
<ng-template #defaultText>
|
||||
lassen Sie diesen automatisch generieren.
|
||||
</ng-template>
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-center flex justify-center my-4">
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { UiDialogModalComponent, UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { mapFromReturnItemDTO, mapFromReturnSuggestionDTO } from 'apps/domain/remission/src/lib/mappings';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
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';
|
||||
|
||||
@@ -169,11 +169,26 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
throw new Error('Item hat keinen passenden DTO Typ');
|
||||
}
|
||||
|
||||
// Bei remittieren eines Stapels die StockInformation für alle anderen Stapel mit der selben EAN aktualisieren
|
||||
if (placementType != 'Leistung') {
|
||||
const items = await this._store.items$.pipe(first()).toPromise();
|
||||
|
||||
const itemsByEan = items?.filter(
|
||||
(i) => i.dto.product.ean === this.item.dto.product.ean && i.dto.id !== this.item.dto.id && i.placementType === 'Stapel'
|
||||
);
|
||||
|
||||
if (itemsByEan?.length > 0) {
|
||||
const updatedItems = await this.updateStockInformation(itemsByEan);
|
||||
updatedItems.forEach((i) => this._store.updateItem(i));
|
||||
}
|
||||
}
|
||||
|
||||
this._store.removeItem(this.item);
|
||||
if (response && !!response?.item2) {
|
||||
response.item2.placementType = placementType;
|
||||
this.addItem(response.item2);
|
||||
await this.addItem(response.item2);
|
||||
}
|
||||
|
||||
this._store.updateCache();
|
||||
} catch (err) {
|
||||
this._modal.open({
|
||||
@@ -201,7 +216,9 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
updatedDto = await this._remissionService.returnSuggestion(this.item.dto?.id).toPromise();
|
||||
}
|
||||
|
||||
if (updatedDto.impediment?.attempts > 3) {
|
||||
if (updatedDto.impediment?.attempts === 1 && updatedDto.returnReason.startsWith('Abholfach:')) {
|
||||
this._store.removeItem(this.item);
|
||||
} else if (updatedDto.impediment?.attempts > 3) {
|
||||
this._store.removeItem(this.item);
|
||||
} else {
|
||||
this._store.updateItemDto(updatedDto);
|
||||
@@ -237,18 +254,21 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
// Anzeige der Remi-Menge und des aktuellen Bestands aktualisieren
|
||||
item = await this.updateStockInformation(item);
|
||||
const items = await this.updateStockInformation([item]);
|
||||
|
||||
this._store.addItems([item]);
|
||||
this._store.addItems(items);
|
||||
}
|
||||
|
||||
async updateStockInformation(item: RemissionListItem) {
|
||||
async updateStockInformation(items: RemissionListItem[]) {
|
||||
try {
|
||||
const res = (await this._remissionService.getStockInformation([item]).toPromise())?.find((_) => true);
|
||||
item.remissionQuantity = res.remissionQuantity;
|
||||
item.remainingQuantity = res.remainingQuantity;
|
||||
item.inStock = res.inStock;
|
||||
return item;
|
||||
const res = await this._remissionService.getStockInformation(items).toPromise();
|
||||
items.forEach((item) => {
|
||||
const resForItem = res.find((r) => r.dto.id === item.dto.id);
|
||||
item.remissionQuantity = resForItem?.remissionQuantity;
|
||||
item.remainingQuantity = resForItem?.remainingQuantity;
|
||||
item.inStock = resForItem?.inStock;
|
||||
});
|
||||
return items;
|
||||
} catch (err) {
|
||||
throw new Error('Fehler bei der Bestandsabfrage');
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
});
|
||||
|
||||
searchCompleted = this._searchCompleted.asObservable();
|
||||
|
||||
_sourceOrSupplierChange$ = new BehaviorSubject<boolean>(false);
|
||||
_triggerReload$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
private _filterChange$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
@@ -154,11 +153,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
}
|
||||
|
||||
initSearch() {
|
||||
combineLatest([this._sourceOrSupplierChange$, this._filterChange$])
|
||||
combineLatest([this._triggerReload$, this._filterChange$])
|
||||
.pipe(debounceTime(500), takeUntil(this._onDestroy$))
|
||||
.subscribe(([change, filter]) => {
|
||||
.subscribe(([reload, filter]) => {
|
||||
const data = this.getCachedData();
|
||||
if (change || data.items?.length === 0 || filter) {
|
||||
if (reload || data.items?.length === 0 || filter) {
|
||||
this.search({ newSearch: true });
|
||||
}
|
||||
});
|
||||
@@ -167,7 +166,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
// tslint:disable: member-ordering
|
||||
loadSuppliers = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
// tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
switchMap((_) =>
|
||||
this._domainRemissionService.getSuppliers().pipe(
|
||||
tapResponse(
|
||||
@@ -181,7 +180,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
loadSources = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
// tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
switchMap((_) =>
|
||||
this._domainRemissionService.getSources().pipe(
|
||||
tapResponse(
|
||||
@@ -195,7 +194,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
loadRequiredCapacities = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
// tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
withLatestFrom(this.selectedSupplier$, this.filter$),
|
||||
switchMap(([_, supplier, filter]) => {
|
||||
let departments = [];
|
||||
@@ -215,7 +214,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
loadFilter = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
// tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
withLatestFrom(this.selectedSupplier$, this.selectedSource$, this._activatedRoute.queryParams),
|
||||
filter(([, selectedSupplier, selectedSource]) => !!selectedSupplier?.id && !!selectedSource),
|
||||
switchMap(([, selectedSupplier, selectedSource, queryParams]) =>
|
||||
@@ -236,7 +235,13 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
}
|
||||
|
||||
this.setFilter(filter);
|
||||
this._filterChange$.next(true);
|
||||
|
||||
// Only trigger search with _filterChange$ if no cached data available
|
||||
// If cached data is available, there is no need to trigger the search
|
||||
const data = this.getCachedData();
|
||||
if (data.items?.length === 0) {
|
||||
this._filterChange$.next(true);
|
||||
}
|
||||
},
|
||||
(err) => {}
|
||||
)
|
||||
@@ -247,12 +252,13 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
search = this.effect((options$: Observable<{ newSearch?: boolean }>) =>
|
||||
options$.pipe(
|
||||
tap((options) => {
|
||||
withLatestFrom(this.filter$, this.selectedSource$, this.selectedSupplier$, this.searchOptions$, this.items$),
|
||||
filter(([, filter, source, supplier]) => !!supplier?.id && !!source && !!filter),
|
||||
filter(([, filter, source]) => (source === 'Abteilungsremission' ? !!filter.getQueryToken().filter.abteilungen : true)),
|
||||
tap(([options]) => {
|
||||
this.setFetching(true);
|
||||
options?.newSearch ? this.setSearchResult({ result: [], hits: 0 }) : null;
|
||||
}),
|
||||
withLatestFrom(this.filter$, this.selectedSource$, this.selectedSupplier$, this.searchOptions$, this.items$),
|
||||
filter(([, filter, source, supplier]) => !!supplier?.id && !!source && !!filter),
|
||||
switchMap(([options, filter, source, supplier, searchOptions, items]) =>
|
||||
this._domainRemissionService
|
||||
.getItems({
|
||||
@@ -265,11 +271,13 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
supplierId: supplier.id,
|
||||
})
|
||||
.pipe(
|
||||
// Nochmal letzten Stand der Items holen, da diese während dem Nachladen manipuliert werden können (remittieren)
|
||||
withLatestFrom(this.items$),
|
||||
tapResponse(
|
||||
(res) => {
|
||||
([res, currentItems]) => {
|
||||
const results = options?.newSearch
|
||||
? { result: [...res.result], hits: res.hits ?? 0 }
|
||||
: { result: [...(items ?? []), ...(res.result ?? [])], hits: res.hits ?? 0 };
|
||||
: { result: [...(currentItems ?? []), ...(res.result ?? [])], hits: res.hits ?? 0 };
|
||||
|
||||
// find items that are already in the list and remove the first duplicate
|
||||
// why do we need it? when we use the action item not found we will add this item to the end of the list
|
||||
@@ -277,8 +285,8 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
// to keep the list clean we remove all duplicates and just keep the last one
|
||||
const itemsToRemove: number[] = [];
|
||||
results.result.forEach((item) => {
|
||||
const duplicates = items.filter((i) => i.dto.id === item.dto.id);
|
||||
if (duplicates.length > 1) {
|
||||
const duplicates = results.result.filter((i) => i.dto.id === item.dto.id);
|
||||
if (duplicates.length > 1 && !itemsToRemove.includes(duplicates.find((_) => true)?.dto?.id)) {
|
||||
// skip the first duplicate
|
||||
// and add ids of the duplicates to the list of items to remove
|
||||
itemsToRemove.push(...duplicates.slice(1).map((i) => i.dto.id));
|
||||
@@ -289,6 +297,8 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
const index = results.result.findIndex((i) => i.dto.id === id);
|
||||
if (index > -1) {
|
||||
results.result.splice(index, 1);
|
||||
// Hits anpassen, da sonst beim runterscrollen versucht wird nachzuladen obwohl evtl. nichts mehr kommt
|
||||
results.hits--;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -380,6 +390,13 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
hits: state.hits - 1,
|
||||
}));
|
||||
|
||||
updateItem = this.updater<RemissionListItem>((state, item) => {
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((i) => (i.dto.id === item.dto.id ? { ...item } : i)),
|
||||
};
|
||||
});
|
||||
|
||||
updateItemDto = this.updater<ReturnItemDTO | ReturnSuggestionDTO>((state, itemDto) => {
|
||||
const itemToUpdate = state.items.find((i) => i.dto?.id === itemDto.id);
|
||||
|
||||
@@ -436,7 +453,10 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
}
|
||||
|
||||
async setSupplier(supplier: SupplierDTO) {
|
||||
this._sourceOrSupplierChange$.next(true);
|
||||
if (supplier.id === this.selectedSupplier?.id) {
|
||||
return;
|
||||
}
|
||||
this._triggerReload$.next(true);
|
||||
this.setSearchResult({ result: [], hits: 0 });
|
||||
this.clearCache();
|
||||
await this._router.navigate([], {
|
||||
@@ -449,7 +469,10 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
}
|
||||
|
||||
async setSource(source: string) {
|
||||
this._sourceOrSupplierChange$.next(true);
|
||||
if (source === this.selectedSource) {
|
||||
return;
|
||||
}
|
||||
this._triggerReload$.next(true);
|
||||
this.setSearchResult({ result: [], hits: 0 });
|
||||
this.clearCache();
|
||||
await this._router.navigate([], {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<cdk-virtual-scroll-viewport
|
||||
#scrollContainer
|
||||
class="remission-list scroll-bar"
|
||||
class="remission-list"
|
||||
[itemSize]="368"
|
||||
minBufferPx="1200"
|
||||
maxBufferPx="1200"
|
||||
@@ -36,7 +36,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<br />
|
||||
<div class="inline-flex flex-row bg-white rounded-md mt-4">
|
||||
<div *ngIf="(filteredSuppliers$ | async).length > 1" class="inline-flex flex-row bg-white rounded-md mt-4">
|
||||
<button
|
||||
class="w-48 py-2 bg-white text-black rounded-md font-bold"
|
||||
type="button"
|
||||
@@ -76,8 +76,17 @@
|
||||
<page-remission-list-item [item]="item" [returnDto]="return$ | async"></page-remission-list-item>
|
||||
</div>
|
||||
<page-remission-list-item-loading *ngIf="fetching$ | async"></page-remission-list-item-loading>
|
||||
<div *ngIf="listEmpty$ | async" class="bg-white text-center font-semibold text-inactive-branch py-10 rounded-card">
|
||||
Es sind im Moment keine Artikel vorhanden
|
||||
<div
|
||||
*ngIf="listEmpty$ | async"
|
||||
class="bg-white text-center font-semibold text-inactive-branch py-10 rounded-card"
|
||||
[ngSwitch]="showSelectDepartmenttext$ | async"
|
||||
>
|
||||
<span *ngSwitchCase="true">
|
||||
Wählen Sie die Abteilung, aus der Sie remittieren möchten.
|
||||
</span>
|
||||
<span *ngSwitchCase="false">
|
||||
Es sind im Moment keine Artikel vorhanden
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ import { RemissionComponentStore } from './remission.component-store';
|
||||
templateUrl: 'remission-list.component.html',
|
||||
styleUrls: ['remission-list.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [RemissionListComponentStore, RemissionComponentStore],
|
||||
providers: [RemissionComponentStore],
|
||||
})
|
||||
export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
@ViewChildren(RemissionListItemComponent) listItems: QueryList<RemissionListItemComponent>;
|
||||
@@ -70,6 +70,24 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
return this._remissionStore.return$;
|
||||
}
|
||||
|
||||
get filter$() {
|
||||
return this._remissionListStore.filter$;
|
||||
}
|
||||
|
||||
showSelectDepartmenttext$ = combineLatest([this.filter$, this.selectedSource$]).pipe(
|
||||
map(([filter, source]) => {
|
||||
if (source !== 'Abteilungsremission') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!!filter?.getQueryToken()?.filter?.abteilungen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
|
||||
listEmpty$ = combineLatest([this.fetching$, this.hits$]).pipe(
|
||||
map(([loading, hits]) => !loading && hits === 0),
|
||||
shareReplay()
|
||||
@@ -121,8 +139,6 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(0)).subscribe(async (queryParams) => {
|
||||
const { supplier, source } = queryParams;
|
||||
|
||||
this._remissionListStore.loadFilter();
|
||||
|
||||
if (supplier) {
|
||||
this._remissionListStore.setSelectedSupplierId(+supplier);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ import { Config } from '@core/config';
|
||||
import { ToastService } from '@core/toast';
|
||||
import { Subject } from 'rxjs';
|
||||
import { filter, first, takeUntil } from 'rxjs/operators';
|
||||
import { RemissionListComponentStore } from './remission-list/remission-list.component-store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-remission',
|
||||
templateUrl: './remission.component.html',
|
||||
styleUrls: ['./remission.component.scss'],
|
||||
providers: [RemissionListComponentStore],
|
||||
})
|
||||
export class RemissionComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject();
|
||||
@@ -21,6 +23,7 @@ export class RemissionComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _remissionListComponentStore: RemissionListComponentStore,
|
||||
private readonly _breadcrumb: BreadcrumbService,
|
||||
private readonly _config: Config,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
|
||||
@@ -8,6 +8,4 @@
|
||||
<div class="progress-inner" [style.width]="staplePercentage + '%'"></div>
|
||||
</div>
|
||||
<div class="mt-px-2 text-active-branch">Stapelplätze: {{ staple }} von {{ maxStaple }} Titel</div>
|
||||
|
||||
<div class="mt-4 text-cool-grey font-semibold text-center">Wählen Sie die Abteilung aus, die Sie<br />remittieren möchten.</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -20,17 +20,12 @@
|
||||
<div>Remi-Menge</div>
|
||||
<div class="font-bold col-span-3">{{ item.quantity }}x</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4">
|
||||
<div>Platz</div>
|
||||
<div class="font-bold col-span-2">Leistung</div>
|
||||
|
||||
<div *ngIf="canRemoveItem" class="text-right">
|
||||
<button [disabled]="loading" class="text-card-sub bg-transparent text-brand border-none font-bold" (click)="removeItem.emit(item)">
|
||||
<ui-spinner [show]="loading">
|
||||
Entfernen
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="canRemoveItem" class="flex justify-end">
|
||||
<button [disabled]="loading" class="text-card-sub bg-transparent text-brand border-none font-bold" (click)="removeItem.emit(item)">
|
||||
<ui-spinner [show]="loading">
|
||||
Entfernen
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[canRemoveItems]="remissionStarted$ | async"
|
||||
[showAddToRemiHint]="remissionStarted$ | async"
|
||||
(deleted)="deleted($event)"
|
||||
(itemDeleted)="reloadReturn()"
|
||||
(itemDeleted)="itemDeleted()"
|
||||
></page-shared-shipping-document-details>
|
||||
|
||||
<ng-container *ngIf="notCompleted$ | async">
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ReturnDTO } from '@swagger/remi';
|
||||
import { NEVER, Observable } from 'rxjs';
|
||||
import { catchError, filter, first, map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { ShortReceiptNumberPipe } from '../../pipes/short-receipt-number.pipe';
|
||||
import { RemissionListComponentStore } from '../../remission-list/remission-list.component-store';
|
||||
|
||||
export interface ShippingDocumentDetailsState {
|
||||
remissionStarted?: boolean;
|
||||
@@ -73,6 +74,7 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _remissionListStore: RemissionListComponentStore,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _remissionService: DomainRemissionService,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
@@ -134,10 +136,21 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
|
||||
}
|
||||
|
||||
deleted() {
|
||||
this._cache.delete({ processId: String(this.processId) });
|
||||
// Cache leeren und Reload bei Wechsel zurück zur Liste triggern
|
||||
this._remissionListStore.clearCache();
|
||||
this._remissionListStore._triggerReload$.next(true);
|
||||
|
||||
this.navigateBack();
|
||||
}
|
||||
|
||||
itemDeleted() {
|
||||
// Cache leeren und Reload bei Wechsel zurück zur Liste triggern
|
||||
this._remissionListStore.clearCache();
|
||||
this._remissionListStore._triggerReload$.next(true);
|
||||
|
||||
this.reloadReturn();
|
||||
}
|
||||
|
||||
reloadReturn = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy, Output, EventEmitter } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { IUiOption, UiOption } from '../../../tree';
|
||||
|
||||
@@ -21,6 +21,8 @@ export class UiFilterInputOptionBoolComponent implements OnDestroy {
|
||||
this.subscribeChanges();
|
||||
}
|
||||
|
||||
@Output() optionChange = new EventEmitter<UiOption>();
|
||||
|
||||
get uiOption() {
|
||||
return this._option;
|
||||
}
|
||||
@@ -37,8 +39,9 @@ export class UiFilterInputOptionBoolComponent implements OnDestroy {
|
||||
this.unsubscribeChanges();
|
||||
if (this.uiOption) {
|
||||
this.optionChangeSubscription.add(
|
||||
this.uiOption.changes.subscribe(() => {
|
||||
this.uiOption.changes.subscribe((change) => {
|
||||
this.cdr.markForCheck();
|
||||
this.optionChange.next(change.target);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
<button type="button" (click)="setSelected(undefined)">
|
||||
Alle entfernen
|
||||
</button>
|
||||
<button type="button" (click)="setSelected(true)" *ngIf="uiInputOptions?.parent?.type === 2 || uiInputOptions?.parent?.type === 4">
|
||||
<button
|
||||
type="button"
|
||||
(click)="setSelected(true)"
|
||||
*ngIf="!uiInputOptions?.max && (uiInputOptions?.parent?.type === 2 || uiInputOptions?.parent?.type === 4)"
|
||||
>
|
||||
Alle auswählen
|
||||
</button>
|
||||
</div>
|
||||
@@ -16,10 +20,14 @@
|
||||
<ng-container *ngIf="uiInputOptions?.parent?.type === 2 || uiInputOptions?.parent?.type === 4">
|
||||
<div class="input-options" #inputOptionsConainter (scroll)="markForCheck()">
|
||||
<ng-container *ngIf="uiInputOptions?.parent?.type === 2">
|
||||
<ui-input-option-bool *ngFor="let option of uiInputOptions?.values" [option]="option"></ui-input-option-bool>
|
||||
<ui-input-option-bool
|
||||
*ngFor="let option of uiInputOptions?.values"
|
||||
[option]="option"
|
||||
(optionChange)="optionChange($event)"
|
||||
></ui-input-option-bool>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="uiInputOptions?.parent?.type === 4">
|
||||
<ui-input-option-tri-state *ngFor="let option of uiInputOptions?.values" [option]="option"></ui-input-option-tri-state>
|
||||
<ui-input-option-tri-state *ngFor="let option of uiInputOptions?.values" [option]="option"> </ui-input-option-tri-state>
|
||||
</ng-container>
|
||||
</div>
|
||||
<button class="cta-scroll" [class.up]="scrollPersantage > 20" *ngIf="scrollable" (click)="scroll(20)">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, ViewChild, ElementRef, AfterViewInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { IUiInputOptions, UiInputOptions, UiInputType } from '../../tree';
|
||||
import { Component, ChangeDetectionStrategy, Input, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { IUiInputOptions, UiInputOptions, UiInputType, UiOption } from '../../tree';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-filter-input-options',
|
||||
@@ -24,6 +25,7 @@ export class UiFilterInputOptionsComponent {
|
||||
} else {
|
||||
this._inputOptions = UiInputOptions.create(value);
|
||||
}
|
||||
|
||||
this.markForCheck();
|
||||
}
|
||||
|
||||
@@ -48,6 +50,20 @@ export class UiFilterInputOptionsComponent {
|
||||
|
||||
constructor(private cdr: ChangeDetectorRef) {}
|
||||
|
||||
optionChange(option: UiOption) {
|
||||
if (!this.uiInputOptions?.max || !option.selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const max = this.uiInputOptions.max;
|
||||
const selectedOptions = this.uiInputOptions.values.filter((o) => o.selected);
|
||||
|
||||
if (selectedOptions.length > max) {
|
||||
const optionsToUnselect = selectedOptions.filter((o) => o.label !== option.label);
|
||||
optionsToUnselect.forEach((option) => option.setSelected(false));
|
||||
}
|
||||
}
|
||||
|
||||
markForCheck() {
|
||||
setTimeout(() => this.cdr.markForCheck(), 0);
|
||||
}
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
@apply relative grid grid-flow-row gap-3;
|
||||
}
|
||||
|
||||
::ng-deep ui-scroll-container .scroll-bar::-webkit-scrollbar {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
::ng-deep ui-scroll-container .scroll-bar::-webkit-scrollbar-track {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
@apply h-px-100;
|
||||
}
|
||||
@@ -25,20 +17,12 @@
|
||||
}
|
||||
|
||||
::ng-deep .customer ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 10rem;
|
||||
}
|
||||
|
||||
.cta-scroll {
|
||||
@apply text-active-customer;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .branch ui-scroll-container {
|
||||
.scrollbar-gap::-webkit-scrollbar-track {
|
||||
margin-bottom: 15.5rem;
|
||||
}
|
||||
|
||||
.cta-scroll {
|
||||
@apply text-cool-grey;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user