Merged PR 1996: fix(crm): consolidate customer feature selection logic

fix(crm): consolidate customer feature selection logic

Introduce centralized `getEnabledCustomerFeature` helper to standardize
feature selection across components. Replaces inconsistent filtering
approaches with unified logic that prioritizes 'd-account' and
'd-no-account' features.

Changes:
- Add `getEnabledCustomerFeature` helper with unit tests
- Add `CustomerFeatureKey` and `CustomerFeatureGroup` enums
- Update customer-order-details-header component
- Update pickup-shelf-details-header component
- Update customer-result-list components
- Update order-details-main-view component

Ref: #5432
This commit is contained in:
Nino Righi
2025-11-03 10:00:02 +00:00
committed by Lorenz Hilpert
parent 7a04b828c3
commit f175b5d2af
14 changed files with 1019 additions and 164 deletions

View File

@@ -1,9 +1,14 @@
<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">
<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="customerFeature$ | async; let feature; else: featureLoading"
>
<shared-icon *ngIf="!!feature" [size]="24" icon="person"></shared-icon>
<div class="grid grid-flow-col gap-2 items-center font-bold text-p2">
{{ feature?.description }}
</div>
</div>
@@ -18,29 +23,54 @@
</button>
</div>
<div class="page-customer-order-details-header__details bg-white px-4 pt-4 pb-5">
<div
class="page-customer-order-details-header__details bg-white px-4 pt-4 pb-5"
>
<h2
class="page-customer-order-details-header__details-header items-center"
[class.mb-8]="!orderItem?.features?.paid && !isKulturpass"
>
<div class="text-h2">
{{ orderItem?.organisation }}
<ng-container *ngIf="!!orderItem?.organisation && (!!orderItem?.firstName || !!orderItem?.lastName)">-</ng-container>
<ng-container
*ngIf="
!!orderItem?.organisation &&
(!!orderItem?.firstName || !!orderItem?.lastName)
"
>-</ng-container
>
{{ orderItem?.lastName }}
{{ orderItem?.firstName }}
</div>
<div class="page-customer-order-details-header__header-compartment text-h3">
{{ orderItem?.compartmentCode }}{{ orderItem?.compartmentInfo && '_' + orderItem?.compartmentInfo }}
<div
class="page-customer-order-details-header__header-compartment text-h3"
>
{{ orderItem?.compartmentCode
}}{{ orderItem?.compartmentInfo && '_' + orderItem?.compartmentInfo }}
</div>
</h2>
<div class="page-customer-order-details-header__paid-marker mt-[0.375rem]" *ngIf="orderItem?.features?.paid && !isKulturpass">
<div class="font-bold w-fit desktop-small:text-p2 px-3 py-[0.125rem] rounded text-white bg-[#26830C]">
<div
class="page-customer-order-details-header__paid-marker mt-[0.375rem]"
*ngIf="orderItem?.features?.paid && !isKulturpass"
>
<div
class="font-bold w-fit desktop-small:text-p2 px-3 py-[0.125rem] rounded text-white bg-[#26830C]"
>
{{ orderItem?.features?.paid }}
</div>
</div>
<div class="page-customer-order-details-header__paid-marker mt-[0.375rem] text-[#26830C]" *ngIf="isKulturpass">
<svg class="fill-current mr-2" xmlns="http://www.w3.org/2000/svg" height="22" viewBox="0 -960 960 960" width="22">
<div
class="page-customer-order-details-header__paid-marker mt-[0.375rem] text-[#26830C]"
*ngIf="isKulturpass"
>
<svg
class="fill-current mr-2"
xmlns="http://www.w3.org/2000/svg"
height="22"
viewBox="0 -960 960 960"
width="22"
>
<path
d="M880-740v520q0 24-18 42t-42 18H140q-24 0-42-18t-18-42v-520q0-24 18-42t42-18h680q24 0 42 18t18 42ZM140-631h680v-109H140v109Zm0 129v282h680v-282H140Zm0 282v-520 520Z"
/>
@@ -49,25 +79,49 @@
</div>
<div class="page-customer-order-details-header__details-wrapper -mt-3">
<div class="flex flex-row page-customer-order-details-header__buyer-number" data-detail-id="Kundennummer">
<div
class="flex flex-row page-customer-order-details-header__buyer-number"
data-detail-id="Kundennummer"
>
<div class="min-w-[9rem]">Kundennummer</div>
<div class="flex flex-row font-bold">{{ orderItem?.buyerNumber }}</div>
<div class="flex flex-row font-bold">
{{ orderItem?.buyerNumber }}
</div>
</div>
<div class="flex flex-row page-customer-order-details-header__order-number" data-detail-id="VorgangId">
<div
class="flex flex-row page-customer-order-details-header__order-number"
data-detail-id="VorgangId"
>
<div class="min-w-[9rem]">Vorgang-ID</div>
<div class="flex flex-row font-bold">{{ orderItem?.orderNumber }}</div>
<div class="flex flex-row font-bold">
{{ orderItem?.orderNumber }}
</div>
</div>
<div class="flex flex-row page-customer-order-details-header__order-date" data-detail-id="Bestelldatum">
<div
class="flex flex-row page-customer-order-details-header__order-date"
data-detail-id="Bestelldatum"
>
<div class="min-w-[9rem]">Bestelldatum</div>
<div class="flex flex-row font-bold">{{ orderItem?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
<div class="flex flex-row font-bold">
{{ orderItem?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr
</div>
</div>
<div class="flex flex-row page-customer-order-details-header__processing-status justify-between" data-detail-id="Status">
<div
class="flex flex-row page-customer-order-details-header__processing-status justify-between"
data-detail-id="Status"
>
<div class="min-w-[9rem]">Status</div>
<div *ngIf="!(changeStatusLoader$ | async)" class="flex flex-row font-bold -mr-[0.125rem]">
<div
*ngIf="!(changeStatusLoader$ | async)"
class="flex flex-row font-bold -mr-[0.125rem]"
>
<shared-icon
class="mr-2 text-black flex items-center justify-center"
[size]="16"
*ngIf="orderItem.processingStatus | processingStatus: 'icon'; let icon"
*ngIf="
orderItem.processingStatus | processingStatus: 'icon';
let icon
"
[icon]="icon"
></shared-icon>
@@ -91,18 +145,36 @@
icon="arrow-drop-down"
></shared-icon>
</button>
<ui-dropdown #statusDropdown yPosition="below" xPosition="after" [xOffset]="8">
<button uiDropdownItem *ngFor="let action of statusActions$ | async" (click)="handleActionClick(action)">
<ui-dropdown
#statusDropdown
yPosition="below"
xPosition="after"
[xOffset]="8"
>
<button
uiDropdownItem
*ngFor="let action of statusActions$ | async"
(click)="handleActionClick(action)"
>
{{ action.label }}
</button>
</ui-dropdown>
</ng-container>
</div>
<ui-spinner *ngIf="changeStatusLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
<ui-spinner
*ngIf="changeStatusLoader$ | async; let loader"
class="flex flex-row font-bold loader"
[show]="loader"
></ui-spinner>
</div>
<div class="flex flex-row page-customer-order-details-header__order-source" data-detail-id="Bestellkanal">
<div
class="flex flex-row page-customer-order-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">
{{ order?.features?.orderSource }}
</div>
</div>
<div
class="flex flex-row page-customer-order-details-header__change-date justify-between"
@@ -124,26 +196,39 @@
<ng-template #changeDate>
<div class="min-w-[9rem]">Geändert</div>
<div class="flex flex-row font-bold">{{ orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
<div class="flex flex-row font-bold">
{{
orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm'
}}
Uhr
</div>
</ng-template>
</div>
<div
class="flex flex-row page-customer-order-details-header__pick-up justify-between"
data-detail-id="Wunschdatum"
*ngIf="orderItem.orderType === 1 && (orderItem.processingStatus === 16 || orderItem.processingStatus === 8192)"
*ngIf="
orderItem.orderType === 1 &&
(orderItem.processingStatus === 16 ||
orderItem.processingStatus === 8192)
"
>
<ng-container *ngTemplateOutlet="preferredPickUpDate"></ng-container>
</div>
<div class="flex flex-col page-customer-order-details-header__dig-and-notification">
<div
class="flex flex-col page-customer-order-details-header__dig-and-notification"
>
<div
*ngIf="orderItem.orderType === 1"
class="flex flex-row page-customer-order-details-header__notification"
data-detail-id="Benachrichtigung"
>
<div class="min-w-[9rem]">Benachrichtigung</div>
<div class="flex flex-row font-bold">{{ (notificationsChannel | notificationsChannel) || '-' }}</div>
<div class="flex flex-row font-bold">
{{ (notificationsChannel | notificationsChannel) || '-' }}
</div>
</div>
<div
@@ -162,38 +247,50 @@
<div *ngIf="showFeature" class="flex flex-row items-center mr-3">
<ng-container [ngSwitch]="order.features.orderType">
<ng-container *ngSwitchCase="'Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<div
class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2"
>
<shared-icon [size]="24" icon="isa-truck"></shared-icon>
</div>
<p class="font-bold text-p1">Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'DIG-Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<div
class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2"
>
<shared-icon [size]="24" icon="isa-truck"></shared-icon>
</div>
<p class="font-bold text-p1">Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'B2B-Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<div
class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2"
>
<shared-icon [size]="24" icon="isa-b2b-truck"></shared-icon>
</div>
<p class="font-bold text-p1">B2B-Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'Abholung'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<div
class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2"
>
<shared-icon [size]="24" icon="isa-box-out"></shared-icon>
</div>
<p class="font-bold text-p1 mr-3">Abholung</p>
{{ orderItem.targetBranch }}
</ng-container>
<ng-container *ngSwitchCase="'Rücklage'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<div
class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2"
>
<shared-icon [size]="24" icon="isa-shopping-bag"></shared-icon>
</div>
<p class="font-bold text-p1">Rücklage</p>
</ng-container>
<ng-container *ngSwitchCase="'Download'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<div
class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2"
>
<shared-icon [size]="24" icon="isa-download"></shared-icon>
</div>
<p class="font-bold text-p1">Download</p>
@@ -201,50 +298,93 @@
</ng-container>
</div>
<div class="page-customer-order-details-header__additional-addresses" *ngIf="showAddresses">
<div
class="page-customer-order-details-header__additional-addresses"
*ngIf="showAddresses"
>
<button (click)="openAddresses = !openAddresses" class="text-[#0556B4]">
Lieferadresse / Rechnungsadresse {{ openAddresses ? 'ausblenden' : 'anzeigen' }}
Lieferadresse / Rechnungsadresse
{{ openAddresses ? 'ausblenden' : 'anzeigen' }}
</button>
<div class="page-customer-order-details-header__addresses-popover" *ngIf="openAddresses">
<div
class="page-customer-order-details-header__addresses-popover"
*ngIf="openAddresses"
>
<button (click)="openAddresses = !openAddresses" class="close">
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
<div class="page-customer-order-details-header__addresses-popover-data">
<div *ngIf="order.shipping" class="page-customer-order-details-header__addresses-popover-delivery">
<div
class="page-customer-order-details-header__addresses-popover-data"
>
<div
*ngIf="order.shipping"
class="page-customer-order-details-header__addresses-popover-delivery"
>
<p>Lieferadresse</p>
<div class="page-customer-order-details-header__addresses-popover-delivery-data">
<div
class="page-customer-order-details-header__addresses-popover-delivery-data"
>
<ng-container *ngIf="order.shipping?.data?.organisation">
<p>{{ order.shipping?.data?.organisation?.name }}</p>
<p>{{ order.shipping?.data?.organisation?.department }}</p>
</ng-container>
<p>{{ order.shipping?.data?.firstName }} {{ order.shipping?.data?.lastName }}</p>
<p>
{{ order.shipping?.data?.firstName }}
{{ order.shipping?.data?.lastName }}
</p>
<p>{{ order.shipping?.data?.address?.info }}</p>
<p>{{ order.shipping?.data?.address?.street }} {{ order.shipping?.data?.address?.streetNumber }}</p>
<p>{{ order.shipping?.data?.address?.zipCode }} {{ order.shipping?.data?.address?.city }}</p>
<p>
{{ order.shipping?.data?.address?.street }}
{{ order.shipping?.data?.address?.streetNumber }}
</p>
<p>
{{ order.shipping?.data?.address?.zipCode }}
{{ order.shipping?.data?.address?.city }}
</p>
</div>
</div>
<div *ngIf="order.billing" class="page-customer-order-details-header__addresses-popover-billing">
<div
*ngIf="order.billing"
class="page-customer-order-details-header__addresses-popover-billing"
>
<p>Rechnungsadresse</p>
<div class="page-customer-order-details-header__addresses-popover-billing-data">
<div
class="page-customer-order-details-header__addresses-popover-billing-data"
>
<ng-container *ngIf="order.billing?.data?.organisation">
<p>{{ order.billing?.data?.organisation?.name }}</p>
<p>{{ order.billing?.data?.organisation?.department }}</p>
</ng-container>
<p>{{ order.billing?.data?.firstName }} {{ order.billing?.data?.lastName }}</p>
<p>
{{ order.billing?.data?.firstName }}
{{ order.billing?.data?.lastName }}
</p>
<p>{{ order.billing?.data?.address?.info }}</p>
<p>{{ order.billing?.data?.address?.street }} {{ order.billing?.data?.address?.streetNumber }}</p>
<p>{{ order.billing?.data?.address?.zipCode }} {{ order.billing?.data?.address?.city }}</p>
<p>
{{ order.billing?.data?.address?.street }}
{{ order.billing?.data?.address?.streetNumber }}
</p>
<p>
{{ order.billing?.data?.address?.zipCode }}
{{ order.billing?.data?.address?.city }}
</p>
</div>
</div>
</div>
</div>
</div>
<div class="page-customer-order-details-header__select grow" *ngIf="showMultiselect$ | async">
<button class="cta-select-all" (click)="selectAll()">Alle auswählen</button>
{{ selectedOrderItemCount$ | async }} von {{ orderItemCount$ | async }} Titeln
<div
class="page-customer-order-details-header__select grow"
*ngIf="showMultiselect$ | async"
>
<button class="cta-select-all" (click)="selectAll()">
Alle auswählen
</button>
{{ selectedOrderItemCount$ | async }} von
{{ orderItemCount$ | async }} Titeln
</div>
</div>
</div>
@@ -263,13 +403,20 @@
<button
[uiOverlayTrigger]="deadlineDatepicker"
#deadlineDatepickerTrigger="uiOverlayTrigger"
[disabled]="!isKulturpass && (!!orderItem?.features?.paid || (changeDateDisabled$ | async))"
[disabled]="
!isKulturpass &&
(!!orderItem?.features?.paid || (changeDateDisabled$ | async))
"
class="cta-pickup-deadline"
>
<strong class="border-r border-[#AEB7C1] pr-4">
{{ orderItem?.pickUpDeadline | date: 'dd.MM.yy' }}
</strong>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
<shared-icon
class="text-[#596470] ml-4"
[size]="24"
icon="isa-calendar"
></shared-icon>
</button>
<ui-datepicker
#deadlineDatepicker
@@ -282,25 +429,46 @@
(save)="updatePickupDeadline($event)"
></ui-datepicker>
</div>
<ui-spinner *ngIf="changeDateLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
<ui-spinner
*ngIf="changeDateLoader$ | async; let loader"
class="flex flex-row font-bold loader"
[show]="loader"
></ui-spinner>
</ng-template>
<ng-template #preferredPickUpDate>
<div class="min-w-[9rem]">Zurücklegen bis</div>
<div *ngIf="!(changePreferredDateLoader$ | async)" class="flex flex-row font-bold">
<div
*ngIf="!(changePreferredDateLoader$ | async)"
class="flex flex-row font-bold"
>
<button
[uiOverlayTrigger]="preferredPickUpDatePicker"
#preferredPickUpDatePickerTrigger="uiOverlayTrigger"
[disabled]="(!isKulturpass && !!orderItem?.features?.paid) || (changeDateDisabled$ | async)"
[disabled]="
(!isKulturpass && !!orderItem?.features?.paid) ||
(changeDateDisabled$ | async)
"
class="cta-pickup-preferred"
>
<strong class="border-r border-[#AEB7C1] pr-4" *ngIf="preferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
<strong
class="border-r border-[#AEB7C1] pr-4"
*ngIf="
preferredPickUpDate$ | async;
let pickUpDate;
else: selectTemplate
"
>
{{ pickUpDate | date: 'dd.MM.yy' }}
</strong>
<ng-template #selectTemplate>
<strong class="border-r border-[#AEB7C1] pr-4">Auswählen</strong>
</ng-template>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
<shared-icon
class="text-[#596470] ml-4"
[size]="24"
icon="isa-calendar"
></shared-icon>
</button>
<ui-datepicker
#preferredPickUpDatePicker
@@ -313,7 +481,11 @@
(save)="updatePreferredPickUpDate($event)"
></ui-datepicker>
</div>
<ui-spinner *ngIf="changePreferredDateLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
<ui-spinner
*ngIf="changePreferredDateLoader$ | async; let loader"
class="flex flex-row font-bold loader"
[show]="loader"
></ui-spinner>
</ng-template>
<ng-template #vslLieferdatum>
@@ -328,7 +500,11 @@
<span class="border-r border-[#AEB7C1] pr-4">
{{ orderItem?.estimatedShippingDate | date: 'dd.MM.yy' }}
</span>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
<shared-icon
class="text-[#596470] ml-4"
[size]="24"
icon="isa-calendar"
></shared-icon>
</button>
<ui-datepicker
#uiDatepicker
@@ -341,6 +517,10 @@
(save)="updateEstimatedShippingDate($event)"
></ui-datepicker>
</div>
<ui-spinner *ngIf="changeDateLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
<ui-spinner
*ngIf="changeDateLoader$ | async; let loader"
class="flex flex-row font-bold loader"
[show]="loader"
></ui-spinner>
</ng-template>
</ng-container>

View File

@@ -11,12 +11,17 @@ import {
import { CrmCustomerService } from '@domain/crm';
import { DomainOmsService } from '@domain/oms';
import { NotificationChannel } from '@generated/swagger/checkout-api';
import { KeyValueDTOOfStringAndString, OrderDTO, OrderItemListItemDTO } from '@generated/swagger/oms-api';
import {
KeyValueDTOOfStringAndString,
OrderDTO,
OrderItemListItemDTO,
} from '@generated/swagger/oms-api';
import { DateAdapter } from '@ui/common';
import { cloneDeep } from 'lodash';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
import { CustomerOrderDetailsStore } from '../customer-order-details.store';
import { getEnabledCustomerFeature } from '@isa/crm/data-access';
@Component({
selector: 'page-customer-order-details-header',
@@ -39,14 +44,21 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
return this.order?.features?.orderSource === 'KulturPass';
}
minDateDatepicker = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -1);
minDateDatepicker = this.dateAdapter.addCalendarDays(
this.dateAdapter.today(),
-1,
);
today = this.dateAdapter.today();
selectedOrderItemCount$ = this._store.selectedeOrderItemSubsetIds$.pipe(map((ids) => ids?.length ?? 0));
selectedOrderItemCount$ = this._store.selectedeOrderItemSubsetIds$.pipe(
map((ids) => ids?.length ?? 0),
);
orderItemCount$ = this._store.items$.pipe(map((items) => items?.length ?? 0));
orderItem$ = this._store.items$.pipe(map((orderItems) => orderItems?.find((_) => true)));
orderItem$ = this._store.items$.pipe(
map((orderItems) => orderItems?.find((_) => true)),
);
preferredPickUpDate$ = new BehaviorSubject<Date>(undefined);
@@ -58,34 +70,54 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
changeStatusDisabled$ = this._store.changeActionDisabled$;
changeDateDisabled$ = this.changeStatusDisabled$;
features$ = this.orderItem$.pipe(
customerFeature$ = this.orderItem$.pipe(
filter((orderItem) => !!orderItem),
switchMap((orderItem) =>
this.customerService.getCustomers(orderItem.buyerNumber).pipe(
map((res) => res.result.find((c) => c.customerNumber === orderItem.buyerNumber)),
map((customer) => customer?.features || []),
map((features) => features.filter((f) => f.enabled && !!f.description)),
map((res) =>
res.result.find((c) => c.customerNumber === orderItem.buyerNumber),
),
map((customer) => getEnabledCustomerFeature(customer?.features)),
),
),
shareReplay(),
);
statusActions$ = this.orderItem$.pipe(
map((orderItem) => orderItem?.actions?.filter((action) => action.enabled === false)),
map((orderItem) =>
orderItem?.actions?.filter((action) => action.enabled === false),
),
);
showMultiselect$ = combineLatest([this._store.items$, this._store.fetchPartial$, this._store.itemsSelectable$]).pipe(
map(([orderItems, fetchPartial, multiSelect]) => multiSelect && fetchPartial && orderItems?.length > 1),
showMultiselect$ = combineLatest([
this._store.items$,
this._store.fetchPartial$,
this._store.itemsSelectable$,
]).pipe(
map(
([orderItems, fetchPartial, multiSelect]) =>
multiSelect && fetchPartial && orderItems?.length > 1,
),
);
crudaUpdate$ = this.orderItem$.pipe(map((orederItem) => !!(orederItem?.cruda & 4)));
crudaUpdate$ = this.orderItem$.pipe(
map((orederItem) => !!(orederItem?.cruda & 4)),
);
editButtonDisabled$ = combineLatest([this.changeStatusLoader$, this.crudaUpdate$]).pipe(
map(([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate),
editButtonDisabled$ = combineLatest([
this.changeStatusLoader$,
this.crudaUpdate$,
]).pipe(
map(
([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate,
),
);
canEditStatus$ = combineLatest([this.statusActions$, this.crudaUpdate$]).pipe(
map(([statusActions, crudaUpdate]) => statusActions?.length > 0 && crudaUpdate),
map(
([statusActions, crudaUpdate]) =>
statusActions?.length > 0 && crudaUpdate,
),
);
openAddresses: boolean = false;
@@ -96,7 +128,8 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
get showAddresses(): boolean {
return (
(this.order?.orderType === 2 || this.order?.orderType === 4) && (!!this.order?.shipping || !!this.order?.billing)
(this.order?.orderType === 2 || this.order?.orderType === 4) &&
(!!this.order?.shipping || !!this.order?.billing)
);
}
@@ -130,10 +163,20 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
this.changeStatusDisabled$.next(true);
const orderItems = cloneDeep(this._store.items);
for (const item of orderItems) {
if (this.dateAdapter.compareDate(deadline, new Date(item.pickUpDeadline)) !== 0) {
if (
this.dateAdapter.compareDate(
deadline,
new Date(item.pickUpDeadline),
) !== 0
) {
try {
const res = await this.omsService
.setPickUpDeadline(item.orderId, item.orderItemId, item.orderItemSubsetId, deadline?.toISOString())
.setPickUpDeadline(
item.orderId,
item.orderItemId,
item.orderItemSubsetId,
deadline?.toISOString(),
)
.pipe(first())
.toPromise();
item.pickUpDeadline = deadline.toISOString();
@@ -152,7 +195,12 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
this.changeStatusDisabled$.next(true);
const orderItems = cloneDeep(this._store.items);
for (const item of orderItems) {
if (this.dateAdapter.compareDate(estimatedShippingDate, new Date(item.pickUpDeadline)) !== 0) {
if (
this.dateAdapter.compareDate(
estimatedShippingDate,
new Date(item.pickUpDeadline),
) !== 0
) {
try {
const res = await this.omsService
.setEstimatedShippingDate(
@@ -198,7 +246,10 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
try {
await this.omsService.setPreferredPickUpDate({ data }).toPromise();
this.order.items.forEach((item) => {
item.data.subsetItems.forEach((subsetItem) => (subsetItem.data.preferredPickUpDate = date.toISOString()));
item.data.subsetItems.forEach(
(subsetItem) =>
(subsetItem.data.preferredPickUpDate = date.toISOString()),
);
});
this.findLatestPreferredPickUpDate();
} catch (error) {
@@ -218,7 +269,10 @@ export class CustomerOrderDetailsHeaderComponent implements OnChanges {
if (subsetItems?.length > 0) {
latestDate = new Date(
subsetItems?.reduce((a, b) => {
return new Date(a.data.preferredPickUpDate) > new Date(b.data.preferredPickUpDate) ? a : b;
return new Date(a.data.preferredPickUpDate) >
new Date(b.data.preferredPickUpDate)
? a
: b;
})?.data?.preferredPickUpDate,
);
}

View File

@@ -1,6 +1,7 @@
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { CustomerInfoDTO } from '@generated/swagger/crm-api';
import { CustomerLabelColor, CustomerLabelTextColor } from '../../../constants';
import { getEnabledCustomerFeature } from '@isa/crm/data-access';
@Component({
selector: 'page-customer-result-list-item-full',
@@ -15,7 +16,7 @@ export class CustomerResultListItemFullComponent {
customerLabelTextColor = CustomerLabelTextColor;
get label() {
return this.customer?.features?.find((f) => f.enabled);
return getEnabledCustomerFeature(this.customer?.features);
}
@Input()

View File

@@ -1,6 +1,7 @@
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { CustomerInfoDTO } from '@generated/swagger/crm-api';
import { CustomerLabelColor, CustomerLabelTextColor } from '../../../constants';
import { getEnabledCustomerFeature } from '@isa/crm/data-access';
@Component({
selector: 'page-customer-result-list-item',
@@ -15,7 +16,7 @@ export class CustomerResultListItemComponent {
customerLabelTextColor = CustomerLabelTextColor;
get label() {
return this.customer?.features?.find((f) => f.enabled);
return getEnabledCustomerFeature(this.customer?.features);
}
@Input()

View File

@@ -1,4 +1,10 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject } from '@angular/core';
import {
Component,
ChangeDetectionStrategy,
OnInit,
OnDestroy,
inject,
} from '@angular/core';
import { CustomerSearchStore } from '../store';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { map, takeUntil, tap } from 'rxjs/operators';
@@ -21,6 +27,7 @@ import { CustomerSearchNavigation } from '@shared/services/navigation';
import { CustomerOrderItemListItemComponent } from './order-item-list-item/order-item-list-item.component';
import { groupBy } from '@ui/common';
import { EnvironmentService } from '@core/environment';
import { getEnabledCustomerFeature } from '@isa/crm/data-access';
@Component({
selector: 'page-customer-order-details-main-view',
@@ -52,38 +59,58 @@ export class OrderDetailsMainViewComponent implements OnInit, OnDestroy {
private _navigation = inject(CustomerSearchNavigation);
private _env = inject(EnvironmentService);
orderId$ = this._activateRoute.params.pipe(map((params) => Number(params.orderId)));
orderId$ = this._activateRoute.params.pipe(
map((params) => Number(params.orderId)),
);
order$ = this._store.order$;
orderTargetBranch$ = this.order$.pipe(map((order) => order?.targetBranch?.id));
orderTargetBranch$ = this.order$.pipe(
map((order) => order?.targetBranch?.id),
);
orderShippingTarget$ = this.order$.pipe(map((order) => order?.shipping?.data));
orderShippingTarget$ = this.order$.pipe(
map((order) => order?.shipping?.data),
);
customerId$ = this._activateRoute.params.pipe(map((params) => Number(params.customerId)));
customerId$ = this._activateRoute.params.pipe(
map((params) => Number(params.customerId)),
);
customer$ = this._store.customer$;
accountType$ = this.customer$.pipe(
map((customer) => customer?.features?.find((feature) => feature.group === 'd-customertype')),
map((customer) => getEnabledCustomerFeature(customer?.features)),
);
accountTypeKey$ = this.accountType$.pipe(map((accountType) => accountType?.key));
accountTypeKey$ = this.accountType$.pipe(
map((accountType) => accountType?.key),
);
accountTypeDescription$ = this.accountType$.pipe(map((accountType) => accountType?.description));
accountTypeDescription$ = this.accountType$.pipe(
map((accountType) => accountType?.description),
);
orderItemId$ = this._activateRoute.params.pipe(map((params) => Number(params.orderItemId)));
orderItemId$ = this._activateRoute.params.pipe(
map((params) => Number(params.orderItemId)),
);
orderItems$ = this.order$.pipe(map((order) => order?.items?.map((i) => i?.data)));
orderItems$ = this.order$.pipe(
map((order) => order?.items?.map((i) => i?.data)),
);
selectedOrderItem$ = this._store.selectedOrderItem$;
selectedOrderItemOrderType$ = this.selectedOrderItem$.pipe(map((orderItem) => orderItem?.features?.orderType));
selectedOrderItemOrderType$ = this.selectedOrderItem$.pipe(
map((orderItem) => orderItem?.features?.orderType),
);
private _onDestroy = new Subject<void>();
ordersRoute$ = combineLatest([this.customerId$, this._store.processId$]).pipe(
map(([customerId, processId]) => this._navigation.ordersRoute({ processId, customerId })),
map(([customerId, processId]) =>
this._navigation.ordersRoute({ processId, customerId }),
),
);
orderDetailsHistoryRoute$ = combineLatest([
@@ -93,27 +120,38 @@ export class OrderDetailsMainViewComponent implements OnInit, OnDestroy {
this.orderItemId$,
]).pipe(
map(([customerId, processId, orderId, orderItemId]) =>
this._navigation.orderDetailsHistoryRoute({ processId, customerId, orderId, orderItemId }),
this._navigation.orderDetailsHistoryRoute({
processId,
customerId,
orderId,
orderItemId,
}),
),
);
groupedOrderItemsByOrderType$ = this.orderItems$.pipe(
map((orderItems) => groupBy(orderItems, (orderItem) => orderItem?.features?.orderType)),
map((orderItems) =>
groupBy(orderItems, (orderItem) => orderItem?.features?.orderType),
),
tap((groupedOrderItems) => console.log(groupedOrderItems)),
);
showSelectedItem$ = this._env.matchDesktopXLarge$;
showItemList$ = this.showSelectedItem$.pipe(map((showSelectedItem) => !showSelectedItem));
showItemList$ = this.showSelectedItem$.pipe(
map((showSelectedItem) => !showSelectedItem),
);
ngOnInit(): void {
this.orderId$.pipe(takeUntil(this._onDestroy)).subscribe((orderId) => {
this._store.selectOrder(orderId);
});
this.customerId$.pipe(takeUntil(this._onDestroy)).subscribe((customerId) => {
this._store.selectCustomer({ customerId });
});
this.customerId$
.pipe(takeUntil(this._onDestroy))
.subscribe((customerId) => {
this._store.selectCustomer({ customerId });
});
}
ngOnDestroy(): void {

View File

@@ -1,10 +1,19 @@
<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="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">
<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="fetchingCustomerDone$ | async; else featureLoading"
>
<ng-container *ngIf="customerFeature$ | async; let feature">
<shared-icon
*ngIf="!!feature"
[size]="24"
icon="person"
></shared-icon>
<div class="grid grid-flow-col gap-2 items-center font-bold text-p2">
{{ feature?.description }}
</div>
</ng-container>
@@ -27,30 +36,69 @@
<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>
<h2 class="page-pickup-shelf-details-header__details-header items-center">
<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>
<h2
class="page-pickup-shelf-details-header__details-header items-center"
>
<div class="text-h2">
{{ orderItem?.organisation }}
<ng-container *ngIf="!!orderItem?.organisation && (!!orderItem?.firstName || !!orderItem?.lastName)">-</ng-container>
<ng-container
*ngIf="
!!orderItem?.organisation &&
(!!orderItem?.firstName || !!orderItem?.lastName)
"
>-</ng-container
>
{{ orderItem?.lastName }}
{{ orderItem?.firstName }}
</div>
<div class="page-pickup-shelf-details-header__header-compartment text-h3">
{{ orderItem?.compartmentCode }}{{ orderItem?.compartmentInfo && '_' + orderItem?.compartmentInfo }}
<div
class="page-pickup-shelf-details-header__header-compartment text-h3"
>
{{ orderItem?.compartmentCode
}}{{
orderItem?.compartmentInfo && '_' + orderItem?.compartmentInfo
}}
</div>
</h2>
</div>
<div class="page-pickup-shelf-details-header__paid-marker mt-[0.375rem]" *ngIf="orderItem?.features?.paid && !isKulturpass">
<div class="font-bold flex flex-row items-center justify-center text-p2 text-[#26830C]">
<shared-icon class="flex items-center justify-center mr-[0.375rem]" [size]="24" icon="credit-card"></shared-icon>
<div
class="page-pickup-shelf-details-header__paid-marker mt-[0.375rem]"
*ngIf="orderItem?.features?.paid && !isKulturpass"
>
<div
class="font-bold flex flex-row items-center justify-center text-p2 text-[#26830C]"
>
<shared-icon
class="flex items-center justify-center mr-[0.375rem]"
[size]="24"
icon="credit-card"
></shared-icon>
{{ orderItem?.features?.paid }}
</div>
</div>
<div class="page-pickup-shelf-details-header__paid-marker mt-[0.375rem] text-[#26830C]" *ngIf="isKulturpass">
<svg class="fill-current mr-2" xmlns="http://www.w3.org/2000/svg" height="22" viewBox="0 -960 960 960" width="22">
<div
class="page-pickup-shelf-details-header__paid-marker mt-[0.375rem] text-[#26830C]"
*ngIf="isKulturpass"
>
<svg
class="fill-current mr-2"
xmlns="http://www.w3.org/2000/svg"
height="22"
viewBox="0 -960 960 960"
width="22"
>
<path
d="M880-740v520q0 24-18 42t-42 18H140q-24 0-42-18t-18-42v-520q0-24 18-42t42-18h680q24 0 42 18t18 42ZM140-631h680v-109H140v109Zm0 129v282h680v-282H140Zm0 282v-520 520Z"
/>
@@ -59,21 +107,42 @@
</div>
<div class="page-pickup-shelf-details-header__details-wrapper -mt-3">
<div class="flex flex-row page-pickup-shelf-details-header__buyer-number" data-detail-id="Kundennummer">
<div
class="flex flex-row page-pickup-shelf-details-header__buyer-number"
data-detail-id="Kundennummer"
>
<div class="min-w-[9rem]">Kundennummer</div>
<div class="flex flex-row font-bold">{{ orderItem?.buyerNumber }}</div>
<div class="flex flex-row font-bold">
{{ orderItem?.buyerNumber }}
</div>
</div>
<div class="flex flex-row page-pickup-shelf-details-header__order-number" data-detail-id="VorgangId">
<div
class="flex flex-row page-pickup-shelf-details-header__order-number"
data-detail-id="VorgangId"
>
<div class="min-w-[9rem]">Vorgang-ID</div>
<div class="flex flex-row font-bold">{{ orderItem?.orderNumber }}</div>
<div class="flex flex-row font-bold">
{{ orderItem?.orderNumber }}
</div>
</div>
<div class="flex flex-row page-pickup-shelf-details-header__order-date" data-detail-id="Bestelldatum">
<div
class="flex flex-row page-pickup-shelf-details-header__order-date"
data-detail-id="Bestelldatum"
>
<div class="min-w-[9rem]">Bestelldatum</div>
<div class="flex flex-row font-bold">{{ orderItem?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
<div class="flex flex-row font-bold">
{{ orderItem?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr
</div>
</div>
<div class="flex flex-row page-pickup-shelf-details-header__processing-status justify-between" data-detail-id="Status">
<div
class="flex flex-row page-pickup-shelf-details-header__processing-status justify-between"
data-detail-id="Status"
>
<div class="min-w-[9rem]">Status</div>
<div *ngIf="!(changeStatusLoader$ | async)" class="flex flex-row font-bold -mr-[0.125rem]">
<div
*ngIf="!(changeStatusLoader$ | async)"
class="flex flex-row font-bold -mr-[0.125rem]"
>
<span *ngIf="!(canEditStatus$ | async)">
{{ orderItem?.processingStatus | processingStatus }}
</span>
@@ -97,7 +166,12 @@
icon="arrow-drop-down"
></shared-icon>
</button>
<ui-dropdown #statusDropdown yPosition="below" xPosition="after" [xOffset]="8">
<ui-dropdown
#statusDropdown
yPosition="below"
xPosition="after"
[xOffset]="8"
>
<button
uiDropdownItem
*ngFor="let action of statusActions$ | async"
@@ -111,12 +185,22 @@
</ui-dropdown>
</ng-container>
</div>
<ui-spinner *ngIf="changeStatusLoader$ | async; let loader" class="flex flex-row font-bold loader" [show]="loader"></ui-spinner>
<ui-spinner
*ngIf="changeStatusLoader$ | async; let loader"
class="flex flex-row font-bold loader"
[show]="loader"
></ui-spinner>
</div>
<div class="flex flex-row page-pickup-shelf-details-header__order-source" data-detail-id="Bestellkanal">
<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">
<shared-skeleton-loader class="w-32" *ngIf="fetchingOrder$ | async; else orderSourceTmpl"></shared-skeleton-loader>
<shared-skeleton-loader
class="w-32"
*ngIf="fetchingOrder$ | async; else orderSourceTmpl"
></shared-skeleton-loader>
<ng-template #orderSourceTmpl>
{{ order()?.features?.orderSource }}
</ng-template>
@@ -142,19 +226,30 @@
<ng-template #changeDate>
<div class="min-w-[9rem]">Geändert</div>
<div class="flex flex-row font-bold">{{ orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
<div class="flex flex-row font-bold">
{{
orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm'
}}
Uhr
</div>
</ng-template>
</div>
<div
class="flex flex-row page-pickup-shelf-details-header__pick-up justify-between"
data-detail-id="Wunschdatum"
*ngIf="orderItem.orderType === 1 && (orderItem.processingStatus === 16 || orderItem.processingStatus === 8192)"
*ngIf="
orderItem.orderType === 1 &&
(orderItem.processingStatus === 16 ||
orderItem.processingStatus === 8192)
"
>
<ng-container *ngTemplateOutlet="preferredPickUpDate"></ng-container>
</div>
<div class="flex flex-col page-pickup-shelf-details-header__dig-and-notification">
<div
class="flex flex-col page-pickup-shelf-details-header__dig-and-notification"
>
<div
*ngIf="orderItem.orderType === 1"
class="flex flex-row page-pickup-shelf-details-header__notification"
@@ -162,9 +257,14 @@
>
<div class="min-w-[9rem]">Benachrichtigung</div>
<div class="flex flex-row font-bold">
<shared-skeleton-loader class="w-32" *ngIf="fetchingOrder$ | async; else notificationsChannelTpl"></shared-skeleton-loader>
<shared-skeleton-loader
class="w-32"
*ngIf="fetchingOrder$ | async; else notificationsChannelTpl"
></shared-skeleton-loader>
<ng-template #notificationsChannelTpl>
{{ (notificationsChannel$ | async | notificationsChannel) || '-' }}
{{
(notificationsChannel$ | async | notificationsChannel) || '-'
}}
</ng-template>
</div>
</div>
@@ -175,11 +275,17 @@
<ng-template #abholfrist>
<div class="min-w-[9rem]">Abholfrist</div>
<div *ngIf="!(orderItemSubsetLoading$ | async); else featureLoading" class="flex flex-row font-bold">
<div
*ngIf="!(orderItemSubsetLoading$ | async); else featureLoading"
class="flex flex-row font-bold"
>
<button
[uiOverlayTrigger]="deadlineDatepicker"
#deadlineDatepickerTrigger="uiOverlayTrigger"
[disabled]="!isKulturpass && (!!orderItem?.features?.paid || (changeDateDisabled$ | async))"
[disabled]="
!isKulturpass &&
(!!orderItem?.features?.paid || (changeDateDisabled$ | async))
"
class="cta-pickup-deadline"
matomoClickCategory="pickup-shelf-details-header"
matomoClickAction="click"
@@ -188,7 +294,11 @@
<strong class="border-r border-[#AEB7C1] pr-4">
{{ orderItem?.pickUpDeadline | date: 'dd.MM.yy' }}
</strong>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
<shared-icon
class="text-[#596470] ml-4"
[size]="24"
icon="isa-calendar"
></shared-icon>
</button>
<ui-datepicker
#deadlineDatepicker
@@ -205,23 +315,40 @@
<ng-template #preferredPickUpDate>
<div class="min-w-[9rem]">Zurücklegen bis</div>
<div *ngIf="!(orderItemSubsetLoading$ | async); else featureLoading" class="flex flex-row font-bold">
<div
*ngIf="!(orderItemSubsetLoading$ | async); else featureLoading"
class="flex flex-row font-bold"
>
<button
[uiOverlayTrigger]="preferredPickUpDatePicker"
#preferredPickUpDatePickerTrigger="uiOverlayTrigger"
[disabled]="(!isKulturpass && !!orderItem?.features?.paid) || (changeDateDisabled$ | async)"
[disabled]="
(!isKulturpass && !!orderItem?.features?.paid) ||
(changeDateDisabled$ | async)
"
class="cta-pickup-preferred"
matomoClickCategory="pickup-shelf-details-header"
matomoClickAction="click"
matomoClickName="pickup-preferred"
>
<strong class="border-r border-[#AEB7C1] pr-4" *ngIf="findLatestPreferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
<strong
class="border-r border-[#AEB7C1] pr-4"
*ngIf="
findLatestPreferredPickUpDate$ | async;
let pickUpDate;
else: selectTemplate
"
>
{{ pickUpDate | date: 'dd.MM.yy' }}
</strong>
<ng-template #selectTemplate>
<strong class="border-r border-[#AEB7C1] pr-4">Auswählen</strong>
</ng-template>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
<shared-icon
class="text-[#596470] ml-4"
[size]="24"
icon="isa-calendar"
></shared-icon>
</button>
<ui-datepicker
#preferredPickUpDatePicker
@@ -238,7 +365,10 @@
<ng-template #vslLieferdatum>
<div class="min-w-[9rem]">vsl. Lieferdatum</div>
<div *ngIf="!(orderItemSubsetLoading$ | async); else featureLoading" class="flex flex-row font-bold">
<div
*ngIf="!(orderItemSubsetLoading$ | async); else featureLoading"
class="flex flex-row font-bold"
>
<button
class="cta-datepicker"
[disabled]="changeDateDisabled$ | async"
@@ -251,7 +381,11 @@
<span class="border-r border-[#AEB7C1] pr-4">
{{ orderItem?.estimatedShippingDate | date: 'dd.MM.yy' }}
</span>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
<shared-icon
class="text-[#596470] ml-4"
[size]="24"
icon="isa-calendar"
></shared-icon>
</button>
<ui-datepicker
#uiDatepicker

View File

@@ -1,4 +1,12 @@
import { AsyncPipe, DatePipe, NgFor, NgIf, NgSwitch, NgSwitchCase, NgTemplateOutlet } from '@angular/common';
import {
AsyncPipe,
DatePipe,
NgFor,
NgIf,
NgSwitch,
NgSwitchCase,
NgTemplateOutlet,
} from '@angular/common';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
@@ -28,6 +36,7 @@ import { PickUpShelfDetailsHeaderNavMenuComponent } from '../pickup-shelf-detail
import { SkeletonLoaderComponent } from '@shared/components/loader';
import { toSignal } from '@angular/core/rxjs-interop';
import { MatomoModule } from 'ngx-matomo-client';
import { getEnabledCustomerFeature } from '@isa/crm/data-access';
@Component({
selector: 'page-pickup-shelf-details-header',
@@ -65,7 +74,10 @@ export class PickUpShelfDetailsHeaderComponent {
handleAction = new EventEmitter<KeyValueDTOOfStringAndString>();
@Output()
updateDate = new EventEmitter<{ date: Date; type?: 'delivery' | 'pickup' | 'preferred' }>();
updateDate = new EventEmitter<{
date: Date;
type?: 'delivery' | 'pickup' | 'preferred';
}>();
orderItemSubsetLoading$ = this._store.orderItemSubsetLoading$;
@@ -83,12 +95,19 @@ export class PickUpShelfDetailsHeaderComponent {
?.reduce((acc, item) => {
return [...acc, ...item.data.subsetItems];
}, [])
?.filter((a) => !!a.data.preferredPickUpDate && selectedOrderItemIds.find((id) => id === a.data.id));
?.filter(
(a) =>
!!a.data.preferredPickUpDate &&
selectedOrderItemIds.find((id) => id === a.data.id),
);
if (subsetItems?.length > 0) {
latestDate = new Date(
subsetItems?.reduce((a, b) => {
return new Date(a.data.preferredPickUpDate) > new Date(b.data.preferredPickUpDate) ? a : b;
return new Date(a.data.preferredPickUpDate) >
new Date(b.data.preferredPickUpDate)
? a
: b;
})?.data?.preferredPickUpDate,
);
}
@@ -108,14 +127,24 @@ export class PickUpShelfDetailsHeaderComponent {
return this.order()?.features?.orderSource === 'KulturPass';
}
minDateDatepicker = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -1);
minDateDatepicker = this.dateAdapter.addCalendarDays(
this.dateAdapter.today(),
-1,
);
today = this.dateAdapter.today();
// Daten die im Header Angezeigt werden sollen
orderItem$ = combineLatest([
this._store.selectedOrderItem$, // Wenn man im Abholfach ist muss das ausgewählte OrderItem genommen werden
this._store.selectedOrderItems$.pipe(map((orderItems) => orderItems?.find((_) => true))), // Wenn man in der Warenausgabe ist muss man das erste OrderItem nehmen
]).pipe(map(([selectedOrderItem, selectedOrderItems]) => selectedOrderItem || selectedOrderItems));
this._store.selectedOrderItems$.pipe(
map((orderItems) => orderItems?.find((_) => true)),
), // Wenn man in der Warenausgabe ist muss man das erste OrderItem nehmen
]).pipe(
map(
([selectedOrderItem, selectedOrderItems]) =>
selectedOrderItem || selectedOrderItems,
),
);
changeDateLoader$ = new BehaviorSubject<boolean>(false);
changePreferredDateLoader$ = new BehaviorSubject<boolean>(false);
@@ -124,28 +153,41 @@ export class PickUpShelfDetailsHeaderComponent {
changeDateDisabled$ = this.changeStatusDisabled$;
fetchingCustomerDone$ = this._store.fetchingCustomer$.pipe(map((fetchingCustomer) => !fetchingCustomer));
fetchingCustomerDone$ = this._store.fetchingCustomer$.pipe(
map((fetchingCustomer) => !fetchingCustomer),
);
customer$ = this._store.customer$;
features$ = this.customer$.pipe(
map((customer) => customer?.features || []),
map((features) => features.filter((f) => f.enabled && !!f.description)),
customerFeature$ = this.customer$.pipe(
map((customer) => getEnabledCustomerFeature(customer?.features)),
shareReplay(),
);
statusActions$ = this.orderItem$.pipe(
map((orderItem) => orderItem?.actions?.filter((action) => action.enabled === false)),
map((orderItem) =>
orderItem?.actions?.filter((action) => action.enabled === false),
),
);
crudaUpdate$ = this.orderItem$.pipe(map((orederItem) => !!(orederItem?.cruda & 4)));
crudaUpdate$ = this.orderItem$.pipe(
map((orederItem) => !!(orederItem?.cruda & 4)),
);
editButtonDisabled$ = combineLatest([this.changeStatusLoader$, this.crudaUpdate$]).pipe(
map(([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate),
editButtonDisabled$ = combineLatest([
this.changeStatusLoader$,
this.crudaUpdate$,
]).pipe(
map(
([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate,
),
);
canEditStatus$ = combineLatest([this.statusActions$, this.crudaUpdate$]).pipe(
map(([statusActions, crudaUpdate]) => statusActions?.length > 0 && crudaUpdate),
map(
([statusActions, crudaUpdate]) =>
statusActions?.length > 0 && crudaUpdate,
),
);
constructor(