Merged PR 1777: Merge Develop -> Release/3.1

Merge Develop -> Release/3.1
This commit is contained in:
Nino Righi
2024-05-03 13:00:46 +00:00
committed by Lorenz Hilpert
parent ed7dc10246
commit 4db28b1aa7
27 changed files with 216 additions and 63 deletions

View File

@@ -155,7 +155,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
const cleanQueryParams = this.cleanupQueryParams(queryParams);
if (this.route.outlet === 'primary' || processChanged) {
if (processChanged) {
this.scrollToItem(this._getScrollIndexFromCache());
}
@@ -271,7 +271,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
}
private _getScrollIndexFromCache(): number {
return this.cache.get<number>({ processId: this.getProcessId(), token: this.SCROLL_INDEX_TOKEN });
return this.cache.get<number>({ processId: this.getProcessId(), token: this.SCROLL_INDEX_TOKEN }) ?? 0;
}
scrollToItem(i?: number) {

View File

@@ -19,17 +19,14 @@
placeholder="Eine Anmerkung hinzufügen"
[(ngModel)]="value"
[rows]="rows"
(ngModelChange)="check()"
(blur)="save()"
(ngModelChange)="updateValue()"
(blur)="updateValue()"
></textarea>
<div class="comment-actions py-4">
<button type="reset" class="clear pl-4" *ngIf="!disabled && !!value" (click)="clear(); triggerResize()">
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
<button class="cta-save ml-4" type="submit" *ngIf="!disabled && isDirty" (click)="save()">
Speichern
</button>
</div>
</div>

View File

@@ -61,7 +61,7 @@ export class SpecialCommentComponent implements ControlValueAccessor {
clear() {
this.value = '';
this.save();
this.updateValue();
}
check() {
@@ -80,11 +80,12 @@ export class SpecialCommentComponent implements ControlValueAccessor {
this.cdr.markForCheck();
}
save() {
updateValue() {
this.initialValue = this.value;
this.onChange(this.value);
this.check();
}
setIsDirty(isDirty: boolean) {
this.isDirty = isDirty;
this.isDirtyChange.emit(isDirty);

View File

@@ -1,6 +1,6 @@
import { HttpErrorResponse } from '@angular/common/http';
import { ChangeDetectorRef, Directive, OnDestroy, OnInit, ViewChild, inject } from '@angular/core';
import { AbstractControl, AsyncValidatorFn, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { AbstractControl, AsyncValidatorFn, UntypedFormControl, UntypedFormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { CrmCustomerService } from '@domain/crm';
@@ -190,6 +190,47 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
this.cdr.markForCheck();
}
minBirthDateValidator = (): ValidatorFn => {
return (control: AbstractControl): ValidationErrors | null => {
const minAge = 18; // 18 years
if (!control.value) {
return null;
}
const controlBirthDate = new Date(control.value);
const minBirthDate = new Date();
minBirthDate.setFullYear(minBirthDate.getFullYear() - minAge);
// Check if customer is over 18 years old
if (this._checkIfAgeOver18(controlBirthDate, minBirthDate)) {
return null;
} else {
return { minBirthDate: `Teilnahme ab ${minAge} Jahren` };
}
};
};
private _checkIfAgeOver18(inputDate: Date, minBirthDate: Date): boolean {
// Check year
if (inputDate.getFullYear() < minBirthDate.getFullYear()) {
return true;
}
// Check Year + Month
else if (inputDate.getFullYear() === minBirthDate.getFullYear() && inputDate.getMonth() < minBirthDate.getMonth()) {
return true;
}
// Check Year + Month + Day
else if (
inputDate.getFullYear() === minBirthDate.getFullYear() &&
inputDate.getMonth() === minBirthDate.getMonth() &&
inputDate.getDate() <= minBirthDate.getDate()
) {
return true;
}
return false;
}
emailExistsValidator: AsyncValidatorFn = (control) => {
return of(control.value).pipe(
tap((_) => this.customerExists$.next(false)),

View File

@@ -70,7 +70,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
agbValidatorFns = [Validators.requiredTrue];
birthDateValidatorFns = [Validators.required];
birthDateValidatorFns = [];
existingCustomer$: Observable<CustomerInfoDTO | null>;
@@ -138,6 +138,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
initMarksAndValidators() {
this.asyncLoyaltyCardValidatorFn = [this.checkLoyalityCardValidator];
this.birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()];
if (this._customerType === 'webshop') {
this.emailRequiredMark = true;
this.emailValidatorFn = [Validators.required, Validators.email, validateEmail];

View File

@@ -22,7 +22,7 @@ export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer im
agbValidatorFns = [Validators.requiredTrue];
birthDateValidatorFns = [Validators.required];
birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()];
nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];

View File

@@ -36,12 +36,22 @@
<page-pickup-shelf-details-tags class="mb-px-2" *ngIf="showTagsComponent$ | async"></page-pickup-shelf-details-tags>
<page-pickup-shelf-details-covers
*ngIf="(coverOrderItems$ | async)?.length > 0"
[coverItems]="coverOrderItems$ | async"
[selectedOrderItem]="selectedItem$ | async"
(coverClick)="coverClick($event)"
></page-pickup-shelf-details-covers>
<ng-container *ngIf="fetchingCoverItems$ | async; else coverItemsTmpl">
<div class="bg-white grid grid-flow-col gap-5 justify-center items-center h-40">
<shared-skeleton-loader class="h-16 w-12"></shared-skeleton-loader>
<shared-skeleton-loader class="h-16 w-12"></shared-skeleton-loader>
<shared-skeleton-loader class="h-16 w-12"></shared-skeleton-loader>
</div>
</ng-container>
<ng-template #coverItemsTmpl>
<page-pickup-shelf-details-covers
*ngIf="(coverOrderItems$ | async)?.length > 0"
[coverItems]="coverOrderItems$ | async"
[selectedOrderItem]="selectedItem$ | async"
(coverClick)="coverClick($event)"
></page-pickup-shelf-details-covers>
</ng-template>
</div>
<div class="page-pickup-shelf-in-details__action-wrapper">

View File

@@ -18,6 +18,7 @@ import { ActivatedRoute } from '@angular/router';
import { RunCheckTrigger } from '../../trigger';
import { PickUpShelfDetailsItemsGroupComponent } from '../../shared/pickup-shelf-details-items-group/pickup-shelf-details-items-group.component';
import { isEqual } from 'lodash';
import { SkeletonLoaderComponent } from '@shared/components/loader';
@Component({
selector: 'page-pickup-shelf-in-details',
@@ -38,6 +39,7 @@ import { isEqual } from 'lodash';
PickupShelfAddToPreviousCompartmentCodeLabelPipe,
UiSpinnerModule,
OnInitDirective,
SkeletonLoaderComponent,
],
})
export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseComponent implements OnInit, AfterViewInit {
@@ -54,12 +56,12 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
noOrderItemsFound$ = this.store.noOrderItemsFound$;
fetching$ = this.store.fetchingOrder$;
fetchingOrder$ = this.store.fetchingOrder$;
fetchingItems$ = this.store.fetchingOrderItems$;
fetchingCoverItems$ = this.store.fetchingCoverOrderItems$;
viewFetching$ = combineLatest([this.fetching$, this.fetchingItems$, this.fetchingCoverItems$]).pipe(
map(([fetching, fetchingItems, fetchingCoverItems]) => fetching || fetchingItems || fetchingCoverItems)
viewFetching$ = combineLatest([this.fetchingItems$, this.orderItems$]).pipe(
map(([fetchingItems, orderItems]) => fetchingItems && orderItems.length === 0)
);
selectedCompartmentInfo = this.store.selectedCompartmentInfo;

View File

@@ -212,7 +212,7 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
*/
const filterQueryParams = this.listStore.filter.getQueryParams();
if (response.hits === 1 || this._hasSameOrderNumber(response)) {
if (response.hits === 1) {
const detailsPath = await this.getPathForDetail(response.result[0]).pipe(take(1)).toPromise();
await this.router.navigate(detailsPath.path, { queryParams: { ...queryParams, ...filterQueryParams, ...detailsPath.queryParams } });
} else if (response.hits > 1) {
@@ -224,10 +224,13 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
});
}
// Fix Ticket #4684 Navigate on Details if items contain same OrderNumber
private _hasSameOrderNumber(response: ListResponseArgsOfDBHOrderItemListItemDTO) {
if (response.hits === 0) return false;
const orderNumbers = new Set(response.result.map((item) => item.orderNumber));
return orderNumbers.size === 1;
}
// Ticket 4720 WA // Trefferliste wird übersprungen - Bei mehreren Bestellposten pro Bestellung soll IMMER auf Trefferliste navigiert werden
// Damit werden #4684 und #4688 überflüssig
// REMOVED: Fix Ticket #4684 Navigate on Details if items contain same OrderNumber
// private _hasSameOrderNumber(response: ListResponseArgsOfDBHOrderItemListItemDTO) {
// if (response.hits === 0) return false;
// const orderNumbers = new Set(response.result.map((item) => item.orderNumber));
// return orderNumbers.size === 1;
// }
}

View File

@@ -1,11 +1,13 @@
<ng-container *ngIf="orderItem$ | async; let orderItem">
<div class="grid grid-flow-row gap-px-2">
<div class="bg-[#F5F7FA] flex flex-row justify-between items-center p-4 rounded-t">
<div class="grid grid-flow-col gap-[0.4375rem] items-center" *ngIf="features$ | async; let features; else: featureLoading">
<shared-icon *ngIf="features?.length > 0" [size]="24" icon="person"></shared-icon>
<div class="grid grid-flow-col gap-2 items-center font-bold text-p2" *ngFor="let feature of features">
{{ feature?.description }}
</div>
<div class="grid grid-flow-col gap-[0.4375rem] items-center" *ngIf="fetchingCustomerDone$ | async; else featureLoading">
<ng-container *ngIf="features$ | async; let features">
<shared-icon *ngIf="features?.length > 0" [size]="24" icon="person"></shared-icon>
<div class="grid grid-flow-col gap-2 items-center font-bold text-p2" *ngFor="let feature of features">
{{ feature?.description }}
</div>
</ng-container>
</div>
<button
@@ -18,6 +20,10 @@
</button>
</div>
<ng-template #featureLoading>
<shared-skeleton-loader class="w-64 h-6"></shared-skeleton-loader>
</ng-template>
<div class="page-pickup-shelf-details-header__details bg-white px-4 pt-4 pb-5">
<div class="flex flex-row items-center" [class.mb-8]="!orderItem?.features?.paid && !isKulturpass">
<page-pickup-shelf-details-header-nav-menu class="mr-2" [customer]="customer$ | async"></page-pickup-shelf-details-header-nav-menu>
@@ -96,7 +102,12 @@
</div>
<div class="flex flex-row page-pickup-shelf-details-header__order-source" data-detail-id="Bestellkanal">
<div class="min-w-[9rem]">Bestellkanal</div>
<div class="flex flex-row font-bold">{{ order?.features?.orderSource }}</div>
<div class="flex flex-row font-bold">
<shared-skeleton-loader class="w-32" *ngIf="fetchingOrder$ | async; else orderSourceTmpl"></shared-skeleton-loader>
<ng-template #orderSourceTmpl>
{{ order?.features?.orderSource }}
</ng-template>
</div>
</div>
<div
class="flex flex-row page-pickup-shelf-details-header__change-date justify-between"
@@ -137,21 +148,18 @@
data-detail-id="Benachrichtigung"
>
<div class="min-w-[9rem]">Benachrichtigung</div>
<div class="flex flex-row font-bold">{{ (notificationsChannel$ | async | notificationsChannel) || '-' }}</div>
<div class="flex flex-row font-bold">
<shared-skeleton-loader class="w-32" *ngIf="fetchingOrder$ | async; else notificationsChannelTpl"></shared-skeleton-loader>
<ng-template #notificationsChannelTpl>
{{ (notificationsChannel$ | async | notificationsChannel) || '-' }}
</ng-template>
</div>
</div>
</div>
</div>
</div>
</div>
<ng-template #featureLoading>
<div class="fetch-wrapper">
<div class="fetching"></div>
<div class="fetching"></div>
<div class="fetching"></div>
</div>
</ng-template>
<ng-template #abholfrist>
<div class="min-w-[9rem]">Abholfrist</div>
<div *ngIf="!(changeDateLoader$ | async)" class="flex flex-row font-bold">

View File

@@ -12,6 +12,7 @@ import { PickupShelfNotificationsChannelPipe } from '../pipes/notifications-chan
import { PickupShelfProcessingStatusPipe } from '../pipes/processing-status.pipe';
import { UiDatepickerModule } from '@ui/datepicker';
import { PickUpShelfDetailsHeaderNavMenuComponent } from '../pickup-shelf-details-header-nav-menu/pickup-shelf-details-header-nav-menu.component';
import { SkeletonLoaderComponent } from '@shared/components/loader';
@Component({
selector: 'page-pickup-shelf-details-header',
@@ -36,6 +37,7 @@ import { PickUpShelfDetailsHeaderNavMenuComponent } from '../pickup-shelf-detail
UiCommonModule,
UiDatepickerModule,
PickUpShelfDetailsHeaderNavMenuComponent,
SkeletonLoaderComponent,
],
})
export class PickUpShelfDetailsHeaderComponent {
@@ -50,6 +52,8 @@ export class PickUpShelfDetailsHeaderComponent {
@Output()
updateDate = new EventEmitter<{ date: Date; type?: 'delivery' | 'pickup' | 'preferred' }>();
fetchingOrder$ = this._store.fetchingOrder$;
get order$(): Observable<OrderDTO> {
return this._store.order$;
}
@@ -105,6 +109,8 @@ export class PickUpShelfDetailsHeaderComponent {
changeDateDisabled$ = this.changeStatusDisabled$;
fetchingCustomerDone$ = this._store.fetchingCustomer$.pipe(map((fetchingCustomer) => !fetchingCustomer));
customer$ = this._store.customer$;
features$ = this.customer$.pipe(

View File

@@ -3,7 +3,7 @@
[routerLink]="itemDetailsLink"
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
queryParamsHandling="preserve"
(click)="isDesktopLarge ? scrollIntoView() : ''"
(click)="onDetailsClick()"
>
<div
class="page-pickup-shelf-list-item__item-grid-container"

View File

@@ -10,6 +10,7 @@ import { PickupShelfProcessingStatusPipe } from '../pipes/processing-status.pipe
import { FormsModule } from '@angular/forms';
import { PickupShelfStore } from '../../store';
import { map } from 'rxjs/operators';
import { CacheService } from '@core/cache';
@Component({
selector: 'page-pickup-shelf-list-item',
@@ -34,6 +35,8 @@ import { map } from 'rxjs/operators';
providers: [PickupShelfProcessingStatusPipe],
})
export class PickUpShelfListItemComponent {
private cache = inject(CacheService);
store = inject(PickupShelfStore);
@Input() item: DBHOrderItemListItemDTO;
@@ -85,6 +88,45 @@ export class PickUpShelfListItemComponent {
private _processingStatusPipe: PickupShelfProcessingStatusPipe
) {}
onDetailsClick() {
if (this.isDesktopLarge) {
this.scrollIntoView();
}
if (!this.hasOrderItemInCache()) {
this.addOrderItemIntoCache();
}
}
hasOrderItemInCache() {
const items =
this.cache.get<DBHOrderItemListItemDTO[]>({
name: 'orderItems',
orderId: this.item.orderId,
compartmentCode: this.item.compartmentCode,
compartmentInfo: this.item.compartmentInfo,
orderItemProcessingStatus: this.item.processingStatus,
store: 'PickupShelfDetailsStore',
}) ?? [];
return items.some((i) => i.orderItemSubsetId === this.item.orderItemSubsetId);
}
addOrderItemIntoCache() {
this.cache.set(
{
name: 'orderItems',
orderId: this.item.orderId,
compartmentCode: this.item.compartmentCode,
compartmentInfo: this.item.compartmentInfo,
orderItemProcessingStatus: this.item.processingStatus,
store: 'PickupShelfDetailsStore',
},
[this.item],
{ persist: false, ttl: 1000 }
);
}
scrollIntoView() {
this._elRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
}

View File

@@ -18,7 +18,7 @@ import {
} from '@swagger/oms';
import { PickupShelfIOService, PickupShelfService } from '@domain/pickup-shelf';
import { Injectable, inject } from '@angular/core';
import { debounceTime, delayWhen, distinctUntilChanged, filter, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
import { delayWhen, filter, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
import { UiModalService } from '@ui/modal';
import { CrmCustomerService } from '@domain/crm';
import * as Selectors from './pickup-shelf-details.selectors';
@@ -27,7 +27,6 @@ import { CacheService } from '@core/cache';
import { RunCheckTrigger } from '../trigger';
import { DomainReceiptService } from '@domain/oms';
import { PickupShelfStore } from './pickup-shelf.store';
import { isEqual } from 'lodash';
@Injectable()
export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsState> {
@@ -340,6 +339,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
fetchOrder = this.effect((trigger$: Observable<{ orderId: number }>) =>
trigger$.pipe(
tap(({ orderId }) => this.beforeFetchOrder(orderId)),
// delay(10000),
switchMap(({ orderId }) =>
this._pickupShelfService.getOrderByOrderId(orderId).pipe(tapResponse(this.fetchOrderSuccess, this.fetchOrderFailed))
)
@@ -347,7 +347,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
);
private beforeFetchOrder = (orderId) => {
const order = this._cacheService.get<OrderDTO>({ name: 'order', orderId, store: 'PickupShelfDetailsStore' });
const order = this._cacheService.get<OrderDTO>({ name: 'order', orderId, store: 'PickupShelfDetailsStore' }) ?? { id: orderId };
const customer = this._cacheService.get<CustomerInfoDTO>({
name: 'customer',
orderId,
@@ -480,7 +480,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
fetchCustomer = this.effect((trigger$: Observable<{ buyerNumber: string }>) =>
trigger$.pipe(
filter(({ buyerNumber }) => this.customer?.customerNumber !== buyerNumber),
tap(this.beforeFetchCustomer),
tap(() => this.beforeFetchCustomer()),
switchMap(({ buyerNumber }) =>
this._customerService.getCustomers(buyerNumber).pipe(tapResponse(this.fetchCustomerSuccess, this.fetchCustomerFailed))
)
@@ -493,7 +493,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
orderId: this.order.id,
store: 'PickupShelfDetailsStore',
});
this.patchState({ fetchingCustomer: true, customer });
this.patchState({ fetchingCustomer: !customer, customer: customer });
};
fetchCustomerSuccess = (res: ListResponseArgsOfCustomerInfoDTO) => {
@@ -502,6 +502,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
// check if response contains exactly one customer
if (customers.length > 1) {
this._modal.error('Fehler beim Laden des Kunden', new Error('Es wurde mehr als ein Kunde gefunden.'));
this.patchState({ fetchingCustomer: false });
return;
}
@@ -518,6 +519,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
// also check if the order is a KulturPass order, then there may be no customer
if (!isKulturpass && customer?.customerNumber !== this.order.buyer.buyerNumber) {
this._modal.error('Fehler beim Laden des Kunden', new Error('Der Kunde ist nicht der Bestellung zugeordnet.'));
this.patchState({ fetchingCustomer: false });
return;
}

View File

@@ -11,6 +11,7 @@ import { UiTooltipModule } from '@ui/tooltip';
import { UiCommonModule } from '@ui/common';
import { UiDropdownModule } from '@ui/dropdown';
import { UiIconModule } from '@ui/icon';
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
@NgModule({
imports: [
@@ -25,6 +26,7 @@ import { UiIconModule } from '@ui/icon';
UiTooltipModule,
UiDropdownModule,
UiIconModule,
SharedProductGroupPipe,
],
exports: [AddProductModalComponent],
declarations: [AddProductModalComponent],

View File

@@ -1,2 +1 @@
export * from './product-group.pipe';
export * from './remission-pipe.module';

View File

@@ -1,11 +1,10 @@
import { NgModule } from '@angular/core';
import { AssortmentPipe } from './assortment.pipe';
import { ProductGroupPipe } from './product-group.pipe';
import { ShortReceiptNumberPipe } from './short-receipt-number.pipe';
import { SupplierPipe } from './supplier.pipe';
@NgModule({
declarations: [ProductGroupPipe, AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
exports: [ProductGroupPipe, AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
declarations: [AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
exports: [AssortmentPipe, ShortReceiptNumberPipe, SupplierPipe],
})
export class RemissionPipeModule {}

View File

@@ -8,6 +8,7 @@ import { UiTooltipModule } from '@ui/tooltip';
import { UiCommonModule } from '@ui/common';
import { AddProductToShippingDocumentModalModule } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.module';
import { UiSpinnerModule } from '@ui/spinner';
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
@NgModule({
imports: [
@@ -18,6 +19,7 @@ import { UiSpinnerModule } from '@ui/spinner';
RemissionPipeModule,
UiTooltipModule,
AddProductToShippingDocumentModalModule,
SharedProductGroupPipe,
],
exports: [RemissionListItemComponent],
declarations: [RemissionListItemComponent],

View File

@@ -5,9 +5,10 @@ import { UiSpinnerModule } from '@ui/spinner';
import { RemissionPipeModule } from '../../pipes';
import { SharedShippingDocumentDetailsItemComponent } from './shipping-document-details-item/shipping-document-details-item.component';
import { SharedShippingDocumentDetailsComponent } from './shipping-document-details.component';
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
@NgModule({
imports: [CommonModule, RemissionPipeModule, ProductImageModule, UiSpinnerModule],
imports: [CommonModule, RemissionPipeModule, ProductImageModule, UiSpinnerModule, SharedProductGroupPipe],
exports: [SharedShippingDocumentDetailsComponent, SharedShippingDocumentDetailsItemComponent],
declarations: [SharedShippingDocumentDetailsComponent, SharedShippingDocumentDetailsItemComponent],
providers: [],

View File

@@ -18,7 +18,21 @@
<div class="goods-in-out-order-group-item-details-thumbnail">
<img loading="lazy" *ngIf="item?.product?.ean | productImage; let productImage" [src]="productImage" [alt]="item?.product?.name" />
</div>
<div class="goods-in-out-order-group-item-details-data">
<div data-which="item-details-data" class="goods-in-out-order-group-item-details-data">
<div
data-what="product-group"
*ngIf="item?.product?.productGroup"
class="goods-in-out-order-group-item-details__product-group flex flex-row justify-end items-center text-p3"
>
{{ item?.product?.productGroup }}: {{ item?.product?.productGroup | productGroup }}
</div>
<div
*ngIf="compartmentFromStock"
data-what="compartment"
class="goods-in-out-order-group-item-details__compartment flex flex-row justify-end items-center text-p3"
>
{{ compartmentFromStock }}
</div>
<div class="item-top-row">
<div class="item-title">{{ [item.product.contributors, item.product.name] | title }}</div>
<div class="item-processing-status">

View File

@@ -78,7 +78,15 @@ export class GoodsInOutOrderGroupItemComponent extends ComponentStore<GoodsInOut
showSupplier: boolean;
@Input()
showInStock: StockInfoDTO[];
showInStock?: StockInfoDTO[];
get stockInfoForItem() {
return this.showInStock?.find((stock) => stock?.ean === this.item?.product?.ean);
}
get compartmentFromStock() {
return this.stockInfoForItem?.compartment;
}
get cruda() {
return (this.item as any)?.cruda;

View File

@@ -10,6 +10,7 @@ import { UiSelectBulletModule } from '@ui/select-bullet';
import { FormsModule } from '@angular/forms';
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
import { SharedProductGroupPipe } from '@shared/pipes/product-group';
@NgModule({
imports: [
@@ -21,6 +22,7 @@ import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
FormsModule,
UiQuantityDropdownModule,
UiSpinnerModule,
SharedProductGroupPipe,
],
exports: [GoodsInOutOrderGroupComponent, GoodsInOutOrderGroupItemComponent],
declarations: [GoodsInOutOrderGroupComponent, GoodsInOutOrderGroupItemComponent],

View File

@@ -1,16 +1,20 @@
:host {
@apply inline-block min-h-[1rem] min-w-[2rem] bg-gray-500;
@apply inline-block min-h-[1rem] min-w-[2rem] overflow-hidden rounded;
background: rgb(238, 238, 238);
}
.gr-bar {
@apply w-full h-full;
animation: load 1s ease-in-out infinite;
background: linear-gradient(75deg, rgba(238, 238, 238, 1) 0%, rgba(190, 190, 190, 1) 50%, rgba(238, 238, 238, 1) 100%);
}
@keyframes load {
0% {
opacity: 0;
}
30% {
opacity: 0.5;
transform: translateX(-100%);
}
100% {
opacity: 0;
transform: translateX(100%);
}
}

View File

@@ -0,0 +1 @@
<div class="gr-bar"></div>

View File

@@ -0,0 +1,6 @@
{
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@@ -6,8 +6,9 @@ import { distinctUntilChanged, map, switchMap } from 'rxjs/operators';
@Pipe({
name: 'productGroup',
pure: false,
standalone: true,
})
export class ProductGroupPipe implements PipeTransform, OnDestroy {
export class SharedProductGroupPipe implements PipeTransform, OnDestroy {
result: string;
productGroup$ = new Subject<string>();

View File

@@ -0,0 +1 @@
export * from './lib/product-group.pipe';