Migration Angular v19 -> v20

This commit is contained in:
Lorenz Hilpert
2025-06-16 11:54:47 +02:00
parent 54664123fb
commit d8c2ca9bdc
272 changed files with 10560 additions and 9792 deletions

View File

@@ -2,6 +2,3 @@ last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 iOS major versions
safari > 11
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@@ -1,4 +1,4 @@
import { DOCUMENT } from '@angular/common';
import {
Component,
effect,
@@ -10,6 +10,7 @@ import {
Renderer2,
signal,
untracked,
DOCUMENT
} from '@angular/core';
import { Title } from '@angular/platform-browser';
import { SwUpdate } from '@angular/service-worker';

View File

@@ -3,10 +3,12 @@
<p>Vorschläge:</p>
<ul class="content">
<li *ngFor="let item of ref?.data">
<span>{{ item.street }} {{ item.streetNumber }}, {{ item.zipCode }} {{ item.city }}</span>
<button (click)="ref.close(item)">Übernehmen</button>
</li>
@for (item of ref?.data; track item) {
<li>
<span>{{ item.street }} {{ item.streetNumber }}, {{ item.zipCode }} {{ item.city }}</span>
<button (click)="ref.close(item)">Übernehmen</button>
</li>
}
</ul>
<div class="center">

View File

@@ -6,13 +6,19 @@
uiSearchboxSearchButton
(click)="filter(input.value)"
[disabled]="branchesFetching$ | async"
>
<ui-icon class="spin" *ngIf="branchesFetching$ | async" icon="spinner" size="32px"></ui-icon>
<ui-icon *ngIf="!(branchesFetching$ | async)" icon="search" size="24px"></ui-icon>
</button>
<button *ngIf="input.value" type="reset" uiSearchboxClearButton (click)="filter(''); cancelSearch(); input.value = ''">
<ui-icon icon="close" size="22px"></ui-icon>
>
@if (branchesFetching$ | async) {
<ui-icon class="spin" icon="spinner" size="32px"></ui-icon>
}
@if (!(branchesFetching$ | async)) {
<ui-icon icon="search" size="24px"></ui-icon>
}
</button>
@if (input.value) {
<button type="reset" uiSearchboxClearButton (click)="filter(''); cancelSearch(); input.value = ''">
<ui-icon icon="close" size="22px"></ui-icon>
</button>
}
</ui-searchbox>
<p class="subtitle">
@@ -25,7 +31,7 @@
<hr />
<div class="branches">
<ng-container *ngFor="let branch of filteredBranches$ | async">
@for (branch of filteredBranches$ | async; track branch) {
<div class="branch">
<div class="branch-info">
<span class="branch-name">
@@ -36,25 +42,23 @@
{{ branch.address.city }}
</span>
</div>
<div class="branch-actions">
<button
*ngIf="(branch.id | stockInfo: (inStock$ | async))?.availableQuantity > 0 && branch?.isShippingEnabled"
class="cta-reserve"
(click)="reserve(branch)"
>
Reservieren
</button>
@if ((branch.id | stockInfo: (inStock$ | async))?.availableQuantity > 0 && branch?.isShippingEnabled) {
<button
class="cta-reserve"
(click)="reserve(branch)"
>
Reservieren
</button>
}
<ui-spinner [show]="stockFetching$ | async">
<span class="branch-stock">
<ui-icon icon="home" size="22px"></ui-icon>
<span>{{ branch.id | inStock: (inStock$ | async) }}x</span>
</span>
</ui-spinner>
</div>
</div>
<hr />
</ng-container>
}
</div>

View File

@@ -3,9 +3,11 @@
</div>
<div class="thumbnails-wrapper">
<button *ngFor="let image of images" (click)="activeImage = image" [class.selected]="activeImage.url === image.url">
<img class="thumbnail" [src]="image.thumbUrl" />
</button>
@for (image of images; track image) {
<button (click)="activeImage = image" [class.selected]="activeImage.url === image.url">
<img class="thumbnail" [src]="image.thumbUrl" />
</button>
}
</div>
<div class="controls">

View File

@@ -18,9 +18,11 @@
<ui-quantity-dropdown [quantity]="itemQuantity$ | async" (quantityChange)="onQuantityChange($event)"></ui-quantity-dropdown>
</div>
<div class="relative">
<div *ngIf="stockWarning$ | async" class="text-warning font-bold absolute right-0 top-0 whitespace-nowrap">
Es befinden sich {{ availableQuantity$ | async }} Exemplare in der Filiale
</div>
@if (stockWarning$ | async) {
<div class="text-warning font-bold absolute right-0 top-0 whitespace-nowrap">
Es befinden sich {{ availableQuantity$ | async }} Exemplare in der Filiale
</div>
}
</div>
</div>
</div>

View File

@@ -20,18 +20,21 @@
</div>
</div>
<div class="overflow-y-auto -mx-4 scroll-bar">
<div *ngIf="emptyShoppingCart$ | async" class="h-full grid items-center justify-center">
<h3 class="text-xl font-bold text-center text-gray-500">
Warenkorb ist leer, bitte suchen oder scannen
<br />
Sie Artikel um den Warenkob zu füllen.
</h3>
</div>
<shared-kulturpass-order-item
class="border-b border-solid border-[#EFF1F5]"
*ngFor="let item of items$ | async; trackBy: trackItemById"
[item]="item"
></shared-kulturpass-order-item>
@if (emptyShoppingCart$ | async) {
<div class="h-full grid items-center justify-center">
<h3 class="text-xl font-bold text-center text-gray-500">
Warenkorb ist leer, bitte suchen oder scannen
<br />
Sie Artikel um den Warenkob zu füllen.
</h3>
</div>
}
@for (item of items$ | async; track trackItemById($index, item)) {
<shared-kulturpass-order-item
class="border-b border-solid border-[#EFF1F5]"
[item]="item"
></shared-kulturpass-order-item>
}
</div>
<div class="flex flex-row justify-evenly items-stretch border-t border-solid border-[#EFF1F5] py-3 px-4 -mx-4">
<div class="grid grid-flow-row text-xl">
@@ -49,13 +52,15 @@
</div>
</div>
<div class="grid items-end justify-between">
<div *ngIf="negativeBalance$ | async" class="text-xl text-warning font-bold text-center">Der Betrag übersteigt ihr Guthaben</div>
@if (negativeBalance$ | async) {
<div class="text-xl text-warning font-bold text-center">Der Betrag übersteigt ihr Guthaben</div>
}
<button
type="button"
class="bg-brand text-white px-6 py-3 font-bold rounded-full disabled:bg-disabled-branch disabled:text-active-branch"
[disabled]="orderButtonDisabled$ | async"
(click)="order()"
>
>
<shared-loader [loading]="ordering$ | async" hideContent="true">Kauf abschließen und Rechnung drucken</shared-loader>
</button>
</div>

View File

@@ -2,19 +2,20 @@
{{ message }}
</p>
<div class="message-modal-actions grid grid-flow-col gap-4 items-center justify-center">
<button
*ngFor="let action of actions"
type="button"
class="btn rounded-full font-bold text-p1 border-[2px] border-solid border-brand px-6"
[class.bg-brand]="action.primary"
[class.hover:bg-brand]="action.primary"
[class.text-white]="action.primary"
[class.bg-white]="!action.primary"
[class.text-brand]="!action.primary"
[class.hover:bg-white]="!action.primary"
[class.hover:text-brand]="!action.primary"
(click)="clickAction(action)"
>
{{ action.label }}
</button>
@for (action of actions; track action) {
<button
type="button"
class="btn rounded-full font-bold text-p1 border-[2px] border-solid border-brand px-6"
[class.bg-brand]="action.primary"
[class.hover:bg-brand]="action.primary"
[class.text-white]="action.primary"
[class.bg-white]="!action.primary"
[class.text-brand]="!action.primary"
[class.hover:bg-white]="!action.primary"
[class.hover:text-brand]="!action.primary"
(click)="clickAction(action)"
>
{{ action.label }}
</button>
}
</div>

View File

@@ -1,4 +1,4 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { UiModalRef } from '@ui/modal';
import { MessageModalData } from './message-modal.data';
@@ -10,7 +10,7 @@ import { MessageModalAction } from './message-modal.action';
styleUrls: ['message-modal.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'shared-message-modal' },
imports: [CommonModule],
imports: [],
})
export class MessageModalComponent {
get message() {

View File

@@ -4,8 +4,10 @@
<div class="notification-text">{{ item.text }}</div>
</div>
<div>
<button *ngIf="editButton" class="notification-edit-cta text-brand font-bold text-lg px-4 py-3" (click)="itemSelected.emit(item)">
{{ editButtonLabel }}
</button>
@if (editButton) {
<button class="notification-edit-cta text-brand font-bold text-lg px-4 py-3" (click)="itemSelected.emit(item)">
{{ editButtonLabel }}
</button>
}
</div>
</div>

View File

@@ -1,5 +1,5 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
@for (notification of notifications; track notification) {
<modal-notifications-list-item
(click)="itemSelected(notification)"
[editButtonLabel]="'Packstück-Prüfung'"
@@ -7,5 +7,5 @@
(itemSelected)="itemSelected($event)"
></modal-notifications-list-item>
<hr />
</ng-container>
}
</div>

View File

@@ -1,8 +1,8 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
@for (notification of notifications; track notification) {
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
<hr />
</ng-container>
}
</div>
<div class="actions">

View File

@@ -1,8 +1,8 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
@for (notification of notifications; track notification) {
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
<hr />
</ng-container>
}
</div>
<div class="actions">

View File

@@ -1,8 +1,8 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
@for (notification of notifications; track notification) {
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
<hr />
</ng-container>
}
</div>
<div class="actions">

View File

@@ -1,11 +1,11 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
@for (notification of notifications; track notification) {
<div class="notification-headline">
<h1>{{ notification.headline }}</h1>
</div>
<div class="notification-text">{{ notification.text }}</div>
<hr />
</ng-container>
}
</div>
<div class="actions">

View File

@@ -1,6 +1,6 @@
<h1>Sie haben neue Nachrichten</h1>
<ng-container *ngFor="let notification of notifications$ | async | keyvalue">
@for (notification of notifications$ | async | keyvalue; track notification) {
<button type="button" class="notification-card" (click)="selectArea(notification.key)">
<div class="notification-icon">
<div class="notification-counter">{{ notification.value?.length }}</div>
@@ -9,30 +9,37 @@
<span>{{ notification.value?.[0]?.category }}</span>
</button>
<hr class="-mx-4" />
<ng-container *ngIf="notification.key === selectedArea" [ngSwitch]="notification.value?.[0]?.category">
<modal-notifications-update-group
*ngSwitchCase="'ISA-Update'"
[notifications]="notifications[selectedArea]"
></modal-notifications-update-group>
<modal-notifications-reservation-group
*ngSwitchCase="'Reservierungsanfragen'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-reservation-group>
<modal-notifications-remission-group
*ngSwitchCase="'Remission'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-remission-group>
<modal-notifications-task-calendar-group
*ngSwitchCase="'Tätigkeitskalender'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-task-calendar-group>
<modal-notifications-package-inspection-group
*ngSwitchCase="'Wareneingang Lagerware'"
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-package-inspection-group>
</ng-container>
</ng-container>
@if (notification.key === selectedArea) {
@switch (notification.value?.[0]?.category) {
@case ('ISA-Update') {
<modal-notifications-update-group
[notifications]="notifications[selectedArea]"
></modal-notifications-update-group>
}
@case ('Reservierungsanfragen') {
<modal-notifications-reservation-group
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-reservation-group>
}
@case ('Remission') {
<modal-notifications-remission-group
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-remission-group>
}
@case ('Tätigkeitskalender') {
<modal-notifications-task-calendar-group
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-task-calendar-group>
}
@case ('Wareneingang Lagerware') {
<modal-notifications-package-inspection-group
[notifications]="notifications[selectedArea]"
(navigated)="close()"
></modal-notifications-package-inspection-group>
}
}
}
}

View File

@@ -2,13 +2,17 @@
<div class="header">
<h1>Wählen Sie einen Drucker aus</h1>
<span *ngIf="error" class="error-message">{{ errorMessage }}</span>
@if (error) {
<span class="error-message">{{ errorMessage }}</span>
}
</div>
<div class="body">
<ui-spinner [show]="!loaded">
<ui-select class="select" [(ngModel)]="selectedPrinterKey">
<ui-select-option *ngFor="let printer of printers$ | async" [label]="printer.description" [value]="printer.key"></ui-select-option>
@for (printer of printers$ | async; track printer) {
<ui-select-option [label]="printer.description" [value]="printer.key"></ui-select-option>
}
</ui-select>
</ui-spinner>
</div>

View File

@@ -1,5 +1,9 @@
<div class="flex flex-col text-right" [class.hidden]="hideHeader$ | async">
<button type="button" class="font-bold text-[#0556B4]" *ngIf="selectButton$ | async" (click)="selectAll()">Alle auswählen</button>
<button type="button" class="font-bold text-[#0556B4]" *ngIf="unselectButton$ | async" (click)="unselectAll()">Alle abwählen</button>
@if (selectButton$ | async) {
<button type="button" class="font-bold text-[#0556B4]" (click)="selectAll()">Alle auswählen</button>
}
@if (unselectButton$ | async) {
<button type="button" class="font-bold text-[#0556B4]" (click)="unselectAll()">Alle abwählen</button>
}
<span class="mt-2">{{ selectedItemsCount$ | async }} von {{ itemsCount$ | async }} Artikel</span>
</div>

View File

@@ -15,147 +15,171 @@
</div>
<div class="shared-purchase-options-list-item__manufacturer-and-ean">
{{ product?.manufacturer }}
<span *ngIf="product?.manufacturer && product?.ean">|</span>
@if (product?.manufacturer && product?.ean) {
<span>|</span>
}
{{ product?.ean }}
</div>
<div class="shared-purchase-options-list-item__volume-and-publication-date">
{{ product?.volume }}
<span *ngIf="product?.volume && product?.publicationDate">|</span>
@if (product?.volume && product?.publicationDate) {
<span>|</span>
}
{{ product?.publicationDate | date: 'dd. MMMM yyyy' }}
</div>
<div class="shared-purchase-options-list-item__availabilities mt-3 grid grid-flow-row gap-2 justify-start">
<div class="whitespace-nowrap self-center" *ngIf="(availabilities$ | async)?.length">Verfügbar als</div>
<div *ngFor="let availability of availabilities$ | async" class="grid grid-flow-col gap-4 justify-start">
<div
[ngSwitch]="availability.purchaseOption"
class="shared-purchase-options-list-item__availability grid grid-flow-col gap-2 items-center"
[attr.data-option]="availability.purchaseOption"
>
<ng-container *ngSwitchCase="'delivery'">
<shared-icon icon="isa-truck" [size]="22"></shared-icon>
{{ availability.data.estimatedDelivery?.start | date: 'EE dd.MM.' }}
-
{{ availability.data.estimatedDelivery?.stop | date: 'EE dd.MM.' }}
</ng-container>
<ng-container *ngSwitchCase="'dig-delivery'">
<shared-icon icon="isa-truck" [size]="22"></shared-icon>
{{ availability.data.estimatedDelivery?.start | date: 'EE dd.MM.' }}
-
{{ availability.data.estimatedDelivery?.stop | date: 'EE dd.MM.' }}
</ng-container>
<ng-container *ngSwitchCase="'b2b-delivery'">
<shared-icon icon="isa-b2b-truck" [size]="24"></shared-icon>
{{ availability.data.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
</ng-container>
<ng-container *ngSwitchCase="'pickup'">
<shared-icon
class="cursor-pointer"
#uiOverlayTrigger="uiOverlayTrigger"
[uiOverlayTrigger]="orderDeadlineTooltip"
[class.tooltip-active]="uiOverlayTrigger.opened"
icon="isa-box-out"
[size]="18"
></shared-icon>
{{ availability.data.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
<ui-tooltip
#orderDeadlineTooltip
yPosition="above"
xPosition="after"
[yOffset]="-12"
[xOffset]="4"
[warning]="true"
[closeable]="true"
@if ((availabilities$ | async)?.length) {
<div class="whitespace-nowrap self-center">Verfügbar als</div>
}
@for (availability of availabilities$ | async; track availability) {
<div class="grid grid-flow-col gap-4 justify-start">
<div
class="shared-purchase-options-list-item__availability grid grid-flow-col gap-2 items-center"
[attr.data-option]="availability.purchaseOption"
>
<b>{{ availability.data?.orderDeadline | orderDeadline }}</b>
</ui-tooltip>
</ng-container>
<ng-container *ngSwitchCase="'in-store'">
<shared-icon icon="isa-shopping-bag" [size]="18"></shared-icon>
{{ availability.data.inStock }}x
<ng-container *ngIf="isEVT; else noEVT">ab {{ isEVT | date: 'dd. MMMM yyyy' }}</ng-container>
<ng-template #noEVT>ab sofort</ng-template>
</ng-container>
<ng-container *ngSwitchCase="'download'">
<shared-icon icon="isa-download" [size]="22"></shared-icon>
Download
</ng-container>
@switch (availability.purchaseOption) {
@case ('delivery') {
<shared-icon icon="isa-truck" [size]="22"></shared-icon>
{{ availability.data.estimatedDelivery?.start | date: 'EE dd.MM.' }}
-
{{ availability.data.estimatedDelivery?.stop | date: 'EE dd.MM.' }}
}
@case ('dig-delivery') {
<shared-icon icon="isa-truck" [size]="22"></shared-icon>
{{ availability.data.estimatedDelivery?.start | date: 'EE dd.MM.' }}
-
{{ availability.data.estimatedDelivery?.stop | date: 'EE dd.MM.' }}
}
@case ('b2b-delivery') {
<shared-icon icon="isa-b2b-truck" [size]="24"></shared-icon>
{{ availability.data.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
}
@case ('pickup') {
<shared-icon
class="cursor-pointer"
#uiOverlayTrigger="uiOverlayTrigger"
[uiOverlayTrigger]="orderDeadlineTooltip"
[class.tooltip-active]="uiOverlayTrigger.opened"
icon="isa-box-out"
[size]="18"
></shared-icon>
{{ availability.data.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
<ui-tooltip
#orderDeadlineTooltip
yPosition="above"
xPosition="after"
[yOffset]="-12"
[xOffset]="4"
[warning]="true"
[closeable]="true"
>
<b>{{ availability.data?.orderDeadline | orderDeadline }}</b>
</ui-tooltip>
}
@case ('in-store') {
<shared-icon icon="isa-shopping-bag" [size]="18"></shared-icon>
{{ availability.data.inStock }}x
@if (isEVT) {
ab {{ isEVT | date: 'dd. MMMM yyyy' }}
} @else {
ab sofort
}
}
@case ('download') {
<shared-icon icon="isa-download" [size]="22"></shared-icon>
Download
}
}
</div>
</div>
</div>
}
</div>
</div>
<div class="shared-purchase-options-list-item__price text-right ml-4 flex flex-col items-end">
<div class="shared-purchase-options-list-item__price-value font-bold text-xl flex flex-row items-center">
<div class="relative flex flex-row justify-end items-start">
<ui-select
*ngIf="canEditVat$ | async"
class="w-[6.5rem] min-h-[3.4375rem] p-4 rounded-card border border-solid border-[#AEB7C1] mr-4"
tabindex="-1"
[formControl]="manualVatFormControl"
[defaultLabel]="'MwSt'"
>
<ui-select-option *ngFor="let vat of vats$ | async" [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
</ui-select>
<shared-input-control
[class.ml-6]="priceFormControl?.invalid && priceFormControl?.dirty"
*ngIf="canEditPrice$ | async; else priceTmpl"
>
<shared-input-control-indicator>
<shared-icon *ngIf="priceFormControl?.invalid && priceFormControl?.dirty" icon="mat-info"></shared-icon>
</shared-input-control-indicator>
<input
[uiOverlayTrigger]="giftCardTooltip"
triggerOn="none"
#quantityInput
#priceOverlayTrigger="uiOverlayTrigger"
sharedInputControlInput
type="string"
class="w-24"
[formControl]="priceFormControl"
placeholder="00,00"
(sharedOnInit)="onPriceInputInit(quantityInput, priceOverlayTrigger)"
sharedNumberValue
/>
<shared-input-control-suffix>EUR</shared-input-control-suffix>
<shared-input-control-error error="required">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="pattern">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="min">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="max">Preis ist ungültig</shared-input-control-error>
</shared-input-control>
@if (canEditVat$ | async) {
<ui-select
class="w-[6.5rem] min-h-[3.4375rem] p-4 rounded-card border border-solid border-[#AEB7C1] mr-4"
tabindex="-1"
[formControl]="manualVatFormControl"
[defaultLabel]="'MwSt'"
>
@for (vat of vats$ | async; track vat) {
<ui-select-option [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
}
</ui-select>
}
@if (canEditPrice$ | async) {
<shared-input-control
[class.ml-6]="priceFormControl?.invalid && priceFormControl?.dirty"
>
<shared-input-control-indicator>
@if (priceFormControl?.invalid && priceFormControl?.dirty) {
<shared-icon icon="mat-info"></shared-icon>
}
</shared-input-control-indicator>
<input
[uiOverlayTrigger]="giftCardTooltip"
triggerOn="none"
#quantityInput
#priceOverlayTrigger="uiOverlayTrigger"
sharedInputControlInput
type="string"
class="w-24"
[formControl]="priceFormControl"
placeholder="00,00"
(sharedOnInit)="onPriceInputInit(quantityInput, priceOverlayTrigger)"
sharedNumberValue
/>
<shared-input-control-suffix>EUR</shared-input-control-suffix>
<shared-input-control-error error="required">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="pattern">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="min">Preis ist ungültig</shared-input-control-error>
<shared-input-control-error error="max">Preis ist ungültig</shared-input-control-error>
</shared-input-control>
} @else {
{{ priceValue$ | async | currency: 'EUR' : 'code' }}
}
<ui-tooltip [warning]="true" xPosition="after" yPosition="below" [xOffset]="-55" [yOffset]="18" [closeable]="true" #giftCardTooltip>
Tragen Sie hier den
<br />
Gutscheinbetrag ein.
</ui-tooltip>
<ui-tooltip [warning]="true" xPosition="after" yPosition="below" [xOffset]="-55" [yOffset]="18" [closeable]="true" #giftCardTooltip>
Tragen Sie hier den
<br />
Gutscheinbetrag ein.
</ui-tooltip>
</div>
</div>
<ui-quantity-dropdown class="mt-2" [formControl]="quantityFormControl" [range]="maxSelectableQuantity$ | async"></ui-quantity-dropdown>
<div class="pt-7">
@if ((canAddResult$ | async)?.canAdd) {
<input
class="fancy-checkbox"
[class.checked]="selectedFormControl?.value"
[formControl]="selectedFormControl"
type="checkbox"
/>
}
</div>
<ng-template #priceTmpl>
{{ priceValue$ | async | currency: 'EUR' : 'code' }}
</ng-template>
</div>
<ui-quantity-dropdown class="mt-2" [formControl]="quantityFormControl" [range]="maxSelectableQuantity$ | async"></ui-quantity-dropdown>
<div class="pt-7">
<input
*ngIf="(canAddResult$ | async)?.canAdd"
class="fancy-checkbox"
[class.checked]="selectedFormControl?.value"
[formControl]="selectedFormControl"
type="checkbox"
/>
</div>
<ng-container *ngIf="canAddResult$ | async; let canAddResult">
<span *ngIf="!canAddResult.canAdd" class="inline-block font-bold text-[#BE8100] mt-[14px] max-w-[19rem]">
{{ canAddResult.message }}
</span>
</ng-container>
@if (canAddResult$ | async; as canAddResult) {
@if (!canAddResult.canAdd) {
<span class="inline-block font-bold text-[#BE8100] mt-[14px] max-w-[19rem]">
{{ canAddResult.message }}
</span>
}
}
<span *ngIf="showMaxAvailableQuantity$ | async" class="font-bold text-[#BE8100] mt-[14px]">
{{ (availability$ | async)?.inStock }} Exemplare sofort lieferbar
</span>
<span *ngIf="showNotAvailable$ | async" class="font-bold text-[#BE8100] mt-[14px]">Derzeit nicht bestellbar</span>
@if (showMaxAvailableQuantity$ | async) {
<span class="font-bold text-[#BE8100] mt-[14px]">
{{ (availability$ | async)?.inStock }} Exemplare sofort lieferbar
</span>
}
@if (showNotAvailable$ | async) {
<span class="font-bold text-[#BE8100] mt-[14px]">Derzeit nicht bestellbar</span>
}
</div>
</div>
<div class="flex flex-row">
<div class="w-16"></div>
<div class="grow shared-purchase-options-list-item__availabilities"></div>
</div>
</div>
<div class="flex flex-row">
<div class="w-16"></div>
<div class="grow shared-purchase-options-list-item__availabilities"></div>
</div>

View File

@@ -1,28 +1,37 @@
<h3 class="text-center font-bold text-h3">Lieferung auswählen</h3>
<p class="text-center font-2xl mt-4">Wie möchten Sie die Artikel erhalten?</p>
<div class="rounded p-4 shadow-card mt-4 grid grid-flow-col gap-4 justify-center items-center relative">
<ng-container *ngIf="!(isDownloadOnly$ | async)">
<ng-container *ngIf="!(isGiftCardOnly$ | async)">
<app-in-store-purchase-options-tile *ngIf="showOption('in-store')"></app-in-store-purchase-options-tile>
<app-pickup-purchase-options-tile *ngIf="showOption('pickup')"></app-pickup-purchase-options-tile>
</ng-container>
<app-delivery-purchase-options-tile *ngIf="showOption('delivery')"></app-delivery-purchase-options-tile>
</ng-container>
@if (!(isDownloadOnly$ | async)) {
@if (!(isGiftCardOnly$ | async)) {
@if (showOption('in-store')) {
<app-in-store-purchase-options-tile></app-in-store-purchase-options-tile>
}
@if (showOption('pickup')) {
<app-pickup-purchase-options-tile></app-pickup-purchase-options-tile>
}
}
@if (showOption('delivery')) {
<app-delivery-purchase-options-tile></app-delivery-purchase-options-tile>
}
}
<ng-container *ngIf="hasDownload$ | async">
<app-download-purchase-options-tile *ngIf="showOption('download')"></app-download-purchase-options-tile>
</ng-container>
@if (hasDownload$ | async) {
@if (showOption('download')) {
<app-download-purchase-options-tile></app-download-purchase-options-tile>
}
}
</div>
<shared-purchase-options-list-header></shared-purchase-options-list-header>
<div class="shared-purchase-options-modal__items -mx-4">
<shared-purchase-options-list-item
class="border-t border-gray-200 p-4 border-solid"
*ngFor="let item of items$ | async; trackBy: itemTrackBy"
[item]="item"
></shared-purchase-options-list-item>
@for (item of items$ | async; track itemTrackBy($index, item)) {
<shared-purchase-options-list-item
class="border-t border-gray-200 p-4 border-solid"
[item]="item"
></shared-purchase-options-list-item>
}
</div>
<div class="text-center -mx-4 border-t border-gray-200 p-4 border-solid">
<ng-container *ngIf="type === 'add'">
@if (type === 'add') {
<button type="button" class="isa-cta-button" [disabled]="!(canContinue$ | async) || saving" (click)="save('continue-shopping')">
Weiter einkaufen
</button>
@@ -31,18 +40,18 @@
class="ml-4 isa-cta-button isa-button-primary"
[disabled]="!(canContinue$ | async) || saving"
(click)="save('continue')"
>
>
Fortfahren
</button>
</ng-container>
<ng-container *ngIf="type === 'update'">
}
@if (type === 'update') {
<button
type="button"
class="ml-4 isa-cta-button isa-button-primary"
[disabled]="!(canContinue$ | async) || saving"
(click)="save('continue')"
>
>
Fortfahren
</button>
</ng-container>
}
</div>

View File

@@ -1,4 +1,4 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { PurchaseOptionsStore } from '../store';
import { BasePurchaseOptionDirective } from './base-purchase-option.directive';
@@ -9,7 +9,7 @@ import { IconComponent } from '@shared/components/icon';
templateUrl: 'download-purchase-options-tile.component.html',
styleUrls: ['purchase-options-tile.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, IconComponent],
imports: [IconComponent],
})
export class DownloadPurchaseOptionTileComponent extends BasePurchaseOptionDirective {
constructor(

View File

@@ -2,30 +2,31 @@
<hr />
<ng-container *ngIf="orderItem$ | async; let orderItem">
@if (orderItem$ | async; as orderItem) {
<div class="header">
<img
class="thumbnail"
loading="lazy"
*ngIf="orderItem?.product?.ean | productImage; let productImage"
[src]="productImage"
[alt]="orderItem?.product?.name"
/>
@if (orderItem?.product?.ean | productImage; as productImage) {
<img
class="thumbnail"
loading="lazy"
[src]="productImage"
[alt]="orderItem?.product?.name"
/>
}
<div class="details">
<div class="product-name">{{ orderItem.product?.name }}</div>
<div *ngIf="orderItem.product?.format && orderItem.product.formatDetail" class="product-format">
<img class="format-icon" [src]="'/assets/images/Icon_' + orderItem.product?.format + '.svg'" alt="format icon" />
{{ orderItem.product.formatDetail }}
</div>
@if (orderItem.product?.format && orderItem.product.formatDetail) {
<div class="product-format">
<img class="format-icon" [src]="'/assets/images/Icon_' + orderItem.product?.format + '.svg'" alt="format icon" />
{{ orderItem.product.formatDetail }}
</div>
}
<div class="product-ean">
{{ orderItem.product?.ean }}
</div>
<div class="quantity">{{ orderItem.quantity }}x</div>
</div>
</div>
<ng-container *ngIf="availabilities$ | async; let availabilities; else: showLoadingSpinner">
@if (availabilities$ | async; as availabilities) {
<div class="supplier-grid">
<span></span>
<span class="number">Bestand</span>
@@ -34,53 +35,56 @@
<span>vsl. Lieferdatum</span>
<span class="number">Preis</span>
<span></span>
<ng-container *ngFor="let availability of availabilities; let i = index">
<ng-container *ngIf="availability">
@for (availability of availabilities; track availability; let i = $index) {
@if (availability) {
<span class="first-cell">{{ availability.supplier | supplierName }}</span>
<span class="number">{{ availability.qty || 0 }}</span>
<span>{{ availability.ssc }}</span>
<span>
<ui-checkbox *ngIf="availability.supplier !== 'F'" [(ngModel)]="availability.isPrebooked"></ui-checkbox>
@if (availability.supplier !== 'F') {
<ui-checkbox [(ngModel)]="availability.isPrebooked"></ui-checkbox>
}
</span>
<span>{{ availability.at | date: 'dd.MM.yy' }}</span>
<span class="number">{{ availability.price?.value?.value | currency: 'EUR' : 'code' }}</span>
<span>
<ui-select-bullet
*ngIf="availability.supplier !== 'F' || availability.qty > 0"
[(ngModel)]="checkedSupplier"
[value]="availability.supplier"
(ngModelChange)="checked($event, availability)"
></ui-select-bullet>
@if (availability.supplier !== 'F' || availability.qty > 0) {
<ui-select-bullet
[(ngModel)]="checkedSupplier"
[value]="availability.supplier"
(ngModelChange)="checked($event, availability)"
></ui-select-bullet>
}
</span>
</ng-container>
</ng-container>
}
}
</div>
<ng-container *ngIf="storeAvailabilityError$ | async">
@if (storeAvailabilityError$ | async) {
<div class="availability-error">Lieferantenbestand nicht verfügbar</div>
<hr />
</ng-container>
<ng-container *ngIf="takeAwayAvailabilityError$ | async">
}
@if (takeAwayAvailabilityError$ | async) {
<div class="availability-error">Filialbestand nicht verfügbar</div>
<hr />
</ng-container>
<div class="reason" *ngIf="showReasons$ | async">
<button class="reason-dropdown" [uiOverlayTrigger]="statusDropdown" #dropdown="uiOverlayTrigger">
{{ selectedReason || 'Warum wird nachbestellt?' }}
<ui-icon [rotate]="dropdown.opened ? '270deg' : '90deg'" icon="arrow_head"></ui-icon>
</button>
<ui-dropdown #statusDropdown yPosition="above" xPosition="after" [xOffset]="8">
<button uiDropdownItem *ngFor="let reason of reorderReasons$ | async" (click)="selectedReason = reason.value; dropdown.close()">
{{ reason.value }}
}
@if (showReasons$ | async) {
<div class="reason">
<button class="reason-dropdown" [uiOverlayTrigger]="statusDropdown" #dropdown="uiOverlayTrigger">
{{ selectedReason || 'Warum wird nachbestellt?' }}
<ui-icon [rotate]="dropdown.opened ? '270deg' : '90deg'" icon="arrow_head"></ui-icon>
</button>
</ui-dropdown>
<span *ngIf="showReasonError$ | async" class="error">Bitte wählen Sie einen Grund für das nachbestellen</span>
</div>
<ui-dropdown #statusDropdown yPosition="above" xPosition="after" [xOffset]="8">
@for (reason of reorderReasons$ | async; track reason) {
<button uiDropdownItem (click)="selectedReason = reason.value; dropdown.close()">
{{ reason.value }}
</button>
}
</ui-dropdown>
@if (showReasonError$ | async) {
<span class="error">Bitte wählen Sie einen Grund für das nachbestellen</span>
}
</div>
}
<div class="actions">
<button class="cta-not-available cta-action-secondary" [disabled]="ctaDisabled$ | async" (click)="notAvailable()">
<ui-spinner [show]="ctaDisabled$ | async">Nicht lieferbar</ui-spinner>
@@ -89,9 +93,7 @@
<ui-spinner [show]="ctaDisabled$ | async">Bestellen</ui-spinner>
</button>
</div>
</ng-container>
<ng-template #showLoadingSpinner>
} @else {
<ui-spinner class="load-spinner" [show]="true"></ui-spinner>
</ng-template>
</ng-container>
}
}

View File

@@ -5,7 +5,7 @@
<div class="reviews">
<hr />
<ng-container *ngFor="let review of reviews">
@for (review of reviews; track review) {
<div class="review">
<div class="row">
<ui-stars [rating]="review.rating"></ui-stars>
@@ -16,21 +16,29 @@
</div>
<div class="row">
<span>
<span class="text" *ngIf="expandIds.indexOf(review.id) === -1">{{ review.text | substr: 150 }}</span>
<span class="text" *ngIf="expandIds.indexOf(review.id) > -1">{{ review.text }}</span>
@if (expandIds.indexOf(review.id) === -1) {
<span class="text">{{ review.text | substr: 150 }}</span>
}
@if (expandIds.indexOf(review.id) > -1) {
<span class="text">{{ review.text }}</span>
}
</span>
</div>
<div class="row right">
<button *ngIf="expandIds.indexOf(review.id) === -1" class="btn-expand" (click)="expand(review.id)">
Mehr
<ui-icon icon="arrow"></ui-icon>
</button>
<button *ngIf="expandIds.indexOf(review.id) > -1" class="btn-collapse" (click)="expand(review.id)">
<ui-icon icon="arrow" rotate="180deg"></ui-icon>
Weniger
</button>
@if (expandIds.indexOf(review.id) === -1) {
<button class="btn-expand" (click)="expand(review.id)">
Mehr
<ui-icon icon="arrow"></ui-icon>
</button>
}
@if (expandIds.indexOf(review.id) > -1) {
<button class="btn-collapse" (click)="expand(review.id)">
<ui-icon icon="arrow" rotate="180deg"></ui-icon>
Weniger
</button>
}
</div>
</div>
<hr />
</ng-container>
}
</div>

View File

@@ -1,6 +1,6 @@
<div
class="page-price-update-item__item-header flex flex-row w-full items-center justify-between bg-[rgba(0,128,121,0.15)] mb-px-2 px-5 h-[53px] rounded-t"
>
>
<p class="page-price-update-item__item-instruction font-bold text-lg">{{ item?.task?.instruction }}</p>
<p class="page-price-update-item__item-due-date text-p2">
gültig ab
@@ -10,13 +10,14 @@
<div class="page-price-update-item__item-card p-5 bg-white">
<div class="page-price-update-item__item-thumbnail text-center mr-4 w-[47px] h-[73px]">
<img
class="page-price-update-item__item-image w-[47px] max-h-[73px]"
loading="lazy"
*ngIf="item?.product?.ean | productImage; let productImage"
[src]="productImage"
[alt]="item?.product?.name"
/>
@if (item?.product?.ean | productImage; as productImage) {
<img
class="page-price-update-item__item-image w-[47px] max-h-[73px]"
loading="lazy"
[src]="productImage"
[alt]="item?.product?.name"
/>
}
</div>
<div class="page-price-update-item__item-details">
@@ -31,28 +32,33 @@
[class.text-md]="item?.product?.name?.length >= 50"
[class.text-p3]="item?.product?.name?.length >= 60"
[class.text-xs]="item?.product?.name?.length >= 100"
>
>
{{ item?.product?.name }}
</div>
<div class="page-price-update-item__item-format">
<div *ngIf="item?.product?.format && item?.product?.formatDetail" class="font-bold flex flex-row">
<img
class="mr-3"
*ngIf="item?.product?.format !== '--'"
loading="lazy"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
{{ environment.isTablet() ? (item?.product?.formatDetail | substr: 25) : item?.product?.formatDetail }}
</div>
@if (item?.product?.format && item?.product?.formatDetail) {
<div class="font-bold flex flex-row">
@if (item?.product?.format !== '--') {
<img
class="mr-3"
loading="lazy"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
}
{{ environment.isTablet() ? (item?.product?.formatDetail | substr: 25) : item?.product?.formatDetail }}
</div>
}
</div>
<div class="page-price-update-item__item-misc">
{{ environment.isTablet() ? (item?.product?.manufacturer | substr: 18) : item?.product?.manufacturer }} | {{ item?.product?.ean }}
<br />
{{ item?.product?.volume }}
<span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
@if (item?.product?.volume && item?.product?.publicationDate) {
<span>|</span>
}
{{ publicationDate }}
</div>
</div>
@@ -69,18 +75,21 @@
</div>
<div class="page-price-update-item__item-select-bullet">
<input *ngIf="isSelectable" [ngModel]="selected" (ngModelChange)="setSelected()" class="isa-select-bullet" type="checkbox" />
@if (isSelectable) {
<input [ngModel]="selected" (ngModelChange)="setSelected()" class="isa-select-bullet" type="checkbox" />
}
</div>
<div class="page-price-update-item__item-stock flex flex-row font-bold">
<ui-icon class="mt-px-2 mr-1" icon="home" size="1em"></ui-icon>
<span
*ngIf="inStock$ | async; let stock"
[class.skeleton]="stock?.inStock === undefined"
class="min-w-[1rem] text-right inline-block"
>
{{ stock?.inStock }}
</span>
@if (inStock$ | async; as stock) {
<span
[class.skeleton]="stock?.inStock === undefined"
class="min-w-[1rem] text-right inline-block"
>
{{ stock?.inStock }}
</span>
}
x
</div>
</div>

View File

@@ -4,20 +4,26 @@
(click)="print()"
type="button"
class="page-price-update-list__print-cta text-lg font-bold text-[#F70400] pr-5 mb-3"
>
>
Drucken
</button>
<div class="flex flex-row items-center justify-end">
<div *ngIf="getSelectableItems().length > 0" class="text-[#0556B4] font-bold text-p3 mr-5">
<ng-container *ngIf="selectedItemUids$ | async; let selectedItems">
<button class="page-price-update-list__cta-unselect-all" *ngIf="selectedItems?.length > 0" type="button" (click)="unselectAll()">
Alle entfernen ({{ selectedItems?.length }})
</button>
<button class="page-price-update-list__cta-select-all" type="button" (click)="selectAll()" *ngIf="selectedItems?.length === 0">
Alle auswählen ({{ getSelectableItems().length }})
</button>
</ng-container>
</div>
@if (getSelectableItems().length > 0) {
<div class="text-[#0556B4] font-bold text-p3 mr-5">
@if (selectedItemUids$ | async; as selectedItems) {
@if (selectedItems?.length > 0) {
<button class="page-price-update-list__cta-unselect-all" type="button" (click)="unselectAll()">
Alle entfernen ({{ selectedItems?.length }})
</button>
}
@if (selectedItems?.length === 0) {
<button class="page-price-update-list__cta-select-all" type="button" (click)="selectAll()">
Alle auswählen ({{ getSelectableItems().length }})
</button>
}
}
</div>
}
<div class="page-price-update-list__items-count inline-flex flex-row items-center pr-5 text-p3">
{{ items?.length ?? 0 }}
Titel
@@ -32,38 +38,41 @@
<div class="items scroll-bar">
@for (item of items; track item.uId; let first = $first) {
@defer (on viewport) {
<page-price-update-item [item]="item" [selected]="isSelected(item)" [class.mt-px-10]="!first"></page-price-update-item>
<page-price-update-item [item]="item" [selected]="isSelected(item)" [class.mt-px-10]="!first"></page-price-update-item>
} @placeholder {
<page-price-update-item-loader></page-price-update-item-loader>
}
<page-price-update-item-loader></page-price-update-item-loader>
}
}
<page-price-update-item-loader *ngIf="fetching"></page-price-update-item-loader>
<div class="h-28"></div>
@if (fetching) {
<page-price-update-item-loader></page-price-update-item-loader>
}
<div class="h-28"></div>
</div>
<!-- <cdk-virtual-scroll-viewport #scrollContainer [itemSize]="267" minBufferPx="1200" maxBufferPx="1200" class="scroll-bar">
<page-price-update-item
*cdkVirtualFor="let item of items; let first; trackBy: trackByFn"
[item]="item"
[selected]="isSelected(item)"
[class.mt-px-10]="!first"
></page-price-update-item>
<page-price-update-item
*cdkVirtualFor="let item of items; let first; trackBy: trackByFn"
[item]="item"
[selected]="isSelected(item)"
[class.mt-px-10]="!first"
></page-price-update-item>
<page-price-update-item-loader *ngIf="fetching"> </page-price-update-item-loader>
<page-price-update-item-loader *ngIf="fetching"> </page-price-update-item-loader>
<div class="h-28"></div>
<div class="h-28"></div>
</cdk-virtual-scroll-viewport> -->
<div class="page-price-update-list__action-wrapper">
<button
[@cta]
*ngIf="!fetching"
[disabled]="(selectedItemUids$ | async).length === 0 || (loading$ | async)"
class="page-price-update-list__complete-items isa-button isa-cta-button isa-button-primary px-11"
type="button"
(click)="onComplete()"
>
<ui-spinner [show]="loading$ | async">Erledigt</ui-spinner>
</button>
@if (!fetching) {
<button
[@cta]
[disabled]="(selectedItemUids$ | async).length === 0 || (loading$ | async)"
class="page-price-update-list__complete-items isa-button isa-cta-button isa-button-primary px-11"
type="button"
(click)="onComplete()"
>
<ui-spinner [show]="loading$ | async">Erledigt</ui-spinner>
</button>
}
</div>

View File

@@ -5,17 +5,20 @@
id="asortment-filter-button"
class="absolute right-0 top-0 h-14 rounded px-5 text-lg bg-cadet-blue flex flex-row flex-nowrap items-center justify-center"
type="button"
>
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</button>
</div>
<page-price-update-list
*ngIf="showList$ | async; else noResults"
[items]="store.items$ | async"
[fetching]="store.fetching$ | async"
></page-price-update-list>
@if (showList$ | async) {
<page-price-update-list
[items]="store.items$ | async"
[fetching]="store.fetching$ | async"
></page-price-update-list>
} @else {
<div class="bg-white text-h3 text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
}
<shell-filter-overlay #filterOverlay class="relative">
<div class="relative">
@@ -26,22 +29,23 @@
<h3 class="text-3xl text-center font-bold mt-8">Filter</h3>
<ui-filter
*ngIf="filterOverlay.isOpen"
#filter
class="mx-4"
[filter]="store.pendingFilter$ | async"
(search)="applyFilter()"
[loading]="store.fetching$ | async"
[hint]="hint$ | async"
></ui-filter>
@if (filterOverlay.isOpen) {
<ui-filter
#filter
class="mx-4"
[filter]="store.pendingFilter$ | async"
(search)="applyFilter()"
[loading]="store.fetching$ | async"
[hint]="hint$ | async"
></ui-filter>
}
<div class="absolute bottom-8 left-0 right-0 grid grid-flow-col gap-4 justify-center">
<button
type="button"
class="px-6 py-4 font-bold bg-white text-brand border-2 border-solid border-brand rounded-full"
(click)="store.resetPendingFilter()"
>
>
Filter zurücksetzen
</button>
<button
@@ -49,12 +53,9 @@
class="px-6 py-4 font-bold bg-brand text-white border-2 border-solid border-brand rounded-full disabled:bg-cadet-blue disabled:cursor-progress disabled:border-cadet-blue"
(click)="applyFilter()"
[disabled]="store.fetching$ | async"
>
>
<ui-spinner [show]="store.fetching$ | async">Filter anwenden</ui-spinner>
</button>
</div>
</shell-filter-overlay>
<ng-template #noResults>
<div class="bg-white text-h3 text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
</ng-template>

View File

@@ -1,14 +1,16 @@
<ng-container *ngFor="let line of lines">
<ng-container [ngSwitch]="line | lineType">
<ng-container *ngSwitchCase="'reihe'">
<page-article-details-text-link *ngFor="let reihe of getReihen(line)" [route]="reihe | reiheRoute">
{{ reihe }}
</page-article-details-text-link>
@for (line of lines; track line) {
@switch (line | lineType) {
@case ('reihe') {
@for (reihe of getReihen(line); track reihe) {
<page-article-details-text-link [route]="reihe | reiheRoute">
{{ reihe }}
</page-article-details-text-link>
}
<br />
</ng-container>
<ng-container *ngSwitchDefault>
}
@default {
{{ line }}
<br />
</ng-container>
</ng-container>
</ng-container>
}
}
}

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { TextDTO } from '@generated/swagger/cat-search-api';
import { ArticleDetailsTextLinkComponent } from './article-details-text-link.component';
import { NgFor, NgSwitch, NgSwitchCase, NgSwitchDefault } from '@angular/common';
import { LineTypePipe } from './line-type.pipe';
import { ReiheRoutePipe } from './reihe-route.pipe';
@@ -13,13 +13,9 @@ import { ReiheRoutePipe } from './reihe-route.pipe';
host: { class: 'page-article-details-text' },
imports: [
ArticleDetailsTextLinkComponent,
NgFor,
NgSwitch,
NgSwitchCase,
NgSwitchDefault,
LineTypePipe,
ReiheRoutePipe,
],
ReiheRoutePipe
],
})
export class ArticleDetailsTextComponent {
@Input()

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +1,39 @@
<ng-container *ngIf="store.item$ | async; let item">
@if (store.item$ | async; as item) {
<button
class="h-[3.75rem] shadow-[0_-2px_24px_0_#dce2e9] flex flex-row justify-center items-center w-full text-xl bg-white text-[#0556B4] font-bold border-none outline-none rounded-t"
(click)="close.emit()"
>
>
{{ item?.product?.name }}
</button>
<h1>Empfehlungen für Sie</h1>
<p>Neben dem Titel "{{ item.product?.name }}" gibt es noch andere Artikel, die Sie interessieren könnten.</p>
<div class="articles">
<span class="label mb-2">
<ui-icon icon="recommendation" size="20px"></ui-icon>
Artikel
</span>
<ng-container *ngIf="store.recommendations$ | async; let recommendations">
<span *ngIf="recommendations.length === 0" class="empty-message">Keine Empfehlungen verfügbar</span>
<ui-slider *ngIf="recommendations.length > 0" [scrollDistance]="210">
<a
class="article"
*ngFor="let recommendation of store.recommendations$ | async"
[routerLink]="getDetailsPath(recommendation.product.ean)"
[queryParams]="{ main_qs: recommendation.product.ean, filter_format: '' }"
(click)="close.emit()"
>
<img [src]="recommendation.product?.ean | productImage: 195 : 315 : true" alt="product-image" />
<div class="flex flex-col">
<span class="format">{{ recommendation.product?.formatDetail }}</span>
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
</div>
</a>
</ui-slider>
</ng-container>
@if (store.recommendations$ | async; as recommendations) {
@if (recommendations.length === 0) {
<span class="empty-message">Keine Empfehlungen verfügbar</span>
}
@if (recommendations.length > 0) {
<ui-slider [scrollDistance]="210">
@for (recommendation of store.recommendations$ | async; track recommendation) {
<a
class="article"
[routerLink]="getDetailsPath(recommendation.product.ean)"
[queryParams]="{ main_qs: recommendation.product.ean, filter_format: '' }"
(click)="close.emit()"
>
<img [src]="recommendation.product?.ean | productImage: 195 : 315 : true" alt="product-image" />
<div class="flex flex-col">
<span class="format">{{ recommendation.product?.formatDetail }}</span>
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
</div>
</a>
}
</ui-slider>
}
}
</div>
</ng-container>
}

View File

@@ -1,19 +1,19 @@
<div class="hidden desktop-large:block" [class.show-filter]="showFilter">
<ng-container *ngIf="filter$ | async; let filter">
@if (filter$ | async; as filter) {
<div class="catalog-search-filter-content">
<div class="w-full flex flex-row justify-end items-center">
<button (click)="clearFilter(filter)" class="text-[#0556B4] p-4">Alle Filter entfernen</button>
<a
*ngIf="showFilterClose$ | async"
class="text-black p-4 outline-none border-none bg-transparent"
[routerLink]="closeFilterRoute"
(click)="showFilter = false"
queryParamsHandling="preserve"
>
<shared-icon icon="close" [size]="25"></shared-icon>
</a>
@if (showFilterClose$ | async) {
<a
class="text-black p-4 outline-none border-none bg-transparent"
[routerLink]="closeFilterRoute"
(click)="showFilter = false"
queryParamsHandling="preserve"
>
<shared-icon icon="close" [size]="25"></shared-icon>
</a>
}
</div>
<div class="catalog-search-filter-content-main -mt-14 desktop-small:-mt-8 desktop-large:-mt-12">
<h1 class="text-h3 text-[1.625rem] font-bold text-center pt-6 pb-10">Filter</h1>
<shared-filter
@@ -24,16 +24,14 @@
[scanner]="true"
></shared-filter>
</div>
<div class="cta-wrapper">
<button class="cta-reset-filter" (click)="resetFilter(filter)" [disabled]="fetching$ | async">Filter zurücksetzen</button>
<button class="cta-apply-filter" (click)="applyFilter(filter)" [disabled]="(fetching$ | async) || !hasSelectedOptions(filter)">
<ui-spinner [show]="fetching$ | async">Filter anwenden</ui-spinner>
</button>
</div>
</div>
</ng-container>
}
</div>
<div class="desktop-large:hidden" [class.hidden]="showFilter">
<page-article-search-main (showFilter)="showFilter = true"></page-article-search-main>

View File

@@ -1,12 +1,13 @@
<div class="bg-white rounded py-10 px-4 text-center shadow-[0_-2px_24px_0_#dce2e9] h-full">
<h1 class="text-h3 text-[1.625rem] font-bold mb-[0.375rem]">Artikelsuche</h1>
<p class="text-lg mb-10">Welchen Artikel suchen Sie?</p>
<ng-container *ngIf="filter$ | async; let filter">
<shared-filter-filter-group-main
class="mb-8 w-full"
*ngIf="!(isDesktop$ | async)"
[inputGroup]="filter?.filter | group: 'main'"
></shared-filter-filter-group-main>
@if (filter$ | async; as filter) {
@if (!(isDesktop$ | async)) {
<shared-filter-filter-group-main
class="mb-8 w-full"
[inputGroup]="filter?.filter | group: 'main'"
></shared-filter-filter-group-main>
}
<div class="flex flex-row px-12 justify-center desktop-large:px-0">
<shared-filter-input-group-main
class="block w-full mr-3 desktop-large:mx-auto"
@@ -17,38 +18,40 @@
[showDescription]="false"
[scanner]="true"
></shared-filter-input-group-main>
<button
type="button"
*ngIf="!(isDesktop$ | async)"
(click)="showFilter.emit()"
class="page-search-main__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</button>
@if (!(isDesktop$ | async)) {
<button
type="button"
(click)="showFilter.emit()"
class="page-search-main__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</button>
}
</div>
<div class="flex flex-col items-start ml-12 desktop-large:ml-8 py-6 bg-white overflow-hidden h-[calc(100%-13.5rem)]">
<h3 class="text-p3 font-bold mb-3">Deine letzten Suchanfragen</h3>
<ul class="flex flex-col justify-start overflow-hidden overflow-y-scroll items-start m-0 p-0 bg-white w-full">
<li class="list-none pb-3" *ngFor="let recentQuery of history$ | async">
<button
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0"
(click)="setQueryHistory(filter, recentQuery.friendlyName)"
matomoClickCategory="search"
matomoClickAction="click"
matomoClickName="recent-search"
>
<shared-icon
class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
icon="magnify"
[size]="20"
></shared-icon>
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ recentQuery.friendlyName }}</p>
</button>
</li>
@for (recentQuery of history$ | async; track recentQuery) {
<li class="list-none pb-3">
<button
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0"
(click)="setQueryHistory(filter, recentQuery.friendlyName)"
matomoClickCategory="search"
matomoClickAction="click"
matomoClickName="recent-search"
>
<shared-icon
class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
icon="magnify"
[size]="20"
></shared-icon>
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ recentQuery.friendlyName }}</p>
</button>
</li>
}
</ul>
</div>
</ng-container>
}
</div>

View File

@@ -1,4 +1,6 @@
<p class="can-add-message" *ngIf="ref.data.canAddMessage">{{ ref.data.canAddMessage }}</p>
@if (ref.data.canAddMessage) {
<p class="can-add-message">{{ ref.data.canAddMessage }}</p>
}
<div class="actions">
<button (click)="continue()" class="cta cta-action-secondary">Weiter Einkaufen</button>

View File

@@ -1,4 +1,4 @@
<ng-container *ngIf="!primaryOutletActive; else primaryOutlet">
@if (!primaryOutletActive) {
<div class="bg-ucla-blue rounded w-[4.375rem] h-[5.625rem] animate-[load_1s_linear_infinite]"></div>
<div class="flex flex-col flex-grow">
<div class="h-4 bg-ucla-blue ml-4 mb-2 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
@@ -16,9 +16,7 @@
<div class="h-4 bg-ucla-blue ml-4 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
</div>
</div>
</ng-container>
<ng-template #primaryOutlet>
} @else {
<div class="bg-ucla-blue rounded w-[3rem] h-[4.125rem] animate-[load_1s_linear_infinite]"></div>
<div class="flex flex-col ml-4 w-[36.6%]">
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
@@ -35,4 +33,5 @@
<div class="h-4 bg-ucla-blue mb-2 w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
<div class="h-4 bg-ucla-blue w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
</div>
</ng-template>
}

View File

@@ -2,32 +2,34 @@
class="page-search-result-item__item-card hover p-5 desktop-small:px-4 desktop-small:py-[0.625rem] h-[13.25rem] desktop-small:h-[11.3125rem] bg-white border border-solid border-transparent rounded"
[class.page-search-result-item__item-card-primary]="primaryOutletActive"
[class.active]="isActive"
>
>
<div class="page-search-result-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]">
<img
class="page-search-result-item__item-image w-[3.125rem] max-h-[4.9375rem]"
loading="lazy"
*ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl"
[src]="thumbnailUrl"
[alt]="item?.product?.name"
/>
@if (item?.imageId | thumbnailUrl; as thumbnailUrl) {
<img
class="page-search-result-item__item-image w-[3.125rem] max-h-[4.9375rem]"
loading="lazy"
[src]="thumbnailUrl"
[alt]="item?.product?.name"
/>
}
</div>
<div
class="page-search-result-item__item-grid-container"
[class.page-search-result-item__item-grid-container-primary]="primaryOutletActive"
>
>
<div
class="page-search-result-item__item-contributors desktop-small:text-p3 font-bold text-[#0556B4] text-ellipsis overflow-hidden max-w-[24rem] whitespace-nowrap"
>
<a
*ngFor="let contributor of contributors; let last = last"
[routerLink]="resultsPath"
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
(click)="$event?.stopPropagation()"
>
{{ contributor }}{{ last ? '' : ';' }}
</a>
@for (contributor of contributors; track contributor; let last = $last) {
<a
[routerLink]="resultsPath"
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
(click)="$event?.stopPropagation()"
>
{{ contributor }}{{ last ? '' : ';' }}
</a>
}
</div>
<div
@@ -37,21 +39,24 @@
[class.text-md]="item?.product?.name?.length >= 50 && isTablet"
[class.text-p3]="item?.product?.name?.length >= 60 || !isTablet"
[class.text-xs]="item?.product?.name?.length >= 100"
>
>
{{ item?.product?.name }}
</div>
<div class="page-search-result-item__item-format desktop-small:text-p3">
<div *ngIf="item?.product?.format && item?.product?.formatDetail" class="font-bold flex flex-row">
<img
class="mr-3"
*ngIf="item?.product?.format !== '--'"
loading="lazy"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
{{ item?.product?.formatDetail | substr: 30 }}
</div>
@if (item?.product?.format && item?.product?.formatDetail) {
<div class="font-bold flex flex-row">
@if (item?.product?.format !== '--') {
<img
class="mr-3"
loading="lazy"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
}
{{ item?.product?.formatDetail | substr: 30 }}
</div>
}
</div>
<div class="page-search-result-item__item-manufacturer desktop-small:text-p3">
@@ -60,31 +65,34 @@
<div class="page-search-result-item__item-misc desktop-small:text-p3">
{{ item?.product?.volume }}
<span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
@if (item?.product?.volume && item?.product?.publicationDate) {
<span>|</span>
}
{{ publicationDate }}
</div>
<div
class="page-search-result-item__item-price desktop-small:text-p3 font-bold justify-self-end"
[class.page-search-result-item__item-price-primary]="primaryOutletActive"
>
>
{{ item?.catalogAvailability?.price?.value?.value | currency: 'EUR' : 'code' }}
</div>
<div class="page-search-result-item__item-select-bullet justify-self-end">
<input
*ngIf="selectable"
(click)="$event.stopPropagation()"
[ngModel]="selected"
@if (selectable) {
<input
(click)="$event.stopPropagation()"
[ngModel]="selected"
(ngModelChange)="
setSelected();
tracker.trackEvent({ category: 'Trefferliste', action: 'select', name: item.product.name, value: selected ? 1 : 0 })
"
class="isa-select-bullet"
type="checkbox"
matomoTracker
#tracker="matomo"
/>
class="isa-select-bullet"
type="checkbox"
matomoTracker
#tracker="matomo"
/>
}
</div>
<button
@@ -94,20 +102,21 @@
[overlayTriggerDisabled]="!(stockTooltipText$ | async)"
type="button"
(click)="$event.stopPropagation(); $event.preventDefault(); showTooltip()"
>
>
<ui-icon class="mr-[0.125rem] -mt-[0.275rem]" icon="home" size="1rem"></ui-icon>
<ng-container *ngIf="isOrderBranch$ | async">
<span
*ngIf="inStock$ | async; let stock"
[class.skeleton]="stock.inStock === undefined"
class="min-w-[0.75rem] text-right inline-block"
>
{{ stock?.inStock }}
</span>
</ng-container>
<ng-container *ngIf="!(isOrderBranch$ | async)">
@if (isOrderBranch$ | async) {
@if (inStock$ | async; as stock) {
<span
[class.skeleton]="stock.inStock === undefined"
class="min-w-[0.75rem] text-right inline-block"
>
{{ stock?.inStock }}
</span>
}
}
@if (!(isOrderBranch$ | async)) {
<span class="min-w-[1rem] text-center inline-block">-</span>
</ng-container>
}
<span>x</span>
</button>
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-12" [closeable]="true">
@@ -117,14 +126,14 @@
<div
class="page-search-result-item__item-ssc desktop-small:text-p3 w-full text-right overflow-hidden text-ellipsis whitespace-nowrap"
[class.page-search-result-item__item-ssc-primary]="primaryOutletActive"
>
<ng-container *ngIf="ssc$ | async; let ssc">
>
@if (ssc$ | async; as ssc) {
<div class="hidden" [class.page-search-result-item__item-ssc-tooltip]="primaryOutletActive">
{{ ssc?.ssc }} - {{ ssc?.sscText }}
</div>
<strong>{{ ssc?.ssc }}</strong>
- {{ ssc?.sscText }}
</ng-container>
}
</div>
</div>
</div>

View File

@@ -2,50 +2,53 @@
class="page-search-results__header bg-background-liste flex items-end justify-between"
[class.pb-4]="!(primaryOutletActive$ | async)"
[class.flex-col]="!(primaryOutletActive$ | async)"
>
>
<div class="flex flex-row w-full desktop:w-min" [class.desktop-large:w-full]="!(primaryOutletActive$ | async)">
<shared-filter-input-group-main
*ngIf="filter$ | async; let filter"
class="block mr-3 w-full desktop:w-[23.5rem]"
[class.desktop-large:w-full]="!(primaryOutletActive$ | async)"
[hint]="searchboxHint$ | async"
[loading]="fetching$ | async"
[inputGroup]="filter?.input | group: 'main'"
(search)="search({ filter, clear: true })"
[showDescription]="false"
[scanner]="true"
></shared-filter-input-group-main>
@if (filter$ | async; as filter) {
<shared-filter-input-group-main
class="block mr-3 w-full desktop:w-[23.5rem]"
[class.desktop-large:w-full]="!(primaryOutletActive$ | async)"
[hint]="searchboxHint$ | async"
[loading]="fetching$ | async"
[inputGroup]="filter?.input | group: 'main'"
(search)="search({ filter, clear: true })"
[showDescription]="false"
[scanner]="true"
></shared-filter-input-group-main>
}
<a
class="page-search-results__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
[routerLink]="filterRoute"
[queryParams]="filterQueryParams"
>
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</a>
</div>
<div
*ngIf="hits$ | async; let hits"
class="page-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
[class.mb-4]="primaryOutletActive$ | async"
>
{{ hits ?? 0 }}
Titel
</div>
@if (hits$ | async; as hits) {
<div
class="page-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
[class.mb-4]="primaryOutletActive$ | async"
>
{{ hits ?? 0 }}
Titel
</div>
}
</div>
<div class="page-search-results__order-by mb-[0.125rem]" [class.page-search-results__order-by-primary]="primaryOutletActive$ | async">
<shared-order-by-filter
*ngIf="filter$ | async; let filter"
[orderBy]="filter?.orderBy"
(selectedOrderByChange)="search({ filter, clear: true, orderBy: true }); updateBreadcrumbs()"
></shared-order-by-filter>
@if (filter$ | async; as filter) {
<shared-order-by-filter
[orderBy]="filter?.orderBy"
(selectedOrderByChange)="search({ filter, clear: true, orderBy: true }); updateBreadcrumbs()"
></shared-order-by-filter>
}
</div>
<ng-container *ngIf="primaryOutletActive$ | async; else sideOutlet">
@if (primaryOutletActive$ | async) {
<cdk-virtual-scroll-viewport class="product-list" [itemSize]="103 * (scale$ | async)" (scrolledIndexChange)="scrolledIndexChange($event)">
<a
*cdkVirtualFor="let item of results$ | async; let i = index; trackBy: trackByItemId"
@@ -54,7 +57,7 @@
#rla="routerLinkActive"
queryParamsHandling="preserve"
(click)="scrollToItem(i)"
>
>
<search-result-item
class="page-search-results__result-item page-search-results__result-item-primary"
(selectedChange)="addToCart($event)"
@@ -65,24 +68,25 @@
[isActive]="rla.isActive"
></search-result-item>
</a>
<page-search-result-item-loading [primaryOutletActive]="true" *ngIf="fetching$ | async"></page-search-result-item-loading>
@if (fetching$ | async) {
<page-search-result-item-loading [primaryOutletActive]="true"></page-search-result-item-loading>
}
</cdk-virtual-scroll-viewport>
<div class="actions z-sticky h-0">
<button
[disabled]="loading$ | async"
*ngIf="(selectedItemIds$ | async)?.length > 0"
class="cta-cart cta-action-primary"
(click)="addToCart()"
matomoClickCategory="Trefferliste"
matomoClickAction="click"
matomoClickName="In den Warenkorb legen"
>
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
</button>
@if ((selectedItemIds$ | async)?.length > 0) {
<button
[disabled]="loading$ | async"
class="cta-cart cta-action-primary"
(click)="addToCart()"
matomoClickCategory="Trefferliste"
matomoClickAction="click"
matomoClickName="In den Warenkorb legen"
>
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
</button>
}
</div>
</ng-container>
<ng-template #sideOutlet>
} @else {
<cdk-virtual-scroll-viewport class="product-list" [itemSize]="191 * (scale$ | async)" (scrolledIndexChange)="scrolledIndexChange($event)">
<a
*cdkVirtualFor="let item of results$ | async; let i = index; trackBy: trackByItemId"
@@ -91,7 +95,7 @@
#rla="routerLinkActive"
queryParamsHandling="preserve"
(click)="scrollToItem(i)"
>
>
<search-result-item
class="page-search-results__result-item"
(selectedChange)="addToCart($event)"
@@ -102,16 +106,20 @@
[isActive]="rla.isActive"
></search-result-item>
</a>
<page-search-result-item-loading [primaryOutletActive]="false" *ngIf="fetching$ | async"></page-search-result-item-loading>
@if (fetching$ | async) {
<page-search-result-item-loading [primaryOutletActive]="false"></page-search-result-item-loading>
}
</cdk-virtual-scroll-viewport>
<div class="actions z-sticky h-0">
<button
[disabled]="loading$ | async"
*ngIf="(selectedItemIds$ | async)?.length > 0"
class="cta-cart cta-action-primary"
(click)="addToCart()"
>
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
</button>
@if ((selectedItemIds$ | async)?.length > 0) {
<button
[disabled]="loading$ | async"
class="cta-cart cta-action-primary"
(click)="addToCart()"
>
<ui-spinner [show]="loading$ | async">In den Warenkorb legen</ui-spinner>
</button>
}
</div>
</ng-template>
}

View File

@@ -9,87 +9,93 @@
</p>
</div>
</div>
<form *ngIf="control" [formGroup]="control" (submit)="submit()">
<ui-form-control class="searchbox-control" label="EAN/ISBN">
<ui-searchbox
formControlName="ean"
[query]="query$ | async"
(queryChange)="setQuery($event)"
(search)="search($event)"
(scan)="search($event)"
[loading]="loading$ | async"
[hint]="message$ | async"
tabindex="0"
[scanner]="true"
></ui-searchbox>
</ui-form-control>
<ui-form-control label="Titel" requiredMark="*">
<input tabindex="0" uiInput formControlName="name" />
</ui-form-control>
<div class="control-row">
<ui-form-control label="Menge" requiredMark="*">
<input tabindex="0" uiInput formControlName="quantity" />
@if (control) {
<form [formGroup]="control" (submit)="submit()">
<ui-form-control class="searchbox-control" label="EAN/ISBN">
<ui-searchbox
formControlName="ean"
[query]="query$ | async"
(queryChange)="setQuery($event)"
(search)="search($event)"
(scan)="search($event)"
[loading]="loading$ | async"
[hint]="message$ | async"
tabindex="0"
[scanner]="true"
></ui-searchbox>
</ui-form-control>
<ui-form-control class="datepicker" label="vsl. Lieferdatum" requiredMark="*">
<button
tabindex="-1"
class="date-btn"
type="button"
[class.content-selected]="!!(estimatedShippingDate$ | async)"
[uiOverlayTrigger]="uiDatepicker"
#datepicker="uiOverlayTrigger"
>
<strong>
{{ estimatedShippingDate$ | async | date: 'dd.MM.yy' }}
</strong>
<ui-icon icon="arrow_head" class="dp-button-icon" size="20px" [rotate]="datepicker.opened ? '270deg' : '90deg'"></ui-icon>
</button>
<ui-datepicker
formControlName="estimatedShippingDate"
#uiDatepicker
yPosition="below"
xPosition="after"
[min]="minDate"
[disabledDaysOfWeek]="[0]"
[selected]="estimatedShippingDate$ | async"
saveLabel="Übernehmen"
(save)="changeEstimatedShippingDate($event); uiDatepicker.close()"
></ui-datepicker>
<ui-form-control label="Titel" requiredMark="*">
<input tabindex="0" uiInput formControlName="name" />
</ui-form-control>
</div>
<ui-form-control label="Autor">
<input tabindex="0" uiInput formControlName="contributors" />
</ui-form-control>
<ui-form-control label="Verlag">
<input tabindex="0" uiInput formControlName="manufacturer" />
</ui-form-control>
<ui-form-control class="supplier-dropdown" label="Lieferant" requiredMark="*">
<ui-select tabindex="-1" formControlName="supplier">
<ui-select-option *ngFor="let supplier of suppliers$ | async" [label]="supplier.name" [value]="supplier.id"></ui-select-option>
</ui-select>
</ui-form-control>
<div class="control-row">
<ui-form-control class="price" label="Stückpreis" [suffix]="price.value ? '' : ''" requiredMark="*">
<input tabindex="0" #price uiInput formControlName="price" />
<div class="control-row">
<ui-form-control label="Menge" requiredMark="*">
<input tabindex="0" uiInput formControlName="quantity" />
</ui-form-control>
<ui-form-control class="datepicker" label="vsl. Lieferdatum" requiredMark="*">
<button
tabindex="-1"
class="date-btn"
type="button"
[class.content-selected]="!!(estimatedShippingDate$ | async)"
[uiOverlayTrigger]="uiDatepicker"
#datepicker="uiOverlayTrigger"
>
<strong>
{{ estimatedShippingDate$ | async | date: 'dd.MM.yy' }}
</strong>
<ui-icon icon="arrow_head" class="dp-button-icon" size="20px" [rotate]="datepicker.opened ? '270deg' : '90deg'"></ui-icon>
</button>
<ui-datepicker
formControlName="estimatedShippingDate"
#uiDatepicker
yPosition="below"
xPosition="after"
[min]="minDate"
[disabledDaysOfWeek]="[0]"
[selected]="estimatedShippingDate$ | async"
saveLabel="Übernehmen"
(save)="changeEstimatedShippingDate($event); uiDatepicker.close()"
></ui-datepicker>
</ui-form-control>
</div>
<ui-form-control label="Autor">
<input tabindex="0" uiInput formControlName="contributors" />
</ui-form-control>
<ui-form-control class="mwst-dropdown" label="MwSt" requiredMark="*">
<ui-select tabindex="-1" formControlName="vat">
<ui-select-option *ngFor="let vat of vats$ | async" [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
<ui-form-control label="Verlag">
<input tabindex="0" uiInput formControlName="manufacturer" />
</ui-form-control>
<ui-form-control class="supplier-dropdown" label="Lieferant" requiredMark="*">
<ui-select tabindex="-1" formControlName="supplier">
@for (supplier of suppliers$ | async; track supplier) {
<ui-select-option [label]="supplier.name" [value]="supplier.id"></ui-select-option>
}
</ui-select>
</ui-form-control>
</div>
<div class="actions">
<button
class="cta-secondary"
(click)="nextItem()"
[disabled]="control.invalid || control.disabled || (loading$ | async)"
type="button"
>
Weitere Artikel hinzufügen
</button>
<button class="cta-primary" [disabled]="control.invalid || control.disabled || (loading$ | async)" type="submit">
Bestellung anlegen
</button>
</div>
</form>
<div class="control-row">
<ui-form-control class="price" label="Stückpreis" [suffix]="price.value ? '' : ''" requiredMark="*">
<input tabindex="0" #price uiInput formControlName="price" />
</ui-form-control>
<ui-form-control class="mwst-dropdown" label="MwSt" requiredMark="*">
<ui-select tabindex="-1" formControlName="vat">
@for (vat of vats$ | async; track vat) {
<ui-select-option [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
}
</ui-select>
</ui-form-control>
</div>
<div class="actions">
<button
class="cta-secondary"
(click)="nextItem()"
[disabled]="control.invalid || control.disabled || (loading$ | async)"
type="button"
>
Weitere Artikel hinzufügen
</button>
<button class="cta-primary" [disabled]="control.invalid || control.disabled || (loading$ | async)" type="submit">
Bestellung anlegen
</button>
</div>
</form>
}
</div>

View File

@@ -1,10 +1,9 @@
<ng-container *ngIf="(groupedItems$ | async)?.length <= 0 && !(fetching$ | async); else shoppingCart">
@if ((groupedItems$ | async)?.length <= 0 && !(fetching$ | async)) {
<div class="card stretch">
<div class="empty-message">
<span class="cart-icon flex items-center justify-center">
<shared-icon icon="shopping-cart-bold" [size]="24"></shared-icon>
</span>
<h1>Ihr Warenkorb ist leer.</h1>
<p>
Sie haben alle Artikel aus dem
@@ -13,84 +12,75 @@
<br />
keinen Artikel hinzugefügt.
</p>
<div class="btn-wrapper">
<a class="cta-primary" [routerLink]="productSearchBasePath">Artikel suchen</a>
<button class="cta-secondary" (click)="openDummyModal({})">Neuanlage</button>
</div>
</div>
</div>
</ng-container>
<div class="flex items-center justify-center card stretch" *ngIf="fetching$ | async">
<ui-spinner [show]="true"></ui-spinner>
</div>
<ng-template #shoppingCart>
<ng-container *ngIf="shoppingCart$ | async; let shoppingCart">
} @else {
@if (shoppingCart$ | async; as shoppingCart) {
<div class="card stretch">
<div class="cta-print-wrapper">
<button class="cta-print" (click)="openPrintModal()">Drucken</button>
</div>
<h1 class="header">Warenkorb</h1>
<ng-container *ngIf="!(isDesktop$ | async)">
@if (!(isDesktop$ | async)) {
<page-checkout-review-details></page-checkout-review-details>
</ng-container>
<ng-container *ngFor="let group of groupedItems$ | async; let lastGroup = last; trackBy: trackByGroupedItems">
<ng-container *ngIf="group?.orderType !== undefined">
}
@for (group of groupedItems$ | async; track trackByGroupedItems($index, group); let lastGroup = $last) {
@if (group?.orderType !== undefined) {
<hr />
<div class="row item-group-header bg-[#F5F7FA]">
<shared-icon
*ngIf="group.orderType !== 'Dummy'"
class="icon-order-type"
[size]="group.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="group.orderType"
></shared-icon>
@if (group.orderType !== 'Dummy') {
<shared-icon
class="icon-order-type"
[size]="group.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="group.orderType"
></shared-icon>
}
<div class="label" [class.dummy]="group.orderType === 'Dummy'">
{{ group.orderType !== 'Dummy' ? group.orderType : 'Manuelle Anlage / Dummy Bestellung' }}
<button
*ngIf="group.orderType === 'Dummy'"
class="text-brand border-none font-bold text-p1 outline-none pl-4"
(click)="openDummyModal({ changeDataFromCart: true })"
>
Hinzufügen
</button>
@if (group.orderType === 'Dummy') {
<button
class="text-brand border-none font-bold text-p1 outline-none pl-4"
(click)="openDummyModal({ changeDataFromCart: true })"
>
Hinzufügen
</button>
}
</div>
<div class="grow"></div>
<div class="pl-4" *ngIf="group.orderType !== 'Download' && group.orderType !== 'Dummy'">
<button class="cta-edit" (click)="showPurchasingListModal(group.items)">Ändern</button>
</div>
@if (group.orderType !== 'Download' && group.orderType !== 'Dummy') {
<div class="pl-4">
<button class="cta-edit" (click)="showPurchasingListModal(group.items)">Ändern</button>
</div>
}
</div>
<hr
*ngIf="
group.orderType === 'Download' ||
group.orderType === 'Versand' ||
group.orderType === 'B2B-Versand' ||
group.orderType === 'DIG-Versand'
"
/>
</ng-container>
<ng-container *ngFor="let item of group.items; let lastItem = last; let i = index; trackBy: trackByItemId">
<ng-container
*ngIf="group?.orderType !== undefined && (item.features?.orderType === 'Abholung' || item.features?.orderType === 'Rücklage')"
>
<ng-container *ngIf="item?.destination?.data?.targetBranch?.data; let targetBranch">
<ng-container *ngIf="i === 0 || checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)">
@if (
group.orderType === 'Download' ||
group.orderType === 'Versand' ||
group.orderType === 'B2B-Versand' ||
group.orderType === 'DIG-Versand'
) {
<hr
/>
}
}
@for (item of group.items; track trackByItemId(i, item); let lastItem = $last; let i = $index) {
@if (group?.orderType !== undefined && (item.features?.orderType === 'Abholung' || item.features?.orderType === 'Rücklage')) {
@if (item?.destination?.data?.targetBranch?.data; as targetBranch) {
@if (i === 0 || checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)) {
<div
class="flex flex-row items-center px-5 pt-0 pb-[0.875rem] -mt-2 bg-[#F5F7FA]"
[class.multiple-destinations]="checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)"
>
>
<span class="branch-name">{{ targetBranch?.name }} | {{ targetBranch | branchAddress }}</span>
</div>
<hr />
</ng-container>
</ng-container>
</ng-container>
}
}
}
<page-shopping-cart-item
(changeItem)="changeItem($event)"
(changeDummyItem)="changeDummyItem($event)"
@@ -101,19 +91,22 @@
[loadingOnItemChangeById]="loadingOnItemChangeById$ | async"
[loadingOnQuantityChangeById]="loadingOnQuantityChangeById$ | async"
></page-shopping-cart-item>
<hr *ngIf="!lastItem" />
</ng-container>
</ng-container>
@if (!lastItem) {
<hr />
}
}
}
<div class="h-[8.9375rem]"></div>
</div>
<div class="card footer flex flex-col justify-center items-center">
<div class="flex flex-row items-start justify-between w-full mb-1">
<ng-container *ngIf="totalItemCount$ | async; let totalItemCount">
<div *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="total-item-reading-points w-full">
{{ totalItemCount }} Artikel | {{ totalReadingPoints }} Lesepunkte
</div>
</ng-container>
@if (totalItemCount$ | async; as totalItemCount) {
@if (totalReadingPoints$ | async; as totalReadingPoints) {
<div class="total-item-reading-points w-full">
{{ totalItemCount }} Artikel | {{ totalReadingPoints }} Lesepunkte
</div>
}
}
<div class="flex flex-col w-full">
<strong class="total-value">
Zwischensumme {{ shoppingCart?.total?.value | currency: shoppingCart?.total?.currency : 'code' }}
@@ -130,11 +123,18 @@
notificationsControl?.invalid ||
((primaryCtaLabel$ | async) === 'Bestellen' && ((checkingOla$ | async) || (checkoutIsInValid$ | async)))
"
>
>
<ui-spinner [show]="showOrderButtonSpinner">
{{ primaryCtaLabel$ | async }}
</ui-spinner>
</button>
</div>
</ng-container>
</ng-template>
}
}
@if (fetching$ | async) {
<div class="flex items-center justify-center card stretch">
<ui-spinner [show]="true"></ui-spinner>
</div>
}

View File

@@ -2,56 +2,61 @@
Überprüfen Sie die Details.
</h1>
<ng-container *ngIf="buyer$ | async; let buyer">
<div *ngIf="!(showAddresses$ | async)" class="flex flex-row items-start justify-between p-5">
<div class="flex flex-row flex-wrap pr-4">
<ng-container *ngIf="getNameFromBuyer(buyer); let name">
<div class="mr-3">{{ name.label }}</div>
<div class="font-bold">{{ name.value }}</div>
</ng-container>
</div>
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div>
</ng-container>
<ng-container *ngIf="showNotificationChannels$ | async">
<form class="pb-4" *ngIf="control" [formGroup]="control">
<shared-notification-channel-control
[communicationDetails]="communicationDetails$ | async"
(channelActionEvent)="updateNotifications($event)"
[channelActionName]="'Speichern'"
[channelActionLoading]="notificationChannelLoading$ | async"
formGroupName="notificationChannel"
></shared-notification-channel-control>
</form>
</ng-container>
<ng-container *ngIf="payer$ | async; let payer">
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between p-5 pt-0">
<div class="flex flex-row flex-wrap pr-4" data-address-type="Rechnungsadresse" data-which="Rechnungsadresse">
<div class="mr-3" data-what="title">Rechnungsadresse</div>
<div class="font-bold" data-what="address">
{{ payer | payerAddress }}
@if (buyer$ | async; as buyer) {
@if (!(showAddresses$ | async)) {
<div class="flex flex-row items-start justify-between p-5">
<div class="flex flex-row flex-wrap pr-4">
@if (getNameFromBuyer(buyer); as name) {
<div class="mr-3">{{ name.label }}</div>
<div class="font-bold">{{ name.value }}</div>
}
</div>
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div>
}
}
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div>
</ng-container>
@if (showNotificationChannels$ | async) {
@if (control) {
<form class="pb-4" [formGroup]="control">
<shared-notification-channel-control
[communicationDetails]="communicationDetails$ | async"
(channelActionEvent)="updateNotifications($event)"
[channelActionName]="'Speichern'"
[channelActionLoading]="notificationChannelLoading$ | async"
formGroupName="notificationChannel"
></shared-notification-channel-control>
</form>
}
}
<ng-container *ngIf="payer$ | async; let payer">
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between px-5">
<div class="flex flex-row flex-wrap pr-4" data-address-type="Lieferadresse" data-which="Lieferadresse">
<div class="mr-3" data-what="title">Lieferadresse</div>
<div class="font-bold" data-what="address">
{{ shippingAddress$ | async | shippingAddress }}
@if (payer$ | async; as payer) {
@if (showAddresses$ | async) {
<div class="flex flex-row items-start justify-between p-5 pt-0">
<div class="flex flex-row flex-wrap pr-4" data-address-type="Rechnungsadresse" data-which="Rechnungsadresse">
<div class="mr-3" data-what="title">Rechnungsadresse</div>
<div class="font-bold" data-what="address">
{{ payer | payerAddress }}
</div>
</div>
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div>
}
}
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div>
</ng-container>
@if (payer$ | async; as payer) {
@if (showAddresses$ | async) {
<div class="flex flex-row items-start justify-between px-5">
<div class="flex flex-row flex-wrap pr-4" data-address-type="Lieferadresse" data-which="Lieferadresse">
<div class="mr-3" data-what="title">Lieferadresse</div>
<div class="font-bold" data-what="address">
{{ shippingAddress$ | async | shippingAddress }}
</div>
</div>
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div>
}
}
<page-special-comment
class="mb-6 mt-4"

View File

@@ -1,18 +1,21 @@
<div class="item-thumbnail">
<a [routerLink]="productSearchDetailsPath" [queryParams]="{ main_qs: item?.product?.ean }">
<img loading="lazy" *ngIf="item?.product?.ean | productImage; let thumbnailUrl" [src]="thumbnailUrl" [alt]="item?.product?.name" />
@if (item?.product?.ean | productImage; as thumbnailUrl) {
<img loading="lazy" [src]="thumbnailUrl" [alt]="item?.product?.name" />
}
</a>
</div>
<div class="item-contributors">
<a
*ngFor="let contributor of contributors$ | async; let last = last"
[routerLink]="productSearchResultsPath"
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
(click)="$event?.stopPropagation()"
>
{{ contributor }}{{ last ? '' : ';' }}
</a>
@for (contributor of contributors$ | async; track contributor; let last = $last) {
<a
[routerLink]="productSearchResultsPath"
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
(click)="$event?.stopPropagation()"
>
{{ contributor }}{{ last ? '' : ';' }}
</a>
}
</div>
<div
@@ -21,86 +24,106 @@
[class.text-p1]="item?.product?.name?.length >= 50 || !isTablet"
[class.text-p2]="item?.product?.name?.length >= 60 && isTablet"
[class.text-p3]="item?.product?.name?.length >= 100"
>
>
<a [routerLink]="productSearchDetailsPath" [queryParams]="{ main_qs: item?.product?.ean }">{{ item?.product?.name }}</a>
</div>
<div class="item-format" *ngIf="item?.product?.format && item?.product?.formatDetail">
<img
*ngIf="item?.product?.format !== '--'"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
{{ item?.product?.formatDetail }}
</div>
@if (item?.product?.format && item?.product?.formatDetail) {
<div class="item-format">
@if (item?.product?.format !== '--') {
<img
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
}
{{ item?.product?.formatDetail }}
</div>
}
<div class="item-info text-p2">
<div class="mb-1">{{ item?.product?.manufacturer | substr: 25 }} | {{ item?.product?.ean }}</div>
<div class="mb-1">
{{ item?.product?.volume }}
<span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
@if (item?.product?.volume && item?.product?.publicationDate) {
<span>|</span>
}
{{ item?.product?.publicationDate | date }}
</div>
<div *ngIf="notAvailable$ | async">
<span class="text-brand item-date">Nicht verfügbar</span>
</div>
<shared-skeleton-loader class="w-40" *ngIf="refreshingAvailabilit$ | async; else avaTmplt"></shared-skeleton-loader>
<ng-template #avaTmplt>
<div class="item-date" [class.availability-changed]="estimatedShippingDateChanged$ | async" *ngIf="orderType === 'Abholung'">
Abholung ab {{ item?.availability?.estimatedShippingDate | date }}
@if (notAvailable$ | async) {
<div>
<span class="text-brand item-date">Nicht verfügbar</span>
</div>
<div
class="item-date"
[class.availability-changed]="estimatedShippingDateChanged$ | async"
*ngIf="orderType === 'Versand' || orderType === 'B2B-Versand' || orderType === 'DIG-Versand'"
>
<ng-container *ngIf="item?.availability?.estimatedDelivery; else estimatedShippingDate">
Zustellung zwischen {{ (item?.availability?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }}
und
{{ (item?.availability?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}
</ng-container>
<ng-template #estimatedShippingDate>Versand {{ item?.availability?.estimatedShippingDate | date }}</ng-template>
</div>
</ng-template>
}
<div class="item-availability-message" *ngIf="olaError$ | async">Artikel nicht verfügbar</div>
@if (refreshingAvailabilit$ | async) {
<shared-skeleton-loader class="w-40"></shared-skeleton-loader>
} @else {
@if (orderType === 'Abholung') {
<div class="item-date" [class.availability-changed]="estimatedShippingDateChanged$ | async">
Abholung ab {{ item?.availability?.estimatedShippingDate | date }}
</div>
}
@if (orderType === 'Versand' || orderType === 'B2B-Versand' || orderType === 'DIG-Versand') {
<div
class="item-date"
[class.availability-changed]="estimatedShippingDateChanged$ | async"
>
@if (item?.availability?.estimatedDelivery) {
Zustellung zwischen {{ (item?.availability?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }}
und
{{ (item?.availability?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}
} @else {
Versand {{ item?.availability?.estimatedShippingDate | date }}
}
</div>
}
}
@if (olaError$ | async) {
<div class="item-availability-message">Artikel nicht verfügbar</div>
}
</div>
<div class="item-price-stock flex flex-col">
<div class="text-p2 font-bold">{{ item?.availability?.price?.value?.value | currency: 'EUR' : 'code' }}</div>
<div class="text-p2 font-normal">
<ui-quantity-dropdown
*ngIf="!(isDummy$ | async); else quantityDummy"
[ngModel]="item?.quantity"
(ngModelChange)="onChangeQuantity($event)"
[showSpinner]="(loadingOnQuantityChangeById$ | async) === item?.id"
[disabled]="(loadingOnItemChangeById$ | async) === item?.id"
[range]="quantityRange$ | async"
></ui-quantity-dropdown>
<ng-template #quantityDummy>
@if (!(isDummy$ | async)) {
<ui-quantity-dropdown
[ngModel]="item?.quantity"
(ngModelChange)="onChangeQuantity($event)"
[showSpinner]="(loadingOnQuantityChangeById$ | async) === item?.id"
[disabled]="(loadingOnItemChangeById$ | async) === item?.id"
[range]="quantityRange$ | async"
></ui-quantity-dropdown>
} @else {
<div class="mt-2">{{ item?.quantity }}x</div>
</ng-template>
</div>
<div class="quantity-error" *ngIf="quantityError">
{{ quantityError }}
}
</div>
@if (quantityError) {
<div class="quantity-error">
{{ quantityError }}
</div>
}
</div>
<div class="actions" *ngIf="orderType !== 'Download'">
<button
[disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id"
(click)="onChangeItem()"
*ngIf="!(hasOrderType$ | async)"
>
<ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg auswählen</ui-spinner>
</button>
<button
[disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id"
(click)="onChangeItem()"
*ngIf="canEdit$ | async"
>
<ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg ändern</ui-spinner>
</button>
</div>
@if (orderType !== 'Download') {
<div class="actions">
@if (!(hasOrderType$ | async)) {
<button
[disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id"
(click)="onChangeItem()"
>
<ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg auswählen</ui-spinner>
</button>
}
@if (canEdit$ | async) {
<button
[disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id"
(click)="onChangeItem()"
>
<ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg ändern</ui-spinner>
</button>
}
</div>
}

View File

@@ -24,11 +24,15 @@
></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>
@if (!disabled && !!value) {
<button type="reset" class="clear pl-4" (click)="clear(); triggerResize()">
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
}
</div>
</div>
<div *ngIf="!(hasPayer || hasBuyer)" class="text-p3">Zur Info: Sie haben dem Warenkorb noch keinen Kunden hinzugefügt.</div>
@if (!(hasPayer || hasBuyer)) {
<div class="text-p3">Zur Info: Sie haben dem Warenkorb noch keinen Kunden hinzugefügt.</div>
}
</div>

View File

@@ -7,66 +7,63 @@
<h1 class="text-center text-h2 my-1 font-bold">Bestellbestätigung</h1>
<p class="text-center text-p1 mb-10">Nachfolgend erhalten Sie die Übersicht Ihrer Bestellung.</p>
<ng-container *ngFor="let displayOrder of displayOrders$ | async; let i = index; let orderLast = last">
<ng-container *ngIf="i === 0">
@for (displayOrder of displayOrders$ | async; track displayOrder; let i = $index; let orderLast = $last) {
@if (i === 0) {
<div class="flex flex-row items-center bg-white shadow-card min-h-[3.3125rem]">
<div class="text-h3 font-bold px-5 py-[0.875rem]">
{{ displayOrder?.buyer | buyerName }}
</div>
</div>
<hr />
</ng-container>
}
<div class="flex flex-row items-center bg-[#F5F7FA] min-h-[3.3125rem]">
<div class="flex flex-row items-center justify-center px-5 py-[0.875rem]">
<shared-icon
*ngIf="(displayOrder?.items)[0]?.features?.orderType !== 'Dummy'"
class="mr-2"
[size]="(displayOrder?.items)[0]?.features?.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="(displayOrder?.items)[0]?.features?.orderType"
></shared-icon>
@if ((displayOrder?.items)[0]?.features?.orderType !== 'Dummy') {
<shared-icon
class="mr-2"
[size]="(displayOrder?.items)[0]?.features?.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="(displayOrder?.items)[0]?.features?.orderType"
></shared-icon>
}
<p class="text-p1 font-bold mr-3">{{ (displayOrder?.items)[0]?.features?.orderType }}</p>
<div
*ngIf="
(displayOrder?.items)[0]?.features?.orderType === 'Abholung' || (displayOrder?.items)[0]?.features?.orderType === 'Rücklage';
else shippingAddress
"
>
{{ displayOrder.targetBranch?.name }}, {{ displayOrder.targetBranch | branchAddress }}
</div>
<ng-template #shippingAddress>
@if (
(displayOrder?.items)[0]?.features?.orderType === 'Abholung' || (displayOrder?.items)[0]?.features?.orderType === 'Rücklage') {
<div
>
{{ displayOrder.targetBranch?.name }}, {{ displayOrder.targetBranch | branchAddress }}
</div>
} @else {
{{ displayOrder.shippingAddress | branchAddress }}
</ng-template>
<div *ngIf="(displayOrder?.items)[0]?.features?.orderType === 'Download'">
| {{ displayOrder.buyer?.communicationDetails?.email }}
</div>
}
@if ((displayOrder?.items)[0]?.features?.orderType === 'Download') {
<div>
| {{ displayOrder.buyer?.communicationDetails?.email }}
</div>
}
</div>
</div>
<hr />
<div class="flex flex-row justify-between items-center">
<div class="flex flex-col px-5 py-4 bg-white" [attr.data-order-type]="(displayOrder?.items)[0]?.features?.orderType">
<div class="flex flex-row justify-between items-center mb-[0.375rem]">
<div class="flex flex-row">
<span class="w-32">Vorgangs-ID</span>
<ng-container *ngIf="customer$ | async; let customer">
<a
data-which="Vorgangs-ID"
data-what="link"
*ngIf="customer$ | async; let customer"
class="font-bold text-[#0556B4] no-underline"
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
[queryParams]="{ main_qs: customer?.customerNumber, filter_customertype: '' }"
>
{{ displayOrder.orderNumber }}
</a>
</ng-container>
@if (customer$ | async; as customer) {
@if (customer$ | async; as customer) {
<a
data-which="Vorgangs-ID"
data-what="link"
class="font-bold text-[#0556B4] no-underline"
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
[queryParams]="{ main_qs: customer?.customerNumber, filter_customertype: '' }"
>
{{ displayOrder.orderNumber }}
</a>
}
}
<ui-spinner class="text-[#0556B4] h-4 w-4" [show]="!(customer$ | async)"></ui-spinner>
</div>
</div>
<div class="flex flex-row justify-between items-center">
<div class="flex flex-row">
<span class="w-32">Bestelldatum</span>
@@ -74,14 +71,13 @@
</div>
</div>
</div>
<div class="mr-4">
<button
(click)="expanded[i] = !expanded[i]"
type="button"
class="text-[#0556B4] font-bold flex flex-row items-center justify-center"
[class.flex-row-reverse]="!expanded[i]"
>
>
<shared-icon
class="mr-1"
icon="arrow-back"
@@ -93,135 +89,139 @@
</button>
</div>
</div>
<ng-container *ngFor="let order of displayOrder.items; let last = last">
<ng-container *ngIf="expanded[i]">
@for (order of displayOrder.items; track order; let last = $last) {
@if (expanded[i]) {
<div
class="page-checkout-summary__items-tablet px-5 pb-[1.875rem] bg-white"
[class.page-checkout-summary__items]="isDesktop$ | async"
[class.last]="last"
>
>
<div class="page-checkout-summary__items-thumbnail flex flex-row">
<a [routerLink]="getProductSearchDetailsPath(order?.product?.ean)" [queryParams]="getProductSearchDetailsQueryParams(order)">
<img class="w-[3.125rem] max-h-20 mr-2" [src]="order.product?.ean | productImage: 195 : 315 : true" />
</a>
</div>
<div class="page-checkout-summary__items-title whitespace-nowrap overflow-ellipsis overflow-hidden">
<a
class="font-bold no-underline text-[#0556B4]"
[routerLink]="getProductSearchDetailsPath(order?.product?.ean)"
[queryParams]="getProductSearchDetailsQueryParams(order)"
>
>
{{ order?.product?.name }}
</a>
</div>
<div class="page-checkout-summary__items-ssc" *ngIf="(order?.subsetItems)[0]; let subsetItem">
<span class="mr-2">{{ subsetItem.supplierName }}</span>
<span *ngIf="subsetItem?.ssc && subsetItem?.sscText" class="font-bold border-l border-black pl-2">
{{ subsetItem.ssc }} - {{ subsetItem.sscText }}
</span>
</div>
@if ((order?.subsetItems)[0]; as subsetItem) {
<div class="page-checkout-summary__items-ssc">
<span class="mr-2">{{ subsetItem.supplierName }}</span>
@if (subsetItem?.ssc && subsetItem?.sscText) {
<span class="font-bold border-l border-black pl-2">
{{ subsetItem.ssc }} - {{ subsetItem.sscText }}
</span>
}
</div>
}
<div class="page-checkout-summary__items-quantity font-bold justify-self-end">
<span>{{ order.quantity }}x</span>
</div>
<div class="page-checkout-summary__items-price font-bold justify-self-end">
<span>{{ order.price?.value?.value | currency: ' ' }} {{ order.price?.value?.currency }}</span>
</div>
<div class="page-checkout-summary__items-delivery product-details">
<div class="delivery-row" [ngSwitch]="order?.features?.orderType">
<ng-container *ngSwitchCase="'Abholung'">
<span class="order-type">
Abholung ab {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"></ng-container>
</span>
</ng-container>
<ng-container *ngSwitchCase="'Rücklage'">
<span class="order-type">
{{ order?.features?.orderType }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"></ng-container>
</span>
</ng-container>
<ng-container *ngSwitchCase="['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(order?.features?.orderType) > -1">
<ng-container *ngIf="(order?.subsetItems)[0]?.estimatedDelivery; else estimatedShippingDate">
<div class="delivery-row">
@switch (order?.features?.orderType) {
@case ('Abholung') {
<span class="order-type">
Zustellung zwischen
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}
Abholung ab {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"></ng-container>
</span>
</ng-container>
<ng-template #estimatedShippingDate>
<span class="order-type">Versanddatum {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}</span>
</ng-template>
</ng-container>
<ng-container *ngSwitchDefault>
<span class="order-type">{{ order?.features?.orderType }}</span>
</ng-container>
}
@case ('Rücklage') {
<span class="order-type">
{{ order?.features?.orderType }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"></ng-container>
</span>
}
@case (['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(order?.features?.orderType) > -1) {
@if ((order?.subsetItems)[0]?.estimatedDelivery) {
<span class="order-type">
Zustellung zwischen
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}
</span>
} @else {
<span class="order-type">Versanddatum {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}</span>
}
}
@default {
<span class="order-type">{{ order?.features?.orderType }}</span>
}
}
</div>
</div>
</div>
</ng-container>
<hr *ngIf="last" />
</ng-container>
<ng-container *ngIf="orderLast">
}
@if (last) {
<hr />
}
}
@if (orderLast) {
<div class="flex flex-row justify-between items-center min-h-[3.3125rem] bg-white px-5 py-4 rounded-b">
<span *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="text-p2 font-bold">
{{ totalItemCount$ | async }} Artikel | {{ totalReadingPoints }} Lesepunkte
</span>
@if (totalReadingPoints$ | async; as totalReadingPoints) {
<span class="text-p2 font-bold">
{{ totalItemCount$ | async }} Artikel | {{ totalReadingPoints }} Lesepunkte
</span>
}
<div class="flex flex-row items-center justify-center">
<div class="text-p1 font-bold flex flex-row items-center">
<div class="mr-1">Gesamtsumme {{ totalPrice$ | async | currency: ' ' }} {{ totalPriceCurrency$ | async }}</div>
</div>
<div
class="bg-brand text-white font-bold text-p1 outline-none border-none rounded-full px-6 py-3 ml-2"
*ngIf="(takeNowOrders$ | async)?.length === 1 && (isB2BCustomer$ | async)"
>
<button class="cta-goods-out" (click)="navigateToShelfOut()">Zur Warenausgabe</button>
</div>
@if ((takeNowOrders$ | async)?.length === 1 && (isB2BCustomer$ | async)) {
<div
class="bg-brand text-white font-bold text-p1 outline-none border-none rounded-full px-6 py-3 ml-2"
>
<button class="cta-goods-out" (click)="navigateToShelfOut()">Zur Warenausgabe</button>
</div>
}
</div>
</div>
</ng-container>
</ng-container>
}
}
</div>
</div>
<ng-template #abholfrist let-order="order">
<div *ngIf="!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]" class="inline-flex">
<button [uiOverlayTrigger]="deadlineDatepicker" #deadlineDatepickerTrigger="uiOverlayTrigger" class="flex flex-row items-center">
<span class="mx-[0.625rem] font-normal">bis</span>
<strong class="border-r border-[#AEB7C1] pr-4">
{{ ((order?.subsetItems)[0]?.preferredPickUpDate | date: 'dd.MM.yy') || 'TT.MM.JJJJ' }}
</strong>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
</button>
<ui-datepicker
#deadlineDatepicker
yPosition="below"
xPosition="after"
[xOffset]="8"
[min]="minDateDatepicker"
[disabledDaysOfWeek]="[0]"
[(selected)]="selectedDate"
>
<div #content class="grid grid-flow-row gap-2">
<button
class="rounded-full font-bold text-white bg-brand py-px-15 px-px-25"
(click)="updatePreferredPickUpDate(undefined, selectedDate); deadlineDatepickerTrigger.close()"
@if (!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]) {
<div class="inline-flex">
<button [uiOverlayTrigger]="deadlineDatepicker" #deadlineDatepickerTrigger="uiOverlayTrigger" class="flex flex-row items-center">
<span class="mx-[0.625rem] font-normal">bis</span>
<strong class="border-r border-[#AEB7C1] pr-4">
{{ ((order?.subsetItems)[0]?.preferredPickUpDate | date: 'dd.MM.yy') || 'TT.MM.JJJJ' }}
</strong>
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
</button>
<ui-datepicker
#deadlineDatepicker
yPosition="below"
xPosition="after"
[xOffset]="8"
[min]="minDateDatepicker"
[disabledDaysOfWeek]="[0]"
[(selected)]="selectedDate"
>
Für den Warenkorb festlegen
</button>
</div>
</ui-datepicker>
</div>
<div class="fetching" *ngIf="!!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]"></div>
<div #content class="grid grid-flow-row gap-2">
<button
class="rounded-full font-bold text-white bg-brand py-px-15 px-px-25"
(click)="updatePreferredPickUpDate(undefined, selectedDate); deadlineDatepickerTrigger.close()"
>
Für den Warenkorb festlegen
</button>
</div>
</ui-datepicker>
</div>
}
@if (!!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]) {
<div class="fetching"></div>
}
</ng-template>
<div class="relative">
@@ -232,17 +232,18 @@
type="button"
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14 flex flex-row items-center justify-center print-button"
(click)="printOrderConfirmation()"
>
>
<ui-spinner class="min-h-4 min-w-4" [show]="isPrinting$ | async">Bestellbestätigung drucken</ui-spinner>
</button>
<button
*ngIf="hasAbholung$ | async"
type="button"
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14"
(click)="sendOrderConfirmation()"
>
Bestellbestätigung senden
</button>
@if (hasAbholung$ | async) {
<button
type="button"
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14"
(click)="sendOrderConfirmation()"
>
Bestellbestätigung senden
</button>
}
</div>
</div>

View File

@@ -15,7 +15,11 @@ import { CrmCustomerService } from '@domain/crm';
import { ActivatedRoute, Router } from '@angular/router';
import { DomainOmsService } from '@domain/oms';
import { DomainCatalogService } from '@domain/catalog';
import { DisplayOrderDTO, DisplayOrderItemDTO, DisplayOrderItemSubsetDTO } from '@generated/swagger/oms-api';
import {
DisplayOrderDTO,
DisplayOrderItemDTO,
DisplayOrderItemSubsetDTO,
} from '@generated/swagger/oms-api';
import { BreadcrumbService } from '@core/breadcrumb';
import { ApplicationService } from '@core/application';
import { DomainPrinterService } from '@domain/printer';
@@ -49,45 +53,73 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
private _onDestroy$ = new Subject<void>();
processId = Date.now();
selectedDate = this.dateAdapter.today();
minDateDatepicker = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -1);
minDateDatepicker = this.dateAdapter.addCalendarDays(
this.dateAdapter.today(),
-1,
);
updatingPreferredPickUpDate$ = new BehaviorSubject<Record<string, string>>({});
updatingPreferredPickUpDate$ = new BehaviorSubject<Record<string, string>>(
{},
);
displayOrders$ = combineLatest([this.domainCheckoutService.getOrders(), this._route.params]).pipe(
displayOrders$ = combineLatest([
this.domainCheckoutService.getOrders(),
this._route.params,
]).pipe(
map(([orders, params]) => {
let filteredOrders: DisplayOrderDTO[] = [];
if (params?.orderIds) {
const orderIds: string[] = params.orderIds.split(',');
filteredOrders = orders.filter((order) => orderIds.find((id) => Number(id) === order.id));
filteredOrders = orders.filter((order) =>
orderIds.find((id) => Number(id) === order.id),
);
} else {
return filteredOrders;
}
// Ticket #4228 Für die korrekte Gruppierung der Items bei gleichem Bestellziel (Aufsplitten von Abholung und Rücklage)
const ordersWithMultipleFeatures = filteredOrders.filter((order) =>
order.items.find((item) => item.features.orderType !== order.features.orderType),
order.items.find(
(item) => item.features.orderType !== order.features.orderType,
),
);
if (ordersWithMultipleFeatures) {
for (let orderWithMultipleFeatures of ordersWithMultipleFeatures) {
if (orderWithMultipleFeatures?.items?.length > 1) {
const itemsWithOrderFeature = orderWithMultipleFeatures.items.filter(
(item) => item.features.orderType === orderWithMultipleFeatures.features.orderType,
);
const itemsWithDifferentOrderFeature = orderWithMultipleFeatures.items.filter(
(item) => item.features.orderType !== orderWithMultipleFeatures.features.orderType,
);
const itemsWithOrderFeature =
orderWithMultipleFeatures.items.filter(
(item) =>
item.features.orderType ===
orderWithMultipleFeatures.features.orderType,
);
const itemsWithDifferentOrderFeature =
orderWithMultipleFeatures.items.filter(
(item) =>
item.features.orderType !==
orderWithMultipleFeatures.features.orderType,
);
filteredOrders = [...filteredOrders.filter((order) => order.id !== orderWithMultipleFeatures.id)];
filteredOrders = [
...filteredOrders.filter(
(order) => order.id !== orderWithMultipleFeatures.id,
),
];
if (itemsWithOrderFeature?.length > 0) {
filteredOrders = [...filteredOrders, { ...orderWithMultipleFeatures, items: itemsWithOrderFeature }];
filteredOrders = [
...filteredOrders,
{ ...orderWithMultipleFeatures, items: itemsWithOrderFeature },
];
}
if (itemsWithDifferentOrderFeature?.length > 0) {
filteredOrders = [
...filteredOrders,
{ ...orderWithMultipleFeatures, items: itemsWithDifferentOrderFeature },
{
...orderWithMultipleFeatures,
items: itemsWithDifferentOrderFeature,
},
];
}
}
@@ -97,7 +129,9 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
return filteredOrders?.map((order) => {
return {
...order,
items: [...order.items]?.sort((a, b) => a.product?.name.localeCompare(b.product?.name)),
items: [...order.items]?.sort((a, b) =>
a.product?.name.localeCompare(b.product?.name),
),
};
});
}),
@@ -105,14 +139,23 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
);
hasAbholung$ = this.displayOrders$.pipe(
map((displayOrders) => displayOrders.filter((order) => order.features?.orderType === 'Abholung')?.length > 0),
map(
(displayOrders) =>
displayOrders.filter(
(order) => order.features?.orderType === 'Abholung',
)?.length > 0,
),
);
totalItemCount$ = this.displayOrders$.pipe(
map((displayOrders) =>
displayOrders.reduce(
(total, displayOrder) =>
total + displayOrder?.items?.reduce((subTotal, order) => subTotal + order?.quantity, 0),
total +
displayOrder?.items?.reduce(
(subTotal, order) => subTotal + order?.quantity,
0,
),
0,
),
),
@@ -121,7 +164,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
totalReadingPoints$ = this.displayOrders$.pipe(
switchMap((displayOrders) => {
const items = displayOrders
.reduce<DisplayOrderItemDTO[]>((items, order) => [...items, ...order.items], [])
.reduce<DisplayOrderItemDTO[]>(
(items, order) => [...items, ...order.items],
[],
)
.map((i) => {
if (i?.product?.catalogProductNumber) {
return {
@@ -135,7 +181,14 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
if (items.length !== 0) {
return this.domainCatalogService
.getPromotionPoints({ items })
.pipe(map((response) => Object.values(response.result).reduce((sum, points) => sum + points, 0)));
.pipe(
map((response) =>
Object.values(response.result).reduce(
(sum, points) => sum + points,
0,
),
),
);
} else {
return NEVER;
}
@@ -147,7 +200,11 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
displayOrders.reduce(
(total, displayOrder) =>
total +
displayOrder?.items?.reduce((subTotal, order) => subTotal + order?.price?.value?.value * order.quantity, 0),
displayOrder?.items?.reduce(
(subTotal, order) =>
subTotal + order?.price?.value?.value * order.quantity,
0,
),
0,
),
),
@@ -162,22 +219,33 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
containsDeliveryOrder$ = this.displayOrders$.pipe(
map(
(displayOrders) =>
displayOrders.filter((o) => ['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(o.features?.orderType) > -1)
?.length > 0,
displayOrders.filter(
(o) =>
['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(
o.features?.orderType,
) > -1,
)?.length > 0,
),
);
customer$ = this.displayOrders$.pipe(
switchMap((o) => this.customerService.getCustomers(o[0].buyerNumber, { take: 5 })),
switchMap((o) =>
this.customerService.getCustomers(o[0].buyerNumber, { take: 5 }),
),
map((customers) => customers.result[0]),
shareReplay(),
);
isB2BCustomer$ = this.customer$.pipe(map((customer) => customer?.features?.find((f) => f.key === 'b2b') != null));
isB2BCustomer$ = this.customer$.pipe(
map((customer) => customer?.features?.find((f) => f.key === 'b2b') != null),
);
takeNowOrders$ = this.displayOrders$.pipe(
map((displayOrders) =>
displayOrders.filter((o) => o.items.find((oi) => oi.features?.orderType === 'Rücklage') != null),
displayOrders.filter(
(o) =>
o.items.find((oi) => oi.features?.orderType === 'Rücklage') != null,
),
),
);
@@ -210,7 +278,9 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
private _cdr: ChangeDetectorRef,
) {
this.breadcrumb
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['checkout'])
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, [
'checkout',
])
.pipe(first())
.subscribe(async (crumbs) => {
for await (const crumb of crumbs) {
@@ -264,7 +334,8 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
getProductSearchDetailsQueryParams(item: DisplayOrderItemDTO) {
return {
main_qs: item?.product?.ean,
filter_format: item?.features?.orderType === 'Download' ? 'eb;dl' : undefined,
filter_format:
item?.features?.orderType === 'Download' ? 'eb;dl' : undefined,
};
}
@@ -274,9 +345,14 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
try {
const items = item ? [item] : await this.getAllOrderItems();
const subsetItems = items
.filter((item) => ['Rücklage', 'Abholung'].includes(item.features.orderType))
.filter((item) =>
['Rücklage', 'Abholung'].includes(item.features.orderType),
)
// .flatMap((item) => item.subsetItems);
.reduce<DisplayOrderItemSubsetDTO[]>((acc, item) => [...acc, ...item.subsetItems], []);
.reduce<DisplayOrderItemSubsetDTO[]>(
(acc, item) => [...acc, ...item.subsetItems],
[],
);
subsetItems.forEach((item) => (data[`${item.id}`] = date?.toISOString()));
try {
@@ -310,7 +386,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
async getAllOrderItems() {
const orders = await this.displayOrders$.pipe(first()).toPromise();
return orders.reduce<DisplayOrderItemDTO[]>((agg, order) => [...agg, ...order.items], []);
return orders.reduce<DisplayOrderItemDTO[]>(
(agg, order) => [...agg, ...order.items],
[],
);
}
async updateDisplayOrderItem(item: DisplayOrderItemDTO) {
@@ -322,9 +401,16 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
if (takeNowOrders.length != 1) return;
try {
await this.router.navigate(this._shelfOutNavigationService.listRoute({ processId: Date.now() }).path, {
queryParams: { main_qs: takeNowOrders[0].orderNumber, filter_supplier_id: '16' },
});
await this.router.navigate(
this._shelfOutNavigationService.listRoute({ processId: Date.now() })
.path,
{
queryParams: {
main_qs: takeNowOrders[0].orderNumber,
filter_supplier_id: '16',
},
},
);
} catch (e) {
console.error(e);
}
@@ -344,7 +430,8 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
.pipe(
first(),
map((printers) => {
if (Array.isArray(printers)) return printers.find((printer) => printer.selected === true);
if (Array.isArray(printers))
return printers.find((printer) => printer.selected === true);
}),
)
.toPromise();
@@ -362,10 +449,16 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
const result = await this.domainPrinterService
.printOrder({ orderIds: orders.map((o) => o.id), printer })
.toPromise();
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' });
this._toaster.open({
type: 'success',
message: 'Bestellbestätigung wurde gedruckt',
});
return result;
} catch (error) {
this._toaster.open({ type: 'danger', message: 'Fehler beim Drucken der Bestellbestätigung' });
this._toaster.open({
type: 'danger',
message: 'Fehler beim Drucken der Bestellbestätigung',
});
} finally {
this.isPrinting$.next(false);
}
@@ -381,12 +474,21 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
} else {
try {
const result = await this.domainPrinterService
.printOrder({ orderIds: orders.map((o) => o.id), printer: selectedPrinter.key })
.printOrder({
orderIds: orders.map((o) => o.id),
printer: selectedPrinter.key,
})
.toPromise();
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' });
this._toaster.open({
type: 'success',
message: 'Bestellbestätigung wurde gedruckt',
});
return result;
} catch (error) {
this._toaster.open({ type: 'danger', message: 'Fehler beim Drucken der Bestellbestätigung' });
this._toaster.open({
type: 'danger',
message: 'Fehler beim Drucken der Bestellbestätigung',
});
} finally {
this.isPrinting$.next(false);
}

View File

@@ -1,35 +1,35 @@
<ng-container *ngIf="orderItem$ | async; let orderItem">
@if (orderItem$ | async; as orderItem) {
<div #features class="page-customer-order-details-item__features">
<ng-container *ngIf="orderItem?.features?.prebooked">
@if (orderItem?.features?.prebooked) {
<img [uiOverlayTrigger]="prebookedTooltip" src="/assets/images/tag_icon_preorder.svg" [alt]="orderItem?.features?.prebooked" />
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #prebookedTooltip [closeable]="true">
Artikel wird für Sie vorgemerkt.
</ui-tooltip>
</ng-container>
<ng-container *ngIf="notificationsSent$ | async; let notificationsSent">
<ng-container *ngIf="notificationsSent?.NOTIFICATION_EMAIL">
}
@if (notificationsSent$ | async; as notificationsSent) {
@if (notificationsSent?.NOTIFICATION_EMAIL) {
<img [uiOverlayTrigger]="emailTooltip" src="/assets/images/email_bookmark.svg" />
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #emailTooltip [closeable]="true">
Per E-Mail benachrichtigt
<br />
<ng-container *ngFor="let notification of notificationsSent?.NOTIFICATION_EMAIL">
@for (notification of notificationsSent?.NOTIFICATION_EMAIL; track notification) {
{{ notification | date: 'dd.MM.yyyy | HH:mm' }} Uhr
<br />
</ng-container>
}
</ui-tooltip>
</ng-container>
<ng-container *ngIf="notificationsSent?.NOTIFICATION_SMS">
}
@if (notificationsSent?.NOTIFICATION_SMS) {
<img [uiOverlayTrigger]="smsTooltip" src="/assets/images/sms_bookmark.svg" />
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #smsTooltip [closeable]="true">
Per SMS benachrichtigt
<br />
<ng-container *ngFor="let notification of notificationsSent?.NOTIFICATION_SMS">
@for (notification of notificationsSent?.NOTIFICATION_SMS; track notification) {
{{ notification | date: 'dd.MM.yyyy | HH:mm' }} Uhr
<br />
</ng-container>
}
</ui-tooltip>
</ng-container>
</ng-container>
}
}
</div>
<div class="page-customer-order-details-item__item-container">
<div class="page-customer-order-details-item__thumbnail">
@@ -42,169 +42,190 @@
#elementDistance="uiElementDistance"
[style.max-width.px]="elementDistance.distanceChange | async"
class="flex flex-col"
>
>
<div class="font-normal mb-[0.375rem]">{{ orderItem.product?.contributors }}</div>
<div>{{ orderItem.product?.name }}</div>
</h3>
<div class="history-wrapper flex flex-col items-end justify-center">
<button class="cta-history text-p1" (click)="historyClick.emit(orderItem)">Historie</button>
<input
*ngIf="selectable$ | async"
[ngModel]="selected$ | async"
(ngModelChange)="setSelected($event)"
class="isa-select-bullet mt-4"
type="checkbox"
/>
@if (selectable$ | async) {
<input
[ngModel]="selected$ | async"
(ngModelChange)="setSelected($event)"
class="isa-select-bullet mt-4"
type="checkbox"
/>
}
</div>
</div>
<div class="detail">
<div class="label">Menge</div>
<div class="value">
<ng-container *ngIf="!(canChangeQuantity$ | async)">{{ orderItem?.quantity }}x</ng-container>
<ui-quantity-dropdown
*ngIf="canChangeQuantity$ | async"
[showTrash]="false"
[range]="orderItem?.quantity"
[(ngModel)]="quantity"
[showSpinner]="false"
></ui-quantity-dropdown>
@if (!(canChangeQuantity$ | async)) {
{{ orderItem?.quantity }}x
}
@if (canChangeQuantity$ | async) {
<ui-quantity-dropdown
[showTrash]="false"
[range]="orderItem?.quantity"
[(ngModel)]="quantity"
[showSpinner]="false"
></ui-quantity-dropdown>
}
<span class="overall-quantity">(von {{ orderItem?.overallQuantity }})</span>
</div>
</div>
<div class="detail" *ngIf="!!orderItem.product?.formatDetail">
<div class="label">Format</div>
<div class="value">
<img
*ngIf="orderItem?.product?.format && orderItem?.product?.format !== 'UNKNOWN'"
class="format-icon"
[src]="'/assets/images/Icon_' + orderItem.product?.format + '.svg'"
alt="format icon"
/>
<span>{{ orderItem.product?.formatDetail }}</span>
@if (!!orderItem.product?.formatDetail) {
<div class="detail">
<div class="label">Format</div>
<div class="value">
@if (orderItem?.product?.format && orderItem?.product?.format !== 'UNKNOWN') {
<img
class="format-icon"
[src]="'/assets/images/Icon_' + orderItem.product?.format + '.svg'"
alt="format icon"
/>
}
<span>{{ orderItem.product?.formatDetail }}</span>
</div>
</div>
</div>
<div class="detail" *ngIf="!!orderItem.product?.ean">
<div class="label">ISBN/EAN</div>
<div class="value">{{ orderItem.product?.ean }}</div>
</div>
<div class="detail" *ngIf="orderItem.price !== undefined">
<div class="label">Preis</div>
<div class="value">{{ orderItem.price | currency: 'EUR' }}</div>
</div>
<div class="detail" *ngIf="!!orderItem.retailPrice?.vat?.inPercent">
<div class="label">MwSt</div>
<div class="value">{{ orderItem.retailPrice?.vat?.inPercent }}%</div>
</div>
}
@if (!!orderItem.product?.ean) {
<div class="detail">
<div class="label">ISBN/EAN</div>
<div class="value">{{ orderItem.product?.ean }}</div>
</div>
}
@if (orderItem.price !== undefined) {
<div class="detail">
<div class="label">Preis</div>
<div class="value">{{ orderItem.price | currency: 'EUR' }}</div>
</div>
}
@if (!!orderItem.retailPrice?.vat?.inPercent) {
<div class="detail">
<div class="label">MwSt</div>
<div class="value">{{ orderItem.retailPrice?.vat?.inPercent }}%</div>
</div>
}
<hr class="border-[#EDEFF0] border-t-2 my-4" />
<div class="detail" *ngIf="orderItem.supplier">
<div class="label">Lieferant</div>
<div class="value">{{ orderItem.supplier }}</div>
</div>
<div class="detail" *ngIf="!!orderItem.ssc || !!orderItem.sscText">
<div class="label">Meldenummer</div>
<div class="value">{{ orderItem.ssc }} - {{ orderItem.sscText }}</div>
</div>
<div class="detail" *ngIf="!!orderItem.targetBranch">
<div class="label">Zielfiliale</div>
<div class="value">{{ orderItem.targetBranch }}</div>
</div>
@if (orderItem.supplier) {
<div class="detail">
<div class="label">Lieferant</div>
<div class="value">{{ orderItem.supplier }}</div>
</div>
}
@if (!!orderItem.ssc || !!orderItem.sscText) {
<div class="detail">
<div class="label">Meldenummer</div>
<div class="value">{{ orderItem.ssc }} - {{ orderItem.sscText }}</div>
</div>
}
@if (!!orderItem.targetBranch) {
<div class="detail">
<div class="label">Zielfiliale</div>
<div class="value">{{ orderItem.targetBranch }}</div>
</div>
}
<div class="detail">
<div class="label">
<ng-container
*ngIf="
orderItemFeature(orderItem) === 'Versand' ||
orderItemFeature(orderItem) === 'B2B-Versand' ||
orderItemFeature(orderItem) === 'DIG-Versand'
"
>
@if (
orderItemFeature(orderItem) === 'Versand' ||
orderItemFeature(orderItem) === 'B2B-Versand' ||
orderItemFeature(orderItem) === 'DIG-Versand'
) {
{{ orderItem?.estimatedDelivery ? 'Lieferung zwischen' : 'Lieferung ab' }}
</ng-container>
<ng-container *ngIf="orderItemFeature(orderItem) === 'Abholung' || orderItemFeature(orderItem) === 'Rücklage'">
}
@if (orderItemFeature(orderItem) === 'Abholung' || orderItemFeature(orderItem) === 'Rücklage') {
Abholung ab
</ng-container>
}
</div>
<ng-container *ngIf="!!orderItem?.estimatedDelivery || !!orderItem?.estimatedShippingDate">
@if (!!orderItem?.estimatedDelivery || !!orderItem?.estimatedShippingDate) {
<div class="value bg-[#D8DFE5] rounded w-max px-2">
<ng-container *ngIf="!!orderItem?.estimatedDelivery; else estimatedShippingDate">
@if (!!orderItem?.estimatedDelivery) {
{{ orderItem?.estimatedDelivery?.start | date: 'dd.MM.yy' }} und
{{ orderItem?.estimatedDelivery?.stop | date: 'dd.MM.yy' }}
</ng-container>
} @else {
@if (!!orderItem?.estimatedShippingDate) {
{{ orderItem?.estimatedShippingDate | date: 'dd.MM.yy' }}
}
}
</div>
</ng-container>
<ng-template #estimatedShippingDate>
<ng-container *ngIf="!!orderItem?.estimatedShippingDate">
{{ orderItem?.estimatedShippingDate | date: 'dd.MM.yy' }}
</ng-container>
</ng-template>
}
</div>
<div class="page-customer-order-details-item__tracking-details" *ngIf="getOrderItemTrackingData(orderItem); let trackingData">
<div class="label">{{ trackingData.length > 1 ? 'Sendungsnummern' : 'Sendungsnummer' }}</div>
<ng-container *ngFor="let tracking of trackingData">
<ng-container *ngIf="tracking.trackingProvider === 'DHL' && !isNative; else noTrackingLink">
<a class="value text-[#0556B4]" [href]="getTrackingNumberLink(tracking.trackingNumber)" target="_blank">
{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}
</a>
</ng-container>
<ng-template #noTrackingLink>
<p class="value">{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}</p>
</ng-template>
</ng-container>
</div>
@if (getOrderItemTrackingData(orderItem); as trackingData) {
<div class="page-customer-order-details-item__tracking-details">
<div class="label">{{ trackingData.length > 1 ? 'Sendungsnummern' : 'Sendungsnummer' }}</div>
@for (tracking of trackingData; track tracking) {
@if (tracking.trackingProvider === 'DHL' && !isNative) {
<a class="value text-[#0556B4]" [href]="getTrackingNumberLink(tracking.trackingNumber)" target="_blank">
{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}
</a>
} @else {
<p class="value">{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}</p>
}
}
</div>
}
<hr class="border-[#EDEFF0] border-t-2 my-4" />
<div class="detail" *ngIf="!!orderItem?.compartmentCode">
<div class="label">Abholfachnr.</div>
<div class="value">{{ orderItem?.compartmentCode }}</div>
</div>
@if (!!orderItem?.compartmentCode) {
<div class="detail">
<div class="label">Abholfachnr.</div>
<div class="value">{{ orderItem?.compartmentCode }}</div>
</div>
}
<div class="detail">
<div class="label">Vormerker</div>
<div class="value">{{ orderItem.isPrebooked ? 'Ja' : 'Nein' }}</div>
</div>
<hr class="border-[#EDEFF0] border-t-2 my-4" />
<div class="detail" *ngIf="!!orderItem.paymentProcessing">
<div class="label">Zahlungsweg</div>
<div class="value">{{ orderItem.paymentProcessing || '-' }}</div>
</div>
<div class="detail" *ngIf="!!orderItem.paymentType">
<div class="label">Zahlungsart</div>
<div class="value">{{ orderItem.paymentType | paymentType }}</div>
</div>
<h4 class="receipt-header" *ngIf="receiptCount$ | async; let count">
{{ count > 1 ? 'Belege' : 'Beleg' }}
</h4>
<ng-container *ngFor="let receipt of receipts$ | async">
<div class="detail" *ngIf="!!receipt?.receiptNumber">
<div class="label">Belegnummer</div>
<div class="value">{{ receipt?.receiptNumber }}</div>
@if (!!orderItem.paymentProcessing) {
<div class="detail">
<div class="label">Zahlungsweg</div>
<div class="value">{{ orderItem.paymentProcessing || '-' }}</div>
</div>
<div class="detail" *ngIf="!!receipt?.printedDate">
<div class="label">Erstellt am</div>
<div class="value">{{ receipt?.printedDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
}
@if (!!orderItem.paymentType) {
<div class="detail">
<div class="label">Zahlungsart</div>
<div class="value">{{ orderItem.paymentType | paymentType }}</div>
</div>
<div class="detail" *ngIf="!!receipt?.receiptText">
<div class="label">Rechnungstext</div>
<div class="value">{{ receipt?.receiptText || '-' }}</div>
</div>
<div class="detail" *ngIf="!!receipt?.receiptType">
<div class="label">Belegart</div>
<div class="value">
{{ receipt?.receiptType === 1 ? 'Lieferschein' : receipt?.receiptType === 64 ? 'Zahlungsbeleg' : '-' }}
}
@if (receiptCount$ | async; as count) {
<h4 class="receipt-header">
{{ count > 1 ? 'Belege' : 'Beleg' }}
</h4>
}
@for (receipt of receipts$ | async; track receipt) {
@if (!!receipt?.receiptNumber) {
<div class="detail">
<div class="label">Belegnummer</div>
<div class="value">{{ receipt?.receiptNumber }}</div>
</div>
</div>
</ng-container>
}
@if (!!receipt?.printedDate) {
<div class="detail">
<div class="label">Erstellt am</div>
<div class="value">{{ receipt?.printedDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</div>
}
@if (!!receipt?.receiptText) {
<div class="detail">
<div class="label">Rechnungstext</div>
<div class="value">{{ receipt?.receiptText || '-' }}</div>
</div>
}
@if (!!receipt?.receiptType) {
<div class="detail">
<div class="label">Belegart</div>
<div class="value">
{{ receipt?.receiptType === 1 ? 'Lieferschein' : receipt?.receiptType === 64 ? 'Zahlungsbeleg' : '-' }}
</div>
</div>
}
}
<div class="page-customer-order-details-item__comment flex flex-col items-start mt-[1.625rem]">
<div class="label mb-[0.375rem]">Anmerkung</div>
<div class="flex flex-row w-full">
<textarea
matInput
@@ -222,27 +243,28 @@
[formControl]="specialCommentControl"
[class.inactive]="!specialCommentControl.dirty"
></textarea>
<div class="comment-actions">
<button
type="reset"
class="clear"
*ngIf="!!specialCommentControl.value?.length"
(click)="specialCommentControl.setValue(''); saveSpecialComment(); triggerResize()"
>
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
<button
class="cta-save"
type="submit"
*ngIf="specialCommentControl?.enabled && specialCommentControl.dirty"
(click)="saveSpecialComment()"
>
Speichern
</button>
@if (!!specialCommentControl.value?.length) {
<button
type="reset"
class="clear"
(click)="specialCommentControl.setValue(''); saveSpecialComment(); triggerResize()"
>
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
}
@if (specialCommentControl?.enabled && specialCommentControl.dirty) {
<button
class="cta-save"
type="submit"
(click)="saveSpecialComment()"
>
Speichern
</button>
}
</div>
</div>
</div>
</div>
</div>
</ng-container>
}

View File

@@ -1,19 +1,20 @@
<div class="page-customer-order-details-tags__wrapper">
<button
class="page-customer-order-details-tags__tag"
type="button"
[class.selected]="tag === (selected$ | async) && !inputFocus.focused"
*ngFor="let tag of defaultTags"
(click)="setCompartmentInfo(tag)"
>
{{ tag }}
</button>
@for (tag of defaultTags; track tag) {
<button
class="page-customer-order-details-tags__tag"
type="button"
[class.selected]="tag === (selected$ | async) && !inputFocus.focused"
(click)="setCompartmentInfo(tag)"
>
{{ tag }}
</button>
}
<button
(click)="inputFocus.focus()"
type="button"
class="page-customer-order-details-tags__tag"
[class.selected]="(inputValue$ | async) === (selected$ | async) && (inputValue$ | async)"
>
>
<input
#inputFocus="uiFocus"
uiFocus
@@ -23,6 +24,6 @@
placeholder="..."
[size]="controlSize$ | async"
maxlength="15"
/>
/>
</button>
</div>

View File

@@ -1,4 +1,4 @@
import { NgFor, AsyncPipe } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, forwardRef } from '@angular/core';
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { UiCommonModule } from '@ui/common';
@@ -14,7 +14,7 @@ import { PickUpShelfDetailsTagsComponent } from '../../../pickup-shelf/shared/pi
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-pickup-shelf-details-tags' },
standalone: true,
imports: [NgFor, UiCommonModule, FormsModule, AsyncPipe, MatomoModule],
imports: [UiCommonModule, FormsModule, AsyncPipe, MatomoModule],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => PickUpShelfDetailsTagsComponent), multi: true },
],

View File

@@ -4,39 +4,44 @@
(handleAction)="handleAction($event)"
[order]="order$ | async"
></page-customer-order-details-header>
<page-customer-order-details-item
class="mb-px-2"
*ngFor="let item of items$ | async"
[orderItem]="item"
[order]="order$ | async"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
(specialCommentChanged)="onSpecialCommentChange()"
></page-customer-order-details-item>
<page-customer-order-details-tags *ngIf="showTagsComponent$ | async"></page-customer-order-details-tags>
@for (item of items$ | async; track item) {
<page-customer-order-details-item
class="mb-px-2"
[orderItem]="item"
[order]="order$ | async"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
(specialCommentChanged)="onSpecialCommentChange()"
></page-customer-order-details-item>
}
@if (showTagsComponent$ | async) {
<page-customer-order-details-tags></page-customer-order-details-tags>
}
</div>
<div class="page-customer-order-details__action-wrapper">
<button
[disabled]="addToPreviousCompartmentActionDisabled$ | async"
*ngIf="addToPreviousCompartmentAction$ | async; let action"
class="cta-action shadow-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction(action, { compartmentCode: latestCompartmentCode, compartmentInfo: latestCompartmentInfo })"
>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">
{{ latestCompartmentCode$ | async | addToPreviousCompartmentCodeLabelPipe }} zubuchen
</ui-spinner>
</button>
@if (addToPreviousCompartmentAction$ | async; as action) {
<button
[disabled]="addToPreviousCompartmentActionDisabled$ | async"
class="cta-action shadow-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction(action, { compartmentCode: latestCompartmentCode, compartmentInfo: latestCompartmentInfo })"
>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">
{{ latestCompartmentCode$ | async | addToPreviousCompartmentCodeLabelPipe }} zubuchen
</ui-spinner>
</button>
}
<button
[disabled]="actionsDisabled$ | async"
class="cta-action shadow-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
*ngFor="let action of mainActions$ | async"
(click)="handleAction(action)"
>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
</button>
@for (action of mainActions$ | async; track action) {
<button
[disabled]="actionsDisabled$ | async"
class="cta-action shadow-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction(action)"
>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
</button>
}
</div>

View File

@@ -1,3 +1,5 @@
<div *ngIf="items$ | async; let items">
<shared-goods-in-out-order-edit (navigation)="navigateToDetailsPage($event)" [items]="items"></shared-goods-in-out-order-edit>
</div>
@if (items$ | async; as items) {
<div>
<shared-goods-in-out-order-edit (navigation)="navigateToDetailsPage($event)" [items]="items"></shared-goods-in-out-order-edit>
</div>
}

View File

@@ -1,19 +1,19 @@
<div class="hidden desktop-large:block" [class.show-filter]="showFilter">
<ng-container *ngIf="filter$ | async; let filter">
@if (filter$ | async; as filter) {
<div class="customer-orders-search-filter-content">
<div class="w-full flex flex-row justify-end items-center">
<button (click)="clearFilter(filter)" class="text-[#0556B4] p-4">Alle Filter entfernen</button>
<a
*ngIf="showFilterClose$ | async"
class="text-black p-4 outline-none border-none bg-transparent"
[routerLink]="closeFilterRoute"
(click)="showFilter = false"
queryParamsHandling="preserve"
>
<shared-icon icon="close" [size]="25"></shared-icon>
</a>
@if (showFilterClose$ | async) {
<a
class="text-black p-4 outline-none border-none bg-transparent"
[routerLink]="closeFilterRoute"
(click)="showFilter = false"
queryParamsHandling="preserve"
>
<shared-icon icon="close" [size]="25"></shared-icon>
</a>
}
</div>
<div class="customer-orders-search-filter-content-main -mt-14 desktop-small:-mt-8 desktop-large:-mt-12">
<h1 class="text-h3 text-[1.625rem] font-bold text-center pt-6 pb-10">Filter</h1>
<shared-filter
@@ -22,20 +22,18 @@
(search)="applyFilter(filter)"
[hint]="message$ | async"
[scanner]="true"
>
>
<page-order-branch-id-input *sharedFilterCustomInput="'order_branch_id'; let input" [input]="input"></page-order-branch-id-input>
</shared-filter>
</div>
<div class="cta-wrapper">
<button class="cta-reset-filter" (click)="resetFilter()" [disabled]="loading$ | async">Filter zurücksetzen</button>
<button class="cta-apply-filter" (click)="applyFilter(filter)" [disabled]="(loading$ | async) || !hasSelectedOptions(filter)">
<ui-spinner [show]="loading$ | async">Filter anwenden</ui-spinner>
</button>
</div>
</div>
</ng-container>
}
</div>
<div class="desktop-large:hidden" [class.hidden]="showFilter">
<page-customer-order-search-main (showFilter)="showFilter = true"></page-customer-order-search-main>

View File

@@ -11,53 +11,57 @@
<br />
oder scannen Sie die Kundenkarte.
</p>
<ng-container *ngIf="filter$ | async; let filter">
<shared-filter-filter-group-main
class="mb-8 w-full"
*ngIf="!(isDesktop$ | async)"
[inputGroup]="filter?.filter | group: 'main'"
></shared-filter-filter-group-main>
@if (filter$ | async; as filter) {
@if (!(isDesktop$ | async)) {
<shared-filter-filter-group-main
class="mb-8 w-full"
[inputGroup]="filter?.filter | group: 'main'"
></shared-filter-filter-group-main>
}
<div class="flex flex-row px-12 justify-center desktop-large:px-0">
<shared-filter-input-group-main
class="block w-full mr-3 desktop-large:mx-auto"
*ngIf="filter?.input | group: 'main'; let inputGroup"
[inputGroup]="inputGroup"
[loading]="loading$ | async"
(search)="search(filter)"
[hint]="message$ | async"
[scanner]="true"
></shared-filter-input-group-main>
<button
*ngIf="!(isDesktop$ | async)"
(click)="showFilter.emit()"
class="page-search-main__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
type="button"
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</button>
@if (filter?.input | group: 'main'; as inputGroup) {
<shared-filter-input-group-main
class="block w-full mr-3 desktop-large:mx-auto"
[inputGroup]="inputGroup"
[loading]="loading$ | async"
(search)="search(filter)"
[hint]="message$ | async"
[scanner]="true"
></shared-filter-input-group-main>
}
@if (!(isDesktop$ | async)) {
<button
(click)="showFilter.emit()"
class="page-search-main__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
type="button"
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</button>
}
</div>
<div
class="flex flex-col items-start ml-12 desktop-large:ml-8 py-6 bg-white overflow-hidden h-[calc(100%-21rem)] desktop-large:h-[calc(100%-15rem)]"
>
>
<h3 class="text-p3 font-bold mb-3">Deine letzten Suchanfragen</h3>
<ul class="flex flex-col justify-start overflow-hidden overflow-y-scroll items-start m-0 p-0 bg-white w-full">
<li class="list-none pb-3" *ngFor="let query of history$ | async">
<button
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0"
(click)="setQueryHistory(filter, query)"
>
<shared-icon
class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
icon="magnify"
[size]="20"
></shared-icon>
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ query }}</p>
</button>
</li>
@for (query of history$ | async; track query) {
<li class="list-none pb-3">
<button
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0"
(click)="setQueryHistory(filter, query)"
>
<shared-icon
class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
icon="magnify"
[size]="20"
></shared-icon>
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ query }}</p>
</button>
</li>
}
</ul>
</div>
</ng-container>
}
</div>

View File

@@ -5,19 +5,20 @@
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
[queryParams]="queryParams"
(click)="isDesktopLarge ? scrollIntoView() : ''"
>
>
<div
class="page-customer-order-item__item-grid-container"
[class.page-customer-order-item__item-grid-container-main]="primaryOutletActive"
>
>
<div class="page-customer-order-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]">
<img
class="page-customer-order-item__item-image w-[3.125rem] max-h-[4.9375rem]"
loading="lazy"
*ngIf="item?.product?.ean | productImage; let productImage"
[src]="productImage"
[alt]="item?.product?.name"
/>
@if (item?.product?.ean | productImage; as productImage) {
<img
class="page-customer-order-item__item-image w-[3.125rem] max-h-[4.9375rem]"
loading="lazy"
[src]="productImage"
[alt]="item?.product?.name"
/>
}
</div>
<div
@@ -27,7 +28,7 @@
[class.text-p2]="item?.product?.name?.length >= 50 && isTablet"
[class.text-p3]="item?.product?.name?.length >= 60 || !isTablet"
[class.text-p4]="item?.product?.name?.length >= 100"
>
>
{{ item?.product?.name }}
</div>
@@ -35,88 +36,111 @@
{{ item?.specialComment }}
</div>
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-format desktop-small:text-p2">
<div *ngIf="item?.product?.format && item?.product?.formatDetail" class="font-bold flex flex-row">
<img
class="mr-3"
*ngIf="item?.product?.format !== '--'"
loading="lazy"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
{{ item?.product?.formatDetail | substr: 30 }}
@if (primaryOutletActive) {
<div class="page-customer-order-item__item-format desktop-small:text-p2">
@if (item?.product?.format && item?.product?.formatDetail) {
<div class="font-bold flex flex-row">
@if (item?.product?.format !== '--') {
<img
class="mr-3"
loading="lazy"
src="assets/images/Icon_{{ item?.product?.format }}.svg"
[alt]="item?.product?.formatDetail"
/>
}
{{ item?.product?.formatDetail | substr: 30 }}
</div>
}
</div>
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-ean desktop-small:text-p2">
{{ item?.product?.ean }}
</div>
@if (primaryOutletActive) {
<div class="page-customer-order-item__item-ean desktop-small:text-p2">
{{ item?.product?.ean }}
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-price desktop-small:text-p2 font-bold">
{{ item.price | currency: 'EUR' : 'code' }}
</div>
@if (primaryOutletActive) {
<div class="page-customer-order-item__item-price desktop-small:text-p2 font-bold">
{{ item.price | currency: 'EUR' : 'code' }}
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-changed desktop-small:text-p2">
<ng-container [ngSwitch]="showChangeDate$ | async">
<div class="flex flex-row" *ngSwitchCase="true">
<div class="min-w-[7.5rem]">Geändert</div>
<div class="font-bold">{{ item?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</div>
<div class="flex flex-row" *ngSwitchCase="false">
<div class="min-w-[7.5rem]">Bestelldatum</div>
<div class="font-bold">{{ item?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</div>
</ng-container>
</div>
@if (primaryOutletActive) {
<div class="page-customer-order-item__item-changed desktop-small:text-p2">
@switch (showChangeDate$ | async) {
@case (true) {
<div class="flex flex-row">
<div class="min-w-[7.5rem]">Geändert</div>
<div class="font-bold">{{ item?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</div>
}
@case (false) {
<div class="flex flex-row">
<div class="min-w-[7.5rem]">Bestelldatum</div>
<div class="font-bold">{{ item?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</div>
}
}
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-quantity flex flex-row desktop-small:text-p2">
<div class="min-w-[7.5rem]">Menge</div>
<div class="font-bold">{{ item.quantity }} x</div>
</div>
@if (primaryOutletActive) {
<div class="page-customer-order-item__item-quantity flex flex-row desktop-small:text-p2">
<div class="min-w-[7.5rem]">Menge</div>
<div class="font-bold">{{ item.quantity }} x</div>
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-target-branch flex flex-row desktop-small:text-p2">
<ng-container *ngIf="item.orderType === 1; else showDelivery">
<div class="min-w-[7.5rem]">Zielfiliale</div>
<div class="font-bold">{{ item.targetBranch }}</div>
</ng-container>
<ng-template #showDelivery>
<div class="min-w-[7.5rem]">Versanddatum</div>
<div class="font-bold">{{ item?.estimatedShippingDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</ng-template>
</div>
@if (primaryOutletActive) {
<div class="page-customer-order-item__item-target-branch flex flex-row desktop-small:text-p2">
@if (item.orderType === 1) {
<div class="min-w-[7.5rem]">Zielfiliale</div>
<div class="font-bold">{{ item.targetBranch }}</div>
} @else {
<div class="min-w-[7.5rem]">Versanddatum</div>
<div class="font-bold">{{ item?.estimatedShippingDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
}
</div>
}
<hr
*ngIf="!primaryOutletActive"
class="page-customer-order-item__separator border-[#EDEFF0] border-solid border-[1px] -mx-[0.875rem]"
/>
@if (!primaryOutletActive) {
<hr
class="page-customer-order-item__separator border-[#EDEFF0] border-solid border-[1px] -mx-[0.875rem]"
/>
}
<div
class="page-customer-order-item__item-order-number desktop-small:text-xl justify-self-end font-bold"
[class.page-customer-order-item__item-order-number-main]="!primaryOutletActive"
>
<ng-container *ngIf="item?.compartmentCode; else orderNumber">
>
@if (item?.compartmentCode) {
{{ item?.compartmentCode }}{{ item?.compartmentInfo && '_' + item?.compartmentInfo }}
</ng-container>
<ng-template #orderNumber>{{ item?.orderNumber }}</ng-template>
} @else {
{{ item?.orderNumber }}
}
</div>
<div
class="page-customer-order-item__item-processing-paid-status flex flex-col font-bold desktop-small:text-p2 justify-self-end self-center"
>
>
<div class="page-customer-order-item__item-processing-status flex flex-row mb-[0.375rem]">
<shared-icon
class="flex items-center justify-center mr-1"
[size]="16"
*ngIf="item.processingStatus | processingStatus: 'icon'; let icon"
[icon]="icon"
></shared-icon>
@if (item.processingStatus | processingStatus: 'icon'; as icon) {
<shared-icon
class="flex items-center justify-center mr-1"
[size]="16"
[icon]="icon"
></shared-icon>
}
{{ item.processingStatus | processingStatus }}
</div>
<div class="page-customer-order-item__item-paid flex flex-row self-end">
<div class="font-bold w-fit desktop-small:text-p2 px-3 py-[0.125rem] rounded text-white bg-[#26830C]" *ngIf="item.features?.paid">
{{ item.features?.paid }}
</div>
@if (item.features?.paid) {
<div class="font-bold w-fit desktop-small:text-p2 px-3 py-[0.125rem] rounded text-white bg-[#26830C]">
{{ item.features?.paid }}
</div>
}
</div>
</div>
</div>

View File

@@ -2,102 +2,111 @@
class="page-customer-order-search-results__header bg-background-liste flex items-end justify-between"
[class.pb-4]="!(primaryOutletActive$ | async)"
[class.flex-col]="!(primaryOutletActive$ | async)"
>
>
<div class="flex flex-row w-full desktop-small:w-min" [class.desktop-large:w-full]="!(primaryOutletActive$ | async)">
<shared-filter-input-group-main
*ngIf="filter$ | async; let filter"
class="block mr-3 w-full desktop-small:w-[23.5rem]"
[class.desktop-large:w-full]="!(primaryOutletActive$ | async)"
[hint]="message$ | async"
[loading]="loading$ | async"
[inputGroup]="filter?.input | group: 'main'"
(search)="search({ filter, clear: true })"
[showDescription]="false"
[scanner]="true"
></shared-filter-input-group-main>
@if (filter$ | async; as filter) {
<shared-filter-input-group-main
class="block mr-3 w-full desktop-small:w-[23.5rem]"
[class.desktop-large:w-full]="!(primaryOutletActive$ | async)"
[hint]="message$ | async"
[loading]="loading$ | async"
[inputGroup]="filter?.input | group: 'main'"
(search)="search({ filter, clear: true })"
[showDescription]="false"
[scanner]="true"
></shared-filter-input-group-main>
}
<a
class="page-customer-orders-results__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
[routerLink]="filterRoute"
queryParamsHandling="preserve"
>
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
</a>
</div>
<div
*ngIf="hits$ | async; let hits"
class="page-customer-order-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
[class.mb-4]="primaryOutletActive$ | async"
>
{{ hits ?? 0 }}
Titel
</div>
@if (hits$ | async; as hits) {
<div
class="page-customer-order-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
[class.mb-4]="primaryOutletActive$ | async"
>
{{ hits ?? 0 }}
Titel
</div>
}
</div>
<ui-scroll-container
*ngIf="!(listEmpty$ | async); else emptyMessage"
class="page-customer-order-results__scroll-container m-0 p-0"
[showScrollbar]="false"
[showScrollArrow]="false"
(reachEnd)="loadMore()"
[deltaEnd]="150"
[itemLength]="itemLength$ | async"
[containerHeight]="25"
[showSpacer]="(primaryOutletActive$ | async) || (isTablet$ | async)"
>
<ng-container *ngIf="processId$ | async; let processId">
<div class="page-customer-order-results__items-list w-full" *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
<div
class="page-customer-order-search__item-header-group w-full grid grid-flow-col gap-x-4 items-center justify-between bg-white text-xl rounded-t px-4 py-[0.875rem] font-bold mb-px-2"
>
<h3 class="m-0 break-words" [class.w-72]="!(primaryOutletActive$ | async)">
{{ firstItem?.organisation }}
<ng-container *ngIf="!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)">-</ng-container>
{{ firstItem?.lastName }}
{{ firstItem?.firstName }}
</h3>
<h3 class="m-0 break-words text-right" [class.w-40]="!(primaryOutletActive$ | async)">{{ firstItem?.buyerNumber }}</h3>
@if (!(listEmpty$ | async)) {
<ui-scroll-container
class="page-customer-order-results__scroll-container m-0 p-0"
[showScrollbar]="false"
[showScrollArrow]="false"
(reachEnd)="loadMore()"
[deltaEnd]="150"
[itemLength]="itemLength$ | async"
[containerHeight]="25"
[showSpacer]="(primaryOutletActive$ | async) || (isTablet$ | async)"
>
@if (processId$ | async; as processId) {
@for (bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn; track bueryNumberGroup) {
<div class="page-customer-order-results__items-list w-full">
@if (bueryNumberGroup.items[0]; as firstItem) {
<div
class="page-customer-order-search__item-header-group w-full grid grid-flow-col gap-x-4 items-center justify-between bg-white text-xl rounded-t px-4 py-[0.875rem] font-bold mb-px-2"
>
<h3 class="m-0 break-words" [class.w-72]="!(primaryOutletActive$ | async)">
{{ firstItem?.organisation }}
@if (!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)) {
-
}
{{ firstItem?.lastName }}
{{ firstItem?.firstName }}
</h3>
<h3 class="m-0 break-words text-right" [class.w-40]="!(primaryOutletActive$ | async)">{{ firstItem?.buyerNumber }}</h3>
</div>
}
@for (orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; track orderNumberGroup) {
@for (processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; track processingStatusGroup) {
@for (compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; track compartmentCodeGroup) {
@for (item of compartmentCodeGroup.items; track trackByFn($index, item); let firstItem = $first) {
<page-customer-order-item
class="page-customer-orders-results__result-item mb-[0.625rem]"
[class.page-customer-orders-results__result-item-main]="primaryOutletActive$ | async"
[item]="item"
[primaryOutletActive]="primaryOutletActive$ | async"
></page-customer-order-item>
}
}
}
}
</div>
</ng-container>
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn">
<ng-container *ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn">
<ng-container *ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn">
<page-customer-order-item
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
class="page-customer-orders-results__result-item mb-[0.625rem]"
[class.page-customer-orders-results__result-item-main]="primaryOutletActive$ | async"
[item]="item"
[primaryOutletActive]="primaryOutletActive$ | async"
></page-customer-order-item>
</ng-container>
</ng-container>
</ng-container>
</div>
</ng-container>
</ui-scroll-container>
<ng-template #emptyMessage>
}
}
</ui-scroll-container>
} @else {
<div class="empty-message">
Es sind im Moment keine Bestellposten vorhanden,
<br />
die bearbeitet werden können.
</div>
</ng-template>
}
<div class="actions z-fixed" *ngIf="actions$ | async; let actions">
<button
[disabled]="(loadingFetchedActionButton$ | async) || (loading$ | async)"
class="cta-action"
*ngFor="let action of actions"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction(action)"
>
<ui-spinner [show]="(loadingFetchedActionButton$ | async) || (loading$ | async)">{{ action.label }}</ui-spinner>
</button>
</div>
@if (actions$ | async; as actions) {
<div class="actions z-fixed">
@for (action of actions; track action) {
<button
[disabled]="(loadingFetchedActionButton$ | async) || (loading$ | async)"
class="cta-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction(action)"
>
<ui-spinner [show]="(loadingFetchedActionButton$ | async) || (loading$ | async)">{{ action.label }}</ui-spinner>
</button>
}
</div>
}

View File

@@ -4,7 +4,7 @@
[cdkMenuTriggerFor]="navMenu"
#menuTrigger="cdkMenuTriggerFor"
[class.open]="menuTrigger.isOpen()"
>
>
<shared-icon icon="apps" [size]="24"></shared-icon>
<shared-icon [icon]="menuTrigger.isOpen() ? 'arrow-drop-up' : 'arrow-drop-down'" [size]="24"></shared-icon>
</button>
@@ -12,42 +12,46 @@
<ng-template #navMenu>
<div class="pt-1">
<shared-menu>
<a
sharedMenuItem
*ngIf="customerDetailsRoute$ | async; let customerDetailsRoute"
[routerLink]="customerDetailsRoute.path"
[queryParams]="customerDetailsRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Kundendetails
</a>
<a
sharedMenuItem
*ngIf="ordersRoute$ | async; let ordersRoute"
[routerLink]="ordersRoute.path"
[queryParams]="ordersRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Bestellungen
</a>
<a
sharedMenuItem
*ngIf="kundenkarteRoute$ | async; let kundenkarteRoute"
[routerLink]="kundenkarteRoute.path"
[queryParams]="kundenkarteRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Kundenkarte
</a>
<a
sharedMenuItem
*ngIf="historyRoute$ | async; let historyRoute"
[routerLink]="historyRoute.path"
[queryParams]="historyRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Historie
</a>
@if (customerDetailsRoute$ | async; as customerDetailsRoute) {
<a
sharedMenuItem
[routerLink]="customerDetailsRoute.path"
[queryParams]="customerDetailsRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Kundendetails
</a>
}
@if (ordersRoute$ | async; as ordersRoute) {
<a
sharedMenuItem
[routerLink]="ordersRoute.path"
[queryParams]="ordersRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Bestellungen
</a>
}
@if (kundenkarteRoute$ | async; as kundenkarteRoute) {
<a
sharedMenuItem
[routerLink]="kundenkarteRoute.path"
[queryParams]="kundenkarteRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Kundenkarte
</a>
}
@if (historyRoute$ | async; as historyRoute) {
<a
sharedMenuItem
[routerLink]="historyRoute.path"
[queryParams]="historyRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Historie
</a>
}
</shared-menu>
</div>
</ng-template>

View File

@@ -8,7 +8,7 @@ import { map } from 'rxjs/operators';
import { CustomerSearchNavigation } from '@shared/services/navigation';
import { ComponentStore } from '@ngrx/component-store';
import { RouterLink } from '@angular/router';
import { AsyncPipe, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
export interface CustomerMenuComponentState {
customerId?: number;
@@ -26,7 +26,7 @@ export interface CustomerMenuComponentState {
styleUrls: ['customer-menu.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-customer-menu' },
imports: [CdkMenuModule, SharedMenuModule, IconComponent, RouterLink, NgIf, AsyncPipe],
imports: [CdkMenuModule, SharedMenuModule, IconComponent, RouterLink, AsyncPipe],
})
export class CustomerMenuComponent extends ComponentStore<CustomerMenuComponentState> {
private _navigation = inject(CustomerSearchNavigation);

View File

@@ -1,59 +1,66 @@
<cdk-virtual-scroll-viewport
itemSize="100"
class="h-[calc(100vh-20.125rem)] desktop-small:h-[calc(100vh-18.625rem)]"
*ngIf="!compact"
(scrolledIndexChange)="scrolledIndexChange($event)"
>
<a
*cdkVirtualFor="let customer of customers; trackBy: trackByFn; let index = index"
[routerLink]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.path"
[queryParams]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.queryParams"
[queryParamsHandling]="'merge'"
(click)="scrolledIndexChange(index)"
routerLinkActive
#rla="routerLinkActive"
>
<page-customer-result-list-item-full [class.active]="rla.isActive" [customer]="customer"></page-customer-result-list-item-full>
</a>
<div class="h-[6.125rem] bg-white rounded px-4 py-3" *ngIf="hits === customers?.length && !fetching">
<ng-container *ngTemplateOutlet="customerNotFound"></ng-container>
</div>
</cdk-virtual-scroll-viewport>
@if (!compact) {
<cdk-virtual-scroll-viewport
itemSize="100"
class="h-[calc(100vh-20.125rem)] desktop-small:h-[calc(100vh-18.625rem)]"
(scrolledIndexChange)="scrolledIndexChange($event)"
>
<a
*cdkVirtualFor="let customer of customers; trackBy: trackByFn; let index = index"
[routerLink]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.path"
[queryParams]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.queryParams"
[queryParamsHandling]="'merge'"
(click)="scrolledIndexChange(index)"
routerLinkActive
#rla="routerLinkActive"
>
<page-customer-result-list-item-full [class.active]="rla.isActive" [customer]="customer"></page-customer-result-list-item-full>
</a>
@if (hits === customers?.length && !fetching) {
<div class="h-[6.125rem] bg-white rounded px-4 py-3">
<ng-container *ngTemplateOutlet="customerNotFound"></ng-container>
</div>
}
</cdk-virtual-scroll-viewport>
}
<cdk-virtual-scroll-viewport
itemSize="191"
class="h-[calc(100vh-20.75rem)]"
*ngIf="compact"
(scrolledIndexChange)="scrolledIndexChange($event)"
>
<a
*cdkVirtualFor="let customer of customers; trackBy: trackByFn; let index = index"
[routerLink]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.path"
[queryParams]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.queryParams"
[queryParamsHandling]="'merge'"
(click)="scrolledIndexChange(index)"
routerLinkActive
#rla="routerLinkActive"
>
<page-customer-result-list-item [class.active]="rla.isActive" [customer]="customer"></page-customer-result-list-item>
</a>
<div class="h-[11.3125rem] bg-white rounded px-4 py-3" *ngIf="hits === customers?.length && !fetching">
<ng-container *ngTemplateOutlet="customerNotFound"></ng-container>
</div>
</cdk-virtual-scroll-viewport>
@if (compact) {
<cdk-virtual-scroll-viewport
itemSize="191"
class="h-[calc(100vh-20.75rem)]"
(scrolledIndexChange)="scrolledIndexChange($event)"
>
<a
*cdkVirtualFor="let customer of customers; trackBy: trackByFn; let index = index"
[routerLink]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.path"
[queryParams]="customerSearchNavigation.detailsRoute({ processId: processId, customerId: customer.id })?.queryParams"
[queryParamsHandling]="'merge'"
(click)="scrolledIndexChange(index)"
routerLinkActive
#rla="routerLinkActive"
>
<page-customer-result-list-item [class.active]="rla.isActive" [customer]="customer"></page-customer-result-list-item>
</a>
@if (hits === customers?.length && !fetching) {
<div class="h-[11.3125rem] bg-white rounded px-4 py-3">
<ng-container *ngTemplateOutlet="customerNotFound"></ng-container>
</div>
}
</cdk-virtual-scroll-viewport>
}
<ng-template #customerNotFound>
<div class="text-sm">
Hinweis: Aus Datenschutzgründen werden nur Teilinformationen dargestellt. Tab auf einen Kunden um mehr zu erfahren.
</div>
<div class="font-bold text-lg mt-3">
<span>Kunden nicht gefunden?</span>
<a
*ngIf="customerCreateNavigation.defaultRoute({ processId: processId }); let route"
[routerLink]="route.path"
[queryParams]="route.queryParams"
class="text-brand"
>
Neue Kundendaten erfassen
</a>
@if (customerCreateNavigation.defaultRoute({ processId: processId }); as route) {
<a
[routerLink]="route.path"
[queryParams]="route.queryParams"
class="text-brand"
>
Neue Kundendaten erfassen
</a>
}
</div>
</ng-template>

View File

@@ -1,21 +1,23 @@
<ng-container *ifRole="'Store'">
<shared-checkbox
*ngIf="customerType !== 'b2b'"
[ngModel]="p4mUser"
(ngModelChange)="setValue({ p4mUser: !p4mUser })"
[disabled]="p4mReadonly || readonly"
>
Kundenkarte
</shared-checkbox>
</ng-container>
<ng-container *ngFor="let option of filteredOptions$ | async">
<shared-checkbox
*ngIf="option?.enabled !== false"
[ngModel]="option.value === customerType"
(ngModelChange)="setValue({ customerType: $event ? option.value : undefined })"
[disabled]="isOptionDisabled(option)"
[name]="option.value"
>
{{ option.label }}
</shared-checkbox>
@if (customerType !== 'b2b') {
<shared-checkbox
[ngModel]="p4mUser"
(ngModelChange)="setValue({ p4mUser: !p4mUser })"
[disabled]="p4mReadonly || readonly"
>
Kundenkarte
</shared-checkbox>
}
</ng-container>
@for (option of filteredOptions$ | async; track option) {
@if (option?.enabled !== false) {
<shared-checkbox
[ngModel]="option.value === customerType"
(ngModelChange)="setValue({ customerType: $event ? option.value : undefined })"
[disabled]="isOptionDisabled(option)"
[name]="option.value"
>
{{ option.label }}
</shared-checkbox>
}
}

View File

@@ -6,57 +6,59 @@
type="text"
formControlName="street"
[tabindex]="tabIndexStart"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="Hausnummer">
<input
placeholder="Hausnummer"
class="input-control"
type="text"
formControlName="streetNumber"
[tabindex]="tabIndexStart + 1"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="PLZ">
<input
placeholder="PLZ"
class="input-control"
type="text"
formControlName="zipCode"
[tabindex]="tabIndexStart + 2"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="Ort">
<input
placeholder="Ort"
class="input-control"
type="text"
formControlName="city"
[tabindex]="tabIndexStart + 3"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control class="col-span-2" label="Adresszusatz">
<input
placeholder="Adresszusatz"
class="input-control"
type="text"
formControlName="info"
[tabindex]="tabIndexStart + 4"
[readonly]="readonly"
/>
</shared-form-control>
/>
</shared-form-control>
<shared-form-control label="Hausnummer">
<input
placeholder="Hausnummer"
class="input-control"
type="text"
formControlName="streetNumber"
[tabindex]="tabIndexStart + 1"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="PLZ">
<input
placeholder="PLZ"
class="input-control"
type="text"
formControlName="zipCode"
[tabindex]="tabIndexStart + 2"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="Ort">
<input
placeholder="Ort"
class="input-control"
type="text"
formControlName="city"
[tabindex]="tabIndexStart + 3"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" [tabindex]="tabIndexStart + 5" [readonly]="readonly">
<shared-select-option *ngFor="let country of countries || (countries$ | async)" [value]="country.isO3166_A_3">
{{ country.name }}
</shared-select-option>
</shared-select>
</shared-form-control>
</ng-container>
<shared-form-control class="col-span-2" label="Adresszusatz">
<input
placeholder="Adresszusatz"
class="input-control"
type="text"
formControlName="info"
[tabindex]="tabIndexStart + 4"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" [tabindex]="tabIndexStart + 5" [readonly]="readonly">
@for (country of countries || (countries$ | async); track country) {
<shared-select-option [value]="country.isO3166_A_3">
{{ country.name }}
</shared-select-option>
}
</shared-select>
</shared-form-control>
</ng-container>

View File

@@ -4,59 +4,64 @@
[tabindex]="tabIndexStart"
[autofocus]="focusAfterInit"
[readonly]="readonly"
>
>
<ng-content></ng-content>
</shared-checkbox>
<div class="address-block" *ngIf="control.value.deviatingAddress">
<div class="wrapper">
<app-organisation-form-block
*ngIf="organisation"
[tabIndexStart]="tabIndexStart + 1"
#orgaBlock
(onInit)="addOrganisationGroup($event)"
(onDestroy)="removeOrganisationGroup()"
[data]="data?.organisation"
#nameFormBlock
[tabIndexStart]="tabIndexStart + 1"
[requiredMarks]="organisationRequiredMarks"
[validatorFns]="organisationValidatorFns"
[readonly]="readonly"
></app-organisation-form-block>
<app-name-form-block
(onInit)="addNameGroup($event)"
(onDestroy)="removeNameGroup()"
[data]="data?.name"
#nameFormBlock
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidatorFns"
[readonly]="readonly"
></app-name-form-block>
<app-address-form-block
#addressFormBlock
(onInit)="addAddressGroup($event)"
(onDestroy)="removeAddressGroup()"
[data]="data?.address"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidatorFns"
[readonly]="readonly"
></app-address-form-block>
<app-email-form-block
*ngIf="email"
#emailFormBlock
(onInit)="addEmailGroup($event)"
(onDestroy)="removeEmailGroup()"
[data]="data?.email"
[requiredMark]="emailRequiredMark"
[validatorFns]="emailValidationFns"
[readonly]="readonly"
></app-email-form-block>
<app-phone-numbers-form-block
*ngIf="phoneNumbers"
(onInit)="addPhoneNumbersGroup($event)"
(onDestroy)="removePhoneNumbersGroup()"
[readonly]="readonly"
>
[tabIndexStart]="emailFormBlock?.tabIndexEnd+1" [requiredMarks]="phoneNumbersRequiredMarks" [validatorFns]="phoneNumbersValidatorFns">
</app-phone-numbers-form-block>
@if (control.value.deviatingAddress) {
<div class="address-block">
<div class="wrapper">
@if (organisation) {
<app-organisation-form-block
[tabIndexStart]="tabIndexStart + 1"
#orgaBlock
(onInit)="addOrganisationGroup($event)"
(onDestroy)="removeOrganisationGroup()"
[data]="data?.organisation"
#nameFormBlock
[tabIndexStart]="tabIndexStart + 1"
[requiredMarks]="organisationRequiredMarks"
[validatorFns]="organisationValidatorFns"
[readonly]="readonly"
></app-organisation-form-block>
}
<app-name-form-block
(onInit)="addNameGroup($event)"
(onDestroy)="removeNameGroup()"
[data]="data?.name"
#nameFormBlock
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidatorFns"
[readonly]="readonly"
></app-name-form-block>
<app-address-form-block
#addressFormBlock
(onInit)="addAddressGroup($event)"
(onDestroy)="removeAddressGroup()"
[data]="data?.address"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidatorFns"
[readonly]="readonly"
></app-address-form-block>
@if (email) {
<app-email-form-block
#emailFormBlock
(onInit)="addEmailGroup($event)"
(onDestroy)="removeEmailGroup()"
[data]="data?.email"
[requiredMark]="emailRequiredMark"
[validatorFns]="emailValidationFns"
[readonly]="readonly"
></app-email-form-block>
}
@if (phoneNumbers) {
<app-phone-numbers-form-block
(onInit)="addPhoneNumbersGroup($event)"
(onDestroy)="removePhoneNumbersGroup()"
[readonly]="readonly"
>
[tabIndexStart]="emailFormBlock?.tabIndexEnd+1" [requiredMarks]="phoneNumbersRequiredMarks" [validatorFns]="phoneNumbersValidatorFns">
</app-phone-numbers-form-block>
}
</div>
</div>
</div>
}

View File

@@ -1,12 +1,13 @@
<div class="interests-description">Geben Sie Interessen an, um Ihre persönlichen Kontoangaben zu verfeinern.</div>
<div class="interests-wrapper" [formGroup]="control">
<shared-checkbox
*ngFor="let pair of interests | keyvalue; let idx = index"
[formControlName]="pair.key"
[tabindex]="tabIndexStart + idx"
[autofocus]="focusAfterInit"
[readonly]="readonly"
>
{{ pair.value }}
</shared-checkbox>
@for (pair of interests | keyvalue; track pair; let idx = $index) {
<shared-checkbox
[formControlName]="pair.key"
[tabindex]="tabIndexStart + idx"
[autofocus]="focusAfterInit"
[readonly]="readonly"
>
{{ pair.value }}
</shared-checkbox>
}
</div>

View File

@@ -6,8 +6,10 @@
[readonly]="readonly"
[tabindex]="tabIndexStart"
[autofocus]="focusAfterInit"
>
<shared-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
>
@for (gender of genderSettings.genders; track gender) {
<shared-select-option [value]="gender.value">{{ gender.label }}</shared-select-option>
}
</shared-select>
</shared-form-control>
@@ -30,7 +32,7 @@
formControlName="lastName"
[tabindex]="tabIndexStart + 2"
[readonly]="readonly"
/>
/>
</shared-form-control>
<shared-form-control label="Vorname">
@@ -41,6 +43,6 @@
formControlName="firstName"
[tabindex]="tabIndexStart + 3"
[readonly]="readonly"
/>
/>
</shared-form-control>
</ng-container>

View File

@@ -6,30 +6,30 @@
type="text"
formControlName="name"
[tabindex]="tabIndexStart"
[readonly]="readonly"
/>
</shared-form-control>
<ng-container *ngIf="appearence === 'default'">
<shared-form-control label="Abteilung">
<input
placeholder="Abteilung"
class="input-control"
type="text"
formControlName="department"
[tabindex]="tabIndexStart + 1"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="USt-ID">
<input
placeholder="USt-ID"
class="input-control"
type="text"
formControlName="vatId"
[tabindex]="tabIndexStart + 2"
[readonly]="readonly"
/>
</shared-form-control>
</ng-container>
</ng-container>
@if (appearence === 'default') {
<shared-form-control label="Abteilung">
<input
placeholder="Abteilung"
class="input-control"
type="text"
formControlName="department"
[tabindex]="tabIndexStart + 1"
[readonly]="readonly"
/>
</shared-form-control>
<shared-form-control label="USt-ID">
<input
placeholder="USt-ID"
class="input-control"
type="text"
formControlName="vatId"
[tabindex]="tabIndexStart + 2"
[readonly]="readonly"
/>
</shared-form-control>
}
</ng-container>

View File

@@ -6,9 +6,11 @@
[formControl]="control"
[tabindex]="tabIndexStart"
[readonly]="readonly"
/>
</shared-form-control>
<button type="button" *ngIf="!readonly && canScan()" (click)="scan()">
<shared-icon icon="barcode-scan" [size]="32"></shared-icon>
</button>
/>
</shared-form-control>
@if (!readonly && canScan()) {
<button type="button" (click)="scan()">
<shared-icon icon="barcode-scan" [size]="32"></shared-icon>
</button>
}

View File

@@ -1,38 +1,62 @@
<div class="wrapper text-center" [@cardFlip]="state" (@cardFlip.done)="flipAnimationDone($event)">
<div *ngIf="cardDetails" class="card-main">
<div class="icons text-brand">
<button *ngIf="isCustomerCard && frontside" class="icon-barcode" (click)="flipCard()">
<shared-icon [size]="35" icon="barcode-scanner"></shared-icon>
</button>
<button *ngIf="isCustomerCard && !frontside" class="icon-back" (click)="flipCard()">
<shared-icon [size]="35" icon="refresh"></shared-icon>
</button>
<!-- <div *ngIf="!isCustomerCard" class="icon-delete"><ui-icon (click)="onDeletePartnerCard()" size="25px" icon="trash"></ui-icon></div> -->
</div>
<div class="headline">
<p *ngIf="isCustomerCard && frontside">Ihre Lesepunkte</p>
<p *ngIf="isCustomerCard && !frontside">Kartennummer</p>
<p *ngIf="!isCustomerCard">Partnerkartennummer</p>
</div>
<div class="mt-2">
<div *ngIf="!isCustomerCard || (isCustomerCard && !frontside)" class="card-number">{{ cardDetails.code }}</div>
<div *ngIf="isCustomerCard && frontside" class="points">{{ cardDetails.totalPoints | number }}</div>
</div>
<div class="barcode-button">
<div *ngIf="!isCustomerCard || (isCustomerCard && !frontside)" class="barcode-field">
<img class="barcode" src="/assets/images/barcode.png" alt="Barcode" />
@if (cardDetails) {
<div class="card-main">
<div class="icons text-brand">
@if (isCustomerCard && frontside) {
<button class="icon-barcode" (click)="flipCard()">
<shared-icon [size]="35" icon="barcode-scanner"></shared-icon>
</button>
}
@if (isCustomerCard && !frontside) {
<button class="icon-back" (click)="flipCard()">
<shared-icon [size]="35" icon="refresh"></shared-icon>
</button>
}
<!-- <div *ngIf="!isCustomerCard" class="icon-delete"><ui-icon (click)="onDeletePartnerCard()" size="25px" icon="trash"></ui-icon></div> -->
</div>
<div *ngIf="isCustomerCard && frontside">
<button class="button" (click)="onRewardShop()">Zum Prämienshop</button>
<div class="headline">
@if (isCustomerCard && frontside) {
<p>Ihre Lesepunkte</p>
}
@if (isCustomerCard && !frontside) {
<p>Kartennummer</p>
}
@if (!isCustomerCard) {
<p>Partnerkartennummer</p>
}
</div>
<div class="mt-2">
@if (!isCustomerCard || (isCustomerCard && !frontside)) {
<div class="card-number">{{ cardDetails.code }}</div>
}
@if (isCustomerCard && frontside) {
<div class="points">{{ cardDetails.totalPoints | number }}</div>
}
</div>
<div class="barcode-button">
@if (!isCustomerCard || (isCustomerCard && !frontside)) {
<div class="barcode-field">
<img class="barcode" src="/assets/images/barcode.png" alt="Barcode" />
</div>
}
@if (isCustomerCard && frontside) {
<div>
<button class="button" (click)="onRewardShop()">Zum Prämienshop</button>
</div>
}
</div>
</div>
</div>
}
<div class="card-bottom">
<div *ngIf="!isCustomerCard || (isCustomerCard && !frontside)" class="customer-name">
<p>{{ cardDetails.firstName }} {{ cardDetails.lastName }}</p>
</div>
<div *ngIf="isCustomerCard && frontside" class="logo ml-2">
<img class="logo-picture" src="/assets/images/Hugendubel_Logo.png" alt="Hugendubel Logo" />
</div>
@if (!isCustomerCard || (isCustomerCard && !frontside)) {
<div class="customer-name">
<p>{{ cardDetails.firstName }} {{ cardDetails.lastName }}</p>
</div>
}
@if (isCustomerCard && frontside) {
<div class="logo ml-2">
<img class="logo-picture" src="/assets/images/Hugendubel_Logo.png" alt="Hugendubel Logo" />
</div>
}
</div>
</div>

View File

@@ -1,5 +1,5 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { DecimalPipe, NgIf } from '@angular/common';
import { DecimalPipe } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core';
import { IconComponent } from '@shared/components/icon';
import { BonusCardInfoDTO } from '@generated/swagger/crm-api';
@@ -8,7 +8,7 @@ import { BonusCardInfoDTO } from '@generated/swagger/crm-api';
selector: 'page-customer-kundenkarte',
templateUrl: 'kundenkarte.component.html',
styleUrls: ['kundenkarte.component.scss'],
imports: [IconComponent, NgIf, DecimalPipe],
imports: [IconComponent, DecimalPipe],
animations: [
trigger('cardFlip', [
state(

View File

@@ -1,89 +1,83 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">
Um Ihnen den ausgewählten Service zu
<br />
ermöglichen, legen wir Ihnen gerne
<br />
ein Kundenkonto an.
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="b2b"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-organisation-form-block
#orga
[tabIndexStart]="1"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
(onInit)="addFormBlock('organisation', $event)"
[requiredMarks]="organisationFormBlockRequiredMarks"
[validatorFns]="organisationFormBlockValidators"
></app-organisation-form-block>
<app-name-form-block
#name
[tabIndexStart]="orga.tabIndexEnd + 1"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
(onInit)="addFormBlock('name', $event)"
></app-name-form-block>
<app-address-form-block
#address
[tabIndexStart]="name.tabIndexEnd + 1"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
(onInit)="addFormBlock('address', $event)"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
[defaults]="{ country: 'DEU' }"
></app-address-form-block>
<app-email-form-block
#email
[tabIndexStart]="address.tabIndexEnd + 1"
[data]="data.email"
(dataChanges)="patchFormData('email', $event)"
[validatorFns]="emailFormBlockValidators"
(onInit)="addFormBlock('email', $event)"
></app-email-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="email.tabIndexEnd + 1"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
(onInit)="addFormBlock('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-deviating-address-form-block
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="deviatingNameRequiredMarks"
[nameValidatorFns]="deviatingNameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidators"
[organisationRequiredMarks]="organisationFormBlockRequiredMarks"
[organisationValidatorFns]="organisationFormBlockValidators"
[defaults]="{ address: { country: 'DEU' } }"
[organisation]="true"
[email]="true"
[phoneNumbers]="true"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
@if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">
Um Ihnen den ausgewählten Service zu
<br />
ermöglichen, legen wir Ihnen gerne
<br />
ein Kundenkonto an.
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="b2b"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-organisation-form-block
#orga
[tabIndexStart]="1"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
(onInit)="addFormBlock('organisation', $event)"
[requiredMarks]="organisationFormBlockRequiredMarks"
[validatorFns]="organisationFormBlockValidators"
></app-organisation-form-block>
<app-name-form-block
#name
[tabIndexStart]="orga.tabIndexEnd + 1"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
(onInit)="addFormBlock('name', $event)"
></app-name-form-block>
<app-address-form-block
#address
[tabIndexStart]="name.tabIndexEnd + 1"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
(onInit)="addFormBlock('address', $event)"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
[defaults]="{ country: 'DEU' }"
></app-address-form-block>
<app-email-form-block
#email
[tabIndexStart]="address.tabIndexEnd + 1"
[data]="data.email"
(dataChanges)="patchFormData('email', $event)"
[validatorFns]="emailFormBlockValidators"
(onInit)="addFormBlock('email', $event)"
></app-email-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="email.tabIndexEnd + 1"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
(onInit)="addFormBlock('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-deviating-address-form-block
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="deviatingNameRequiredMarks"
[nameValidatorFns]="deviatingNameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidators"
[organisationRequiredMarks]="organisationFormBlockRequiredMarks"
[organisationValidatorFns]="organisationFormBlockValidators"
[defaults]="{ address: { country: 'DEU' } }"
[organisation]="true"
[email]="true"
[phoneNumbers]="true"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
}

View File

@@ -1,4 +1,4 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { CustomerCreateSideViewModule } from './customer-create-side-view';
@@ -10,7 +10,7 @@ import { SharedSplitscreenComponent } from '@shared/components/splitscreen';
templateUrl: 'create-customer.component.html',
styleUrls: ['create-customer.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, RouterModule, SharedSplitscreenComponent, CustomerCreateSideViewModule],
imports: [RouterModule, SharedSplitscreenComponent, CustomerCreateSideViewModule],
})
export class CreateCustomerComponent {
processId$ = this._activatedRoute.parent.data.pipe(map((data) => data.processId));

View File

@@ -1,102 +1,94 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">
Um Ihnen den ausgewählten Service
<br />
zu ermöglichen, legen wir Ihnen
<br />
gerne ein Kundenkonto an.
<br />
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="guest"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-name-form-block
#name
[tabIndexStart]="1"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
(onInit)="addFormBlock('name', $event)"
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidationFns"
></app-name-form-block>
<p class="info">
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
die Übermittlungskosten nach den Basistarifen entstehen.
</p>
<app-email-form-block
#email
[tabIndexStart]="name.tabIndexEnd + 1"
[data]="data.email"
[requiredMark]="true"
(dataChanges)="patchFormData('email', $event)"
[validatorFns]="emailFormBlockValidators"
(onInit)="addFormBlock('email', $event)"
></app-email-form-block>
<app-organisation-form-block
#orga
[tabIndexStart]="email.tabIndexStart + 1"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
(onInit)="addFormBlock('organisation', $event)"
appearence="compact"
></app-organisation-form-block>
<app-address-form-block
#address
[tabIndexStart]="orga.tabIndexEnd + 1"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
(onInit)="addFormBlock('address', $event)"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
[defaults]="{ country: 'DEU' }"
></app-address-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="address.tabIndexEnd + 1"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
(onInit)="addFormBlock('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#birthDate
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-deviating-address-form-block
[tabIndexStart]="birthDate.tabIndexEnd + 1"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="deviatingNameRequiredMarks"
[nameValidatorFns]="deviatingNameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidators"
[defaults]="{ address: { country: 'DEU' } }"
[organisation]="true"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
@if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">
Um Ihnen den ausgewählten Service
<br />
zu ermöglichen, legen wir Ihnen
<br />
gerne ein Kundenkonto an.
<br />
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="guest"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-name-form-block
#name
[tabIndexStart]="1"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
(onInit)="addFormBlock('name', $event)"
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidationFns"
></app-name-form-block>
<p class="info">
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
die Übermittlungskosten nach den Basistarifen entstehen.
</p>
<app-email-form-block
#email
[tabIndexStart]="name.tabIndexEnd + 1"
[data]="data.email"
[requiredMark]="true"
(dataChanges)="patchFormData('email', $event)"
[validatorFns]="emailFormBlockValidators"
(onInit)="addFormBlock('email', $event)"
></app-email-form-block>
<app-organisation-form-block
#orga
[tabIndexStart]="email.tabIndexStart + 1"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
(onInit)="addFormBlock('organisation', $event)"
appearence="compact"
></app-organisation-form-block>
<app-address-form-block
#address
[tabIndexStart]="orga.tabIndexEnd + 1"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
(onInit)="addFormBlock('address', $event)"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
[defaults]="{ country: 'DEU' }"
></app-address-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="address.tabIndexEnd + 1"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
(onInit)="addFormBlock('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#birthDate
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-deviating-address-form-block
[tabIndexStart]="birthDate.tabIndexEnd + 1"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="deviatingNameRequiredMarks"
[nameValidatorFns]="deviatingNameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidators"
[defaults]="{ address: { country: 'DEU' } }"
[organisation]="true"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
}

View File

@@ -1,10 +1,10 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()">
<h1 class="title flex flex-row items-center justify-center">
Kundendaten erfassen
<!-- <span
class="rounded-full ml-4 h-8 w-8 text-xl text-center border-2 border-solid border-brand text-brand">i</span> -->
@if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()">
<h1 class="title flex flex-row items-center justify-center">
Kundendaten erfassen
<!-- <span
class="rounded-full ml-4 h-8 w-8 text-xl text-center border-2 border-solid border-brand text-brand">i</span> -->
</h1>
<p class="description">
Um Sie als Kunde beim nächsten
<br />
@@ -12,7 +12,6 @@
<br />
wir Ihnen gerne eine Kundenkarte an.
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="true"
@@ -20,7 +19,6 @@
(valueChanges)="customerTypeChanged($event)"
[p4mReadonly]="data?._meta?.p4mRequired"
></app-customer-type-selector>
<app-p4m-number-form-block
#p4mBlock
[tabIndexStart]="1"
@@ -31,7 +29,6 @@
[focusAfterInit]="!data?._meta?.p4mRequired"
[asyncValidatorFns]="asyncLoyaltyCardValidatorFn"
></app-p4m-number-form-block>
<app-accept-agb-form-block
[tabIndexStart]="inBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('agb', $event)"
@@ -40,7 +37,6 @@
[requiredMark]="true"
[validatorFns]="agbValidatorFns"
></app-accept-agb-form-block>
<app-newsletter-form-block
class="mb-4"
#newsletterBlock
@@ -50,7 +46,6 @@
(dataChanges)="patchFormData('newsletter', $event)"
[focusAfterInit]="data?._meta?.p4mRequired"
></app-newsletter-form-block>
<app-name-form-block
#nameBlock
[tabIndexStart]="newsletterBlock.tabIndexEnd + 1"
@@ -60,13 +55,13 @@
[validatorFns]="nameValidationFns"
(dataChanges)="patchFormData('name', $event)"
></app-name-form-block>
<p class="info" *ngIf="customerType === 'webshop-p4m'">
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
die Übermittlungskosten nach den Basistarifen entstehen.
</p>
@if (customerType === 'webshop-p4m') {
<p class="info">
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
die Übermittlungskosten nach den Basistarifen entstehen.
</p>
}
<app-email-form-block
class="flex-grow"
#email
@@ -78,7 +73,6 @@
[validatorFns]="emailValidatorFn"
[asyncValidatorFns]="asyncEmailVlaidtorFn"
></app-email-form-block>
<app-organisation-form-block
#orgBlock
[tabIndexStart]="email.tabIndexEnd + 1"
@@ -87,7 +81,6 @@
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
></app-organisation-form-block>
<app-address-form-block
[defaults]="{ country: 'DEU' }"
#addressBlock
@@ -98,7 +91,6 @@
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidatorFns"
></app-address-form-block>
<app-deviating-address-form-block
#ddaBlock
[defaults]="{ address: { country: 'DEU' } }"
@@ -110,10 +102,9 @@
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="shippingAddressRequiredMarks"
[addressValidatorFns]="shippingAddressValidators"
>
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="ddaBlock.tabIndexEnd + 1"
@@ -121,7 +112,6 @@
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#bdBlock
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
@@ -131,7 +121,6 @@
[requiredMark]="true"
[validatorFns]="birthDateValidatorFns"
></app-birth-date-form-block>
<app-interests-form-block
#inBlock
[tabIndexStart]="bdBlock.tabIndexEnd + 1"
@@ -139,12 +128,11 @@
[data]="data.interests"
(dataChanges)="patchFormData('interests', $event)"
></app-interests-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
}

View File

@@ -1,86 +1,78 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">Wir legen Ihnen gerne ein Kundenkonto an</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="store"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-name-form-block
#name
[tabIndexStart]="1"
(onInit)="addFormBlock('name', $event)"
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidationFns"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
></app-name-form-block>
<app-email-form-block
#email
[tabIndexStart]="name.tabIndexEnd + 1"
[validatorFns]="emailFormBlockValidators"
(onInit)="addFormBlock('email', $event)"
[data]="data.email"
(dataChanges)="patchFormData('email', $event)"
></app-email-form-block>
<app-organisation-form-block
#orga
[tabIndexStart]="email.tabIndexEnd + 1"
appearence="compact"
(onInit)="addFormBlock('organisation', $event)"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
></app-organisation-form-block>
<app-address-form-block
#address
[tabIndexStart]="orga.tabIndexEnd + 1"
(onInit)="addFormBlock('address', $event)"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
></app-address-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="address.tabIndexEnd + 1"
(onInit)="addFormBlock('phoneNumbers', $event)"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#birthDate
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-deviating-address-form-block
[tabIndexStart]="birthDate.tabIndexEnd + 1"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[organisation]="true"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="deviatingAddressValidators"
[defaults]="{ address: { country: 'DEU' } }"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
@if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">Wir legen Ihnen gerne ein Kundenkonto an</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="store"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-name-form-block
#name
[tabIndexStart]="1"
(onInit)="addFormBlock('name', $event)"
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidationFns"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
></app-name-form-block>
<app-email-form-block
#email
[tabIndexStart]="name.tabIndexEnd + 1"
[validatorFns]="emailFormBlockValidators"
(onInit)="addFormBlock('email', $event)"
[data]="data.email"
(dataChanges)="patchFormData('email', $event)"
></app-email-form-block>
<app-organisation-form-block
#orga
[tabIndexStart]="email.tabIndexEnd + 1"
appearence="compact"
(onInit)="addFormBlock('organisation', $event)"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
></app-organisation-form-block>
<app-address-form-block
#address
[tabIndexStart]="orga.tabIndexEnd + 1"
(onInit)="addFormBlock('address', $event)"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
></app-address-form-block>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="address.tabIndexEnd + 1"
(onInit)="addFormBlock('phoneNumbers', $event)"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#birthDate
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-deviating-address-form-block
[tabIndexStart]="birthDate.tabIndexEnd + 1"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[organisation]="true"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="deviatingAddressValidators"
[defaults]="{ address: { country: 'DEU' } }"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
}

View File

@@ -1,104 +1,95 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">
Wenn Sie möchten legen wir Ihnen
<br />
gerne ein Onlinekonto an. Dort können
<br />
Sie Ihre Bestellungen einsehen.
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="webshop"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-name-form-block
#name
[tabIndexStart]="1"
(onInit)="addFormBlock('name', $event)"
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidationFns"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
></app-name-form-block>
<p class="info">
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
die Übermittlungskosten nach den Basistarifen entstehen.
</p>
<app-email-form-block
#email
[tabIndexStart]="name.tabIndexEnd + 1"
(onInit)="addFormBlock('email', $event)"
[requiredMark]="true"
[asyncValidatorFns]="asyncEmailValidatorFns"
[validatorFns]="emailValidatorFns"
[data]="data.email"
(dataChanges)="patchFormData('email', $event)"
></app-email-form-block>
<app-organisation-form-block
#org
[tabIndexStart]="email.tabIndexEnd + 1"
appearence="compact"
(onInit)="addFormBlock('organisation', $event)"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
></app-organisation-form-block>
<app-address-form-block
#address
[tabIndexStart]="org.tabIndexEnd + 1"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
(onInit)="addFormBlock('address', $event)"
[defaults]="{ country: 'DEU' }"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
></app-address-form-block>
<p class="info">Das Anlegen geht für Sie noch schneller, wenn wir Ihnen das initiale Passwort per SMS auf Ihr Mobilgerät schicken.</p>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="address.tabIndexEnd + 1"
(onInit)="addFormBlock('phoneNumbers', $event)"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#birthDate
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-deviating-address-form-block
[tabIndexStart]="birthDate.tabIndexEnd + 1"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
appearence="b2b"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidators"
[defaults]="{ address: { country: 'DEU' } }"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
@if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()">
<h1 class="title">Kundendaten erfassen</h1>
<p class="description">
Wenn Sie möchten legen wir Ihnen
<br />
gerne ein Onlinekonto an. Dort können
<br />
Sie Ihre Bestellungen einsehen.
</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="false"
customerType="webshop"
(valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector>
<app-name-form-block
#name
[tabIndexStart]="1"
(onInit)="addFormBlock('name', $event)"
[requiredMarks]="nameRequiredMarks"
[validatorFns]="nameValidationFns"
[data]="data.name"
(dataChanges)="patchFormData('name', $event)"
></app-name-form-block>
<p class="info">
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
die Übermittlungskosten nach den Basistarifen entstehen.
</p>
<app-email-form-block
#email
[tabIndexStart]="name.tabIndexEnd + 1"
(onInit)="addFormBlock('email', $event)"
[requiredMark]="true"
[asyncValidatorFns]="asyncEmailValidatorFns"
[validatorFns]="emailValidatorFns"
[data]="data.email"
(dataChanges)="patchFormData('email', $event)"
></app-email-form-block>
<app-organisation-form-block
#org
[tabIndexStart]="email.tabIndexEnd + 1"
appearence="compact"
(onInit)="addFormBlock('organisation', $event)"
[data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)"
></app-organisation-form-block>
<app-address-form-block
#address
[tabIndexStart]="org.tabIndexEnd + 1"
[requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
(onInit)="addFormBlock('address', $event)"
[defaults]="{ country: 'DEU' }"
[data]="data.address"
(dataChanges)="patchFormData('address', $event)"
></app-address-form-block>
<p class="info">Das Anlegen geht für Sie noch schneller, wenn wir Ihnen das initiale Passwort per SMS auf Ihr Mobilgerät schicken.</p>
<app-phone-numbers-form-block
#phoneNumbers
[tabIndexStart]="address.tabIndexEnd + 1"
(onInit)="addFormBlock('phoneNumbers', $event)"
[data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-birth-date-form-block
#birthDate
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-deviating-address-form-block
[tabIndexStart]="birthDate.tabIndexEnd + 1"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
appearence="b2b"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidators"
[defaults]="{ address: { country: 'DEU' } }"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
>
Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
}

View File

@@ -1,4 +1,4 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { RouterModule } from '@angular/router';
@@ -7,7 +7,7 @@ import { RouterModule } from '@angular/router';
templateUrl: 'customer-create-side-view.component.html',
styleUrls: ['customer-create-side-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, RouterModule],
imports: [RouterModule],
})
export class CustomerCreateSideViewComponent {
constructor() {}

View File

@@ -1,121 +1,109 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()">
<h1 class="title flex flex-row items-center justify-center">Kundenkartendaten erfasen</h1>
<p class="description">Bitte erfassen Sie die Kundenkarte</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="true"
customerType="webshop"
[readonly]="true"
></app-customer-type-selector>
<app-p4m-number-form-block
#p4mBlock
[tabIndexStart]="1"
(onInit)="addFormBlock('p4m', $event)"
[data]="data.p4m"
(dataChanges)="patchFormData('p4m', $event)"
[focusAfterInit]="!data?._meta?.p4mRequired"
[asyncValidatorFns]="asyncLoyaltyCardValidatorFn"
></app-p4m-number-form-block>
<app-accept-agb-form-block
[tabIndexStart]="inBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('agb', $event)"
[data]="data.agb"
(dataChanges)="patchFormData('agb', $event)"
[requiredMark]="true"
[validatorFns]="agbValidatorFns"
></app-accept-agb-form-block>
<app-newsletter-form-block
class="mb-4"
#newsletterBlock
[tabIndexStart]="p4mBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('newsletter', $event)"
[data]="data.newsletter"
(dataChanges)="patchFormData('newsletter', $event)"
[focusAfterInit]="data?._meta?.p4mRequired"
></app-newsletter-form-block>
<app-name-form-block (onInit)="addFormBlock('name', $event)" [data]="data.name" readonly></app-name-form-block>
<app-email-form-block (onInit)="addFormBlock('email', $event)" [data]="data.email" readonly></app-email-form-block>
<app-organisation-form-block
(onInit)="addFormBlock('organisation', $event)"
appearence="compact"
[data]="data.organisation"
readonly
></app-organisation-form-block>
<app-address-form-block [data]="data.address" readonly></app-address-form-block>
<div class="mt-8">
<h4 class="-mb-6">Rechnungsadresse</h4>
<ui-form-control class="-mb-5" [showHint]="false">
<input type="text" [value]="(billingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" />
</ui-form-control>
<app-deviating-address-form-block
#dbaBlock
[defaults]="{ address: { country: 'DEU' } }"
[tabIndexStart]="newsletterBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('billingAddress', $event)"
[data]="data.billingAddress"
(dataChanges)="patchFormData('billingAddress', $event)"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidatorFns"
>
Abweichende Rechnungsadresse anlegen
</app-deviating-address-form-block>
</div>
<div class="mt-8">
<h4 class="-mb-6">Lieferadresse</h4>
<ui-form-control class="-mb-5" [showHint]="false">
<input type="text" [value]="(shippingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" />
</ui-form-control>
<app-deviating-address-form-block
#ddaBlock
[defaults]="{ address: { country: 'DEU' } }"
[tabIndexStart]="dbaBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidatorFns"
>
Abweichende Lieferadresse anlegen
</app-deviating-address-form-block>
</div>
<app-birth-date-form-block
#bdBlock
[tabIndexStart]="ddaBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
[requiredMark]="true"
[validatorFns]="birthDateValidatorFns"
></app-birth-date-form-block>
<app-interests-form-block
#inBlock
[tabIndexStart]="bdBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('interests', $event)"
[data]="data.interests"
(dataChanges)="patchFormData('interests', $event)"
></app-interests-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
@if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()">
<h1 class="title flex flex-row items-center justify-center">Kundenkartendaten erfasen</h1>
<p class="description">Bitte erfassen Sie die Kundenkarte</p>
<app-customer-type-selector
[processId]="processId$ | async"
[p4mUser]="true"
customerType="webshop"
[readonly]="true"
></app-customer-type-selector>
<app-p4m-number-form-block
#p4mBlock
[tabIndexStart]="1"
(onInit)="addFormBlock('p4m', $event)"
[data]="data.p4m"
(dataChanges)="patchFormData('p4m', $event)"
[focusAfterInit]="!data?._meta?.p4mRequired"
[asyncValidatorFns]="asyncLoyaltyCardValidatorFn"
></app-p4m-number-form-block>
<app-accept-agb-form-block
[tabIndexStart]="inBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('agb', $event)"
[data]="data.agb"
(dataChanges)="patchFormData('agb', $event)"
[requiredMark]="true"
[validatorFns]="agbValidatorFns"
></app-accept-agb-form-block>
<app-newsletter-form-block
class="mb-4"
#newsletterBlock
[tabIndexStart]="p4mBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('newsletter', $event)"
[data]="data.newsletter"
(dataChanges)="patchFormData('newsletter', $event)"
[focusAfterInit]="data?._meta?.p4mRequired"
></app-newsletter-form-block>
<app-name-form-block (onInit)="addFormBlock('name', $event)" [data]="data.name" readonly></app-name-form-block>
<app-email-form-block (onInit)="addFormBlock('email', $event)" [data]="data.email" readonly></app-email-form-block>
<app-organisation-form-block
(onInit)="addFormBlock('organisation', $event)"
appearence="compact"
[data]="data.organisation"
readonly
></app-organisation-form-block>
<app-address-form-block [data]="data.address" readonly></app-address-form-block>
<div class="mt-8">
<h4 class="-mb-6">Rechnungsadresse</h4>
<ui-form-control class="-mb-5" [showHint]="false">
<input type="text" [value]="(billingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" />
</ui-form-control>
<app-deviating-address-form-block
#dbaBlock
[defaults]="{ address: { country: 'DEU' } }"
[tabIndexStart]="newsletterBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('billingAddress', $event)"
[data]="data.billingAddress"
(dataChanges)="patchFormData('billingAddress', $event)"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidatorFns"
>
Abweichende Rechnungsadresse anlegen
</app-deviating-address-form-block>
</div>
<div class="mt-8">
<h4 class="-mb-6">Lieferadresse</h4>
<ui-form-control class="-mb-5" [showHint]="false">
<input type="text" [value]="(shippingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" />
</ui-form-control>
<app-deviating-address-form-block
#ddaBlock
[defaults]="{ address: { country: 'DEU' } }"
[tabIndexStart]="dbaBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[data]="data.deviatingDeliveryAddress"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="nameRequiredMarks"
[nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
[addressValidatorFns]="addressValidatorFns"
>
Abweichende Lieferadresse anlegen
</app-deviating-address-form-block>
</div>
<app-birth-date-form-block
#bdBlock
[tabIndexStart]="ddaBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)"
[data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
[requiredMark]="true"
[validatorFns]="birthDateValidatorFns"
></app-birth-date-form-block>
<app-interests-form-block
#inBlock
[tabIndexStart]="bdBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('interests', $event)"
[data]="data.interests"
(dataChanges)="patchFormData('interests', $event)"
></app-interests-form-block>
<div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>
}

View File

@@ -1,19 +1,22 @@
<div class="flex flex-row justify-end -mt-4 -mr-2">
<a
*ngIf="detailsRoute$ | async; let detailsRoute"
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
@if (detailsRoute$ | async; as detailsRoute) {
<a
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
}
</div>
<h1 class="text-2xl text-center font-bold mb-6">Rechnungsadresse hinzufügen</h1>
<form [formGroup]="formGroup" (ngSubmit)="save()">
<shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="1" [autofocus]="true">
<shared-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
@for (gender of genderSettings.genders; track gender) {
<shared-select-option [value]="gender.value">{{ gender.label }}</shared-select-option>
}
</shared-select>
</shared-form-control>
@@ -62,9 +65,11 @@
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="11">
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3">
{{ country.name }}
</shared-select-option>
@for (country of countries$ | async; track country) {
<shared-select-option [value]="country.isO3166_A_3">
{{ country.name }}
</shared-select-option>
}
</shared-select>
</shared-form-control>
@@ -76,7 +81,7 @@
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
>
>
Speichern
</button>
</div>

View File

@@ -6,7 +6,7 @@ import { FormControlComponent } from '@shared/components/form-control';
import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, Gender, PayerDTO } from '@generated/swagger/crm-api';
import { map } from 'rxjs/operators';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { AddressSelectionModalService } from '@modal/address-selection';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation';
@@ -26,13 +26,11 @@ import { GenderSettingsService } from '@shared/services/gender';
IconComponent,
RouterLink,
AsyncPipe,
NgIf,
NgForOf,
ReactiveFormsModule,
SelectModule,
FormControlComponent,
CheckboxComponent,
],
CheckboxComponent
],
})
export class AddBillingAddressMainViewComponent {
private _customerService = inject(CrmCustomerService);

View File

@@ -1,181 +1,183 @@
<div class="flex flex-row justify-end -mt-4 -mr-2">
<a
*ngIf="detailsRoute$ | async; let detailsRoute"
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
@if (detailsRoute$ | async; as detailsRoute) {
<a
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
}
</div>
<h1 class="text-2xl text-center font-bold mb-6">Lieferadresse hinzufügen</h1>
<form [formGroup]="formGroup" (ngSubmit)="save()">
<ng-container *ngIf="isBusinessKonto$ | async">
@if (isBusinessKonto$ | async) {
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Firma *' : 'Firma'"
class="col-span-2"
>
>
<input
class="input-control"
placeholder="Firma"
type="text"
formControlName="organisation"
tabindex="1"
/>
</shared-form-control>
/>
</shared-form-control>
<shared-form-control label="Abteilung">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="department"
tabindex="2"
/>
</shared-form-control>
<shared-form-control label="USt-ID">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="vatId"
tabindex="3"
/>
</shared-form-control>
}
<shared-form-control label="Abteilung">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="department"
tabindex="2"
/>
</shared-form-control>
<shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
@for (gender of genderSettings.genders; track gender) {
<shared-select-option [value]="gender.value">{{
gender.label
}}</shared-select-option>
}
</shared-select>
</shared-form-control>
<shared-form-control label="USt-ID">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="vatId"
tabindex="3"
/>
</shared-form-control>
</ng-container>
<shared-form-control label="Titel">
<shared-select formControlName="title" placeholder="Titel" tabindex="5">
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
<shared-select-option value="Dr.">Dr.</shared-select-option>
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
<shared-select-option value="Prof.">Prof.</shared-select-option>
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
<shared-select-option value="RA">RA</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
<shared-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{
gender.label
}}</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Nachname *' : 'Nachname'"
>
<input
class="input-control"
placeholder="Nachname"
type="text"
formControlName="lastName"
tabindex="6"
/>
</shared-form-control>
<shared-form-control label="Titel">
<shared-select formControlName="title" placeholder="Titel" tabindex="5">
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
<shared-select-option value="Dr.">Dr.</shared-select-option>
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
<shared-select-option value="Prof.">Prof.</shared-select-option>
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
<shared-select-option value="RA">RA</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Vorname *' : 'Vorname'"
>
<input
class="input-control"
placeholder="Vorname"
type="text"
formControlName="firstName"
tabindex="7"
/>
</shared-form-control>
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Nachname *' : 'Nachname'"
>
<input
class="input-control"
placeholder="Nachname"
type="text"
formControlName="lastName"
tabindex="6"
/>
</shared-form-control>
@if (!(isBusinessKonto$ | async)) {
<shared-form-control label="Firma" class="col-span-2">
<input
class="input-control"
placeholder="Firma"
type="text"
formControlName="organisation"
tabindex="8"
/>
</shared-form-control>
}
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Vorname *' : 'Vorname'"
>
<input
class="input-control"
placeholder="Vorname"
type="text"
formControlName="firstName"
tabindex="7"
/>
</shared-form-control>
<shared-form-control label="Straße">
<input
class="input-control"
placeholder="Straße"
type="text"
formControlName="street"
tabindex="9"
/>
</shared-form-control>
<ng-container *ngIf="!(isBusinessKonto$ | async)">
<shared-form-control label="Firma" class="col-span-2">
<input
class="input-control"
placeholder="Firma"
type="text"
formControlName="organisation"
tabindex="8"
/>
</shared-form-control>
</ng-container>
<shared-form-control label="Hausnummer">
<input
class="input-control"
placeholder="Hausnummer"
type="text"
formControlName="streetNumber"
tabindex="10"
/>
</shared-form-control>
<shared-form-control label="Straße">
<input
class="input-control"
placeholder="Straße"
type="text"
formControlName="street"
tabindex="9"
/>
</shared-form-control>
<shared-form-control label="PLZ">
<input
class="input-control"
placeholder="PLZ"
type="text"
formControlName="zipCode"
tabindex="11"
/>
</shared-form-control>
<shared-form-control label="Hausnummer">
<input
class="input-control"
placeholder="Hausnummer"
type="text"
formControlName="streetNumber"
tabindex="10"
/>
</shared-form-control>
<shared-form-control label="Ort">
<input
class="input-control"
placeholder="Ort"
type="text"
formControlName="city"
tabindex="12"
/>
</shared-form-control>
<shared-form-control label="PLZ">
<input
class="input-control"
placeholder="PLZ"
type="text"
formControlName="zipCode"
tabindex="11"
/>
</shared-form-control>
<shared-form-control label="Adresszusatz" class="col-span-2">
<input
class="input-control"
placeholder="Adresszusatz"
type="text"
formControlName="info"
tabindex="13"
/>
</shared-form-control>
<shared-form-control label="Ort">
<input
class="input-control"
placeholder="Ort"
type="text"
formControlName="city"
tabindex="12"
/>
</shared-form-control>
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="14">
@for (country of countries$ | async; track country) {
<shared-select-option
[value]="country.isO3166_A_3"
>
{{ country.name }}
</shared-select-option>
}
</shared-select>
</shared-form-control>
<shared-form-control label="Adresszusatz" class="col-span-2">
<input
class="input-control"
placeholder="Adresszusatz"
type="text"
formControlName="info"
tabindex="13"
/>
</shared-form-control>
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="14">
<shared-select-option
*ngFor="let country of countries$ | async"
[value]="country.isO3166_A_3"
>
{{ country.name }}
</shared-select-option>
</shared-select>
</shared-form-control>
<div class="text-center col-span-2">
<shared-checkbox formControlName="isDefault"
>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox
>
</div>
<div class="mt-6 text-center col-span-2">
<button
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
tabindex="15"
>
Speichern
</button>
</div>
</form>
<div class="text-center col-span-2">
<shared-checkbox formControlName="isDefault"
>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox
>
</div>
<div class="mt-6 text-center col-span-2">
<button
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
tabindex="15"
>
Speichern
</button>
</div>
</form>

View File

@@ -6,7 +6,7 @@ import { FormControlComponent } from '@shared/components/form-control';
import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, Gender, ShippingAddressDTO } from '@generated/swagger/crm-api';
import { map, takeUntil } from 'rxjs/operators';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { AddressSelectionModalService } from '@modal/address-selection';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation';
@@ -27,13 +27,11 @@ import { validateCompanyOrPersonalInfoRequired } from '../../validators/gender-b
RouterLink,
IconComponent,
AsyncPipe,
NgIf,
NgForOf,
ReactiveFormsModule,
SelectModule,
FormControlComponent,
CheckboxComponent,
],
CheckboxComponent
],
})
export class AddShippingAddressMainViewComponent implements OnInit, OnDestroy {
private _customerService = inject(CrmCustomerService);

View File

@@ -1,71 +1,77 @@
<div class="grid grid-flow-col items-center justify-between px-4 py-2 border-t-2 border-solid border-surface-2">
<h3 class="font-bold text-xl">Rechnungsadresse</h3>
<a
*ngIf="addBillingAddressRoute$ | async; let addRoute"
type="button"
class="text-brand font-bold"
[routerLink]="addRoute.path"
[queryParams]="addRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Hinzufügen
</a>
@if (addBillingAddressRoute$ | async; as addRoute) {
<a
type="button"
class="text-brand font-bold"
[routerLink]="addRoute.path"
[queryParams]="addRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Hinzufügen
</a>
}
</div>
<div class="grid grid-flow-row">
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 flex flex-row justify-between items-center"
*ngIf="showCustomerAddress$ | async"
>
<input
*ngIf="isNotBusinessKonto$ | async"
name="assigned-payer"
type="radio"
[checked]="!(selectedPayer$ | async)"
(change)="selectCustomerAddress()"
/>
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ customer$ | async | address }}
</span>
<a
*ngIf="editRoute$ | async; let editRoute"
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
class="text-brand font-bold"
type="button"
@if (showCustomerAddress$ | async) {
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 flex flex-row justify-between items-center"
>
Bearbeiten
</a>
</div>
</label>
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row items-center justify-start"
*ngFor="let assignedPayer of assignedPayers$ | async"
>
<input
name="assigned-payer"
type="radio"
[value]="assignedPayer"
[checked]="(selectedPayer$ | async)?.payer.id === assignedPayer.payer.id"
(change)="selectPayer(assignedPayer)"
/>
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ assignedPayer.payer.data | address }}
</span>
<ng-container *ngIf="canEditAddress$ | async">
<a
*ngIf="editRoute(assignedPayer.payer.id); let editRoute"
class="text-brand font-bold"
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Bearbeiten
</a>
</ng-container>
</div>
</label>
@if (isNotBusinessKonto$ | async) {
<input
name="assigned-payer"
type="radio"
[checked]="!(selectedPayer$ | async)"
(change)="selectCustomerAddress()"
/>
}
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ customer$ | async | address }}
</span>
@if (editRoute$ | async; as editRoute) {
<a
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
class="text-brand font-bold"
type="button"
>
Bearbeiten
</a>
}
</div>
</label>
}
@for (assignedPayer of assignedPayers$ | async; track assignedPayer) {
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row items-center justify-start"
>
<input
name="assigned-payer"
type="radio"
[value]="assignedPayer"
[checked]="(selectedPayer$ | async)?.payer.id === assignedPayer.payer.id"
(change)="selectPayer(assignedPayer)"
/>
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ assignedPayer.payer.data | address }}
</span>
@if (canEditAddress$ | async) {
@if (editRoute(assignedPayer.payer.id); as editRoute) {
<a
class="text-brand font-bold"
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Bearbeiten
</a>
}
}
</div>
</label>
}
</div>

View File

@@ -4,7 +4,7 @@ import { CrmCustomerService } from '@domain/crm';
import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators';
import { Observable, Subject, combineLatest } from 'rxjs';
import { AssignedPayerDTO, CustomerDTO, ListResponseArgsOfAssignedPayerDTO } from '@generated/swagger/crm-api';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { CustomerPipesModule } from '@shared/pipes/customer';
import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators';
@@ -26,7 +26,7 @@ interface DetailsMainViewBillingAddressesComponentState {
styleUrls: ['details-main-view-billing-addresses.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-details-main-view-billing-addresses' },
imports: [NgIf, NgFor, AsyncPipe, CustomerPipesModule, RouterLink],
imports: [AsyncPipe, CustomerPipesModule, RouterLink],
})
export class DetailsMainViewBillingAddressesComponent
extends ComponentStore<DetailsMainViewBillingAddressesComponentState>

View File

@@ -1,64 +1,69 @@
<div class="grid grid-flow-col items-center justify-between px-4 py-2 border-t-2 border-solid border-surface-2">
<h3 class="font-bold text-xl">Lieferadresse</h3>
<a
*ngIf="addShippingAddressRoute$ | async; let addRoute"
type="button"
class="text-brand font-bold"
[routerLink]="addRoute.path"
[queryParams]="addRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Hinzufügen
</a>
@if (addShippingAddressRoute$ | async; as addRoute) {
<a
type="button"
class="text-brand font-bold"
[routerLink]="addRoute.path"
[queryParams]="addRoute.queryParams"
[queryParamsHandling]="'merge'"
>
Hinzufügen
</a>
}
</div>
<div class="grid grid-flow-row">
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
*ngIf="showCustomerAddress$ | async"
>
<input name="shipping-address" type="radio" [checked]="!(selectedShippingAddress$ | async)" (change)="selectCustomerAddress()" />
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ customer$ | async | address }}
</span>
<a
*ngIf="editRoute$ | async; let editRoute"
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
class="text-brand font-bold"
type="button"
@if (showCustomerAddress$ | async) {
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
>
Bearbeiten
</a>
</div>
</label>
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
*ngFor="let shippingAddress of shippingAddresses$ | async"
>
<input
name="shipping-address"
type="radio"
[value]="shippingAddress"
[checked]="(selectedShippingAddress$ | async)?.id === shippingAddress.id"
(change)="selectShippingAddress(shippingAddress)"
/>
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ shippingAddress | address }}
</span>
<a
*ngIf="editShippingAddressRoute$(shippingAddress.id) | async; let route"
class="text-brand font-bold"
type="button"
[routerLink]="route?.path"
[queryParams]="route?.queryParams"
[queryParamsHandling]="'merge'"
<input name="shipping-address" type="radio" [checked]="!(selectedShippingAddress$ | async)" (change)="selectCustomerAddress()" />
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ customer$ | async | address }}
</span>
@if (editRoute$ | async; as editRoute) {
<a
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
class="text-brand font-bold"
type="button"
>
Bearbeiten
</a>
}
</div>
</label>
}
@for (shippingAddress of shippingAddresses$ | async; track shippingAddress) {
<label
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
>
Bearbeiten
</a>
</div>
</label>
<input
name="shipping-address"
type="radio"
[value]="shippingAddress"
[checked]="(selectedShippingAddress$ | async)?.id === shippingAddress.id"
(change)="selectShippingAddress(shippingAddress)"
/>
<div class="ml-2 flex flex-row justify-between items-start grow">
<span class="mr-4">
{{ shippingAddress | address }}
</span>
@if (editShippingAddressRoute$(shippingAddress.id) | async; as route) {
<a
class="text-brand font-bold"
type="button"
[routerLink]="route?.path"
[queryParams]="route?.queryParams"
[queryParamsHandling]="'merge'"
>
Bearbeiten
</a>
}
</div>
</label>
}
</div>

View File

@@ -4,7 +4,7 @@ import { CrmCustomerService } from '@domain/crm';
import { map, switchMap, takeUntil } from 'rxjs/operators';
import { Observable, Subject, combineLatest } from 'rxjs';
import { CustomerDTO, ListResponseArgsOfAssignedPayerDTO, ShippingAddressDTO } from '@generated/swagger/crm-api';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { CustomerPipesModule } from '@shared/pipes/customer';
import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators';
@@ -25,7 +25,7 @@ interface DetailsMainViewDeliveryAddressesComponentState {
styleUrls: ['details-main-view-delivery-addresses.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-details-main-view-delivery-addresses' },
imports: [NgIf, NgFor, AsyncPipe, CustomerPipesModule, RouterLink],
imports: [AsyncPipe, CustomerPipesModule, RouterLink],
})
export class DetailsMainViewDeliveryAddressesComponent
extends ComponentStore<DetailsMainViewDeliveryAddressesComponentState>

View File

@@ -23,40 +23,47 @@
{{ customerType$ | async }}
</span>
</div>
<ng-container *ngIf="showEditButton$ | async">
<a
*ngIf="editRoute$ | async; let editRoute"
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
class="btn btn-label font-bold text-brand"
>
Bearbeiten
</a>
</ng-container>
@if (showEditButton$ | async) {
@if (editRoute$ | async; as editRoute) {
<a
[routerLink]="editRoute.path"
[queryParams]="editRoute.queryParams"
[queryParamsHandling]="'merge'"
class="btn btn-label font-bold text-brand"
>
Bearbeiten
</a>
}
}
</div>
<div class="customer-details-customer-main-data px-5 py-3 grid grid-flow-row gap-3">
<div class="flex flex-row">
<div class="data-label">Erstellungsdatum</div>
<div *ngIf="created$ | async; let created" class="data-value">
{{ created | date: 'dd.MM.yyyy' }} | {{ created | date: 'HH:mm' }} Uhr
</div>
@if (created$ | async; as created) {
<div class="data-value">
{{ created | date: 'dd.MM.yyyy' }} | {{ created | date: 'HH:mm' }} Uhr
</div>
}
</div>
<div class="flex flex-row">
<div class="data-label">Kundennummer</div>
<div class="data-value">{{ customerNumber$ | async }}</div>
</div>
<div class="flex flex-row" *ngIf="customerNumberDig$ | async; let customerNumberDig">
<div class="data-label">Kundennummer-DIG</div>
<div class="data-value">{{ customerNumberDig }}</div>
</div>
<div class="flex flex-row" *ngIf="customerNumberBeeline$ | async; let customerNumberBeeline">
<div class="data-label">Kundennummer-BEELINE</div>
<div class="data-value">{{ customerNumberBeeline }}</div>
</div>
@if (customerNumberDig$ | async; as customerNumberDig) {
<div class="flex flex-row">
<div class="data-label">Kundennummer-DIG</div>
<div class="data-value">{{ customerNumberDig }}</div>
</div>
}
@if (customerNumberBeeline$ | async; as customerNumberBeeline) {
<div class="flex flex-row">
<div class="data-label">Kundennummer-BEELINE</div>
<div class="data-value">{{ customerNumberBeeline }}</div>
</div>
}
</div>
<ng-container *ngIf="isBusinessKonto$ | async">
@if (isBusinessKonto$ | async) {
<div class="customer-details-customer-main-row">
<div class="data-label">Firmenname</div>
<div class="data-value">{{ organisationName$ | async }}</div>
@@ -69,7 +76,7 @@
<div class="data-label">USt-ID</div>
<div class="data-value">{{ vatId$ | async }}</div>
</div>
</ng-container>
}
<div class="customer-details-customer-main-row">
<div class="data-label">Anrede</div>
@@ -113,7 +120,9 @@
</div>
<div class="customer-details-customer-main-row">
<div class="data-label">Land</div>
<div *ngIf="country$ | async; let country" class="data-value">{{ country | country }}</div>
@if (country$ | async; as country) {
<div class="data-value">{{ country | country }}</div>
}
</div>
<div class="customer-details-customer-main-row">
<div class="data-label">Festnetznr.</div>
@@ -124,18 +133,18 @@
<div class="data-value">{{ mobile$ | async }}</div>
</div>
<ng-container *ngIf="!(isBusinessKonto$ | async)">
@if (!(isBusinessKonto$ | async)) {
<div class="customer-details-customer-main-row">
<div class="data-label">Geburtstag</div>
<div class="data-value">{{ dateOfBirth$ | async | date: 'dd.MM.yyyy' }}</div>
</div>
</ng-container>
<ng-container *ngIf="!(isBusinessKonto$ | async) && (organisationName$ | async)">
}
@if (!(isBusinessKonto$ | async) && (organisationName$ | async)) {
<div class="customer-details-customer-main-row">
<div class="data-label">Firmenname</div>
<div class="data-value">{{ organisationName$ | async }}</div>
</div>
<ng-container *ngIf="!(isOnlineOrCustomerCardUser$ | async)">
@if (!(isOnlineOrCustomerCardUser$ | async)) {
<div class="customer-details-customer-main-row">
<div class="data-label">Abteilung</div>
<div class="data-value">{{ department$ | async }}</div>
@@ -144,8 +153,8 @@
<div class="data-label">USt-ID</div>
<div class="data-value">{{ vatId$ | async }}</div>
</div>
</ng-container>
</ng-container>
}
}
<page-details-main-view-billing-addresses></page-details-main-view-billing-addresses>
<page-details-main-view-delivery-addresses></page-details-main-view-delivery-addresses>
@@ -153,22 +162,24 @@
</div>
</shared-loader>
<button
*ngIf="shoppingCartHasNoItems$ | async"
type="button"
(click)="continue()"
class="text-white text-lg bg-brand rounded-full px-5 py-3 absolute top-[calc(100vh-19.375rem)] left-1/2 -translate-x-1/2 font-bold disabled:bg-inactive-branch"
[disabled]="showLoader$ | async"
>
<shared-loader [loading]="showLoader$ | async" spinnerSize="32">Weiter zur Artikelsuche</shared-loader>
</button>
@if (shoppingCartHasNoItems$ | async) {
<button
type="button"
(click)="continue()"
class="text-white text-lg bg-brand rounded-full px-5 py-3 absolute top-[calc(100vh-19.375rem)] left-1/2 -translate-x-1/2 font-bold disabled:bg-inactive-branch"
[disabled]="showLoader$ | async"
>
<shared-loader [loading]="showLoader$ | async" spinnerSize="32">Weiter zur Artikelsuche</shared-loader>
</button>
}
<button
*ngIf="shoppingCartHasItems$ | async"
type="button"
(click)="continue()"
class="text-white text-lg bg-brand rounded-full px-5 py-3 absolute top-[calc(100vh-19.375rem)] left-1/2 -translate-x-1/2 font-bold disabled:bg-inactive-branch"
[disabled]="showLoader$ | async"
>
<shared-loader [loading]="showLoader$ | async" spinnerSize="32">Weiter zum Warenkorb</shared-loader>
</button>
@if (shoppingCartHasItems$ | async) {
<button
type="button"
(click)="continue()"
class="text-white text-lg bg-brand rounded-full px-5 py-3 absolute top-[calc(100vh-19.375rem)] left-1/2 -translate-x-1/2 font-bold disabled:bg-inactive-branch"
[disabled]="showLoader$ | async"
>
<shared-loader [loading]="showLoader$ | async" spinnerSize="32">Weiter zum Warenkorb</shared-loader>
</button>
}

View File

@@ -1,19 +1,22 @@
<div class="flex flex-row justify-end -mt-4 -mr-2">
<a
*ngIf="detailsRoute$ | async; let detailsRoute"
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
@if (detailsRoute$ | async; as detailsRoute) {
<a
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
}
</div>
<h1 class="text-2xl text-center font-bold mb-6">Rechnungsadresse bearbeiten</h1>
<form [formGroup]="formGroup" (ngSubmit)="save()">
<shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="1" [autofocus]="true">
<shared-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
@for (gender of genderSettings.genders; track gender) {
<shared-select-option [value]="gender.value">{{ gender.label }}</shared-select-option>
}
</shared-select>
</shared-form-control>
@@ -62,9 +65,11 @@
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="11">
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3">
{{ country.name }}
</shared-select-option>
@for (country of countries$ | async; track country) {
<shared-select-option [value]="country.isO3166_A_3">
{{ country.name }}
</shared-select-option>
}
</shared-select>
</shared-form-control>
@@ -76,7 +81,7 @@
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
>
>
Speichern
</button>
</div>

View File

@@ -6,7 +6,7 @@ import { FormControlComponent } from '@shared/components/form-control';
import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, Gender, PayerDTO } from '@generated/swagger/crm-api';
import { map, switchMap, takeUntil } from 'rxjs/operators';
import { AsyncPipe, NgForOf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { AddressSelectionModalService } from '@modal/address-selection';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation';
@@ -32,12 +32,11 @@ export interface EditBillingAddressMainViewState {
AsyncPipe,
RouterLink,
IconComponent,
NgForOf,
ReactiveFormsModule,
SelectModule,
FormControlComponent,
CheckboxComponent,
],
CheckboxComponent
],
})
export class EditBillingAddressMainViewComponent
extends ComponentStore<EditBillingAddressMainViewState>

View File

@@ -1,98 +1,105 @@
<div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1">
<a
*ngIf="detailsRoute$ | async; let route"
[routerLink]="route.path"
[queryParams]="route.queryParams"
[queryParamsHandling]="'merge'"
class="btn btn-label"
>
<ui-icon [icon]="'close'"></ui-icon>
</a>
@if (detailsRoute$ | async; as route) {
<a
[routerLink]="route.path"
[queryParams]="route.queryParams"
[queryParamsHandling]="'merge'"
class="btn btn-label"
>
<ui-icon [icon]="'close'"></ui-icon>
</a>
}
</div>
<div class="header">
<h1>Firmendetails</h1>
</div>
<form *ngIf="control" [formGroup]="control" (ngSubmit)="submit()">
<ng-container formGroupName="organisation">
<ui-form-control label="Firmenname" variant="inline">
<input uiInput type="text" formControlName="name" tabindex="1" />
</ui-form-control>
<ui-form-control label="Abteilung" variant="inline">
<input uiInput type="text" formControlName="department" tabindex="2" />
</ui-form-control>
<ui-form-control label="USt ID" variant="inline">
<input uiInput type="text" formControlName="vatId" tabindex="3" />
</ui-form-control>
</ng-container>
<ui-form-control [clearable]="true" label="Anrede" variant="inline">
<ui-select formControlName="gender" tabindex="4">
<ui-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value" [label]="gender.label"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control [clearable]="true" label="Titel" variant="inline">
<ui-select formControlName="title" tabindex="5">
<ui-select-option value="Dipl.-Ing." label="Dipl.-Ing."></ui-select-option>
<ui-select-option value="Dr." label="Dr."></ui-select-option>
<ui-select-option value="Dr. med." label="Dr. med."></ui-select-option>
<ui-select-option value="Prof." label="Prof."></ui-select-option>
<ui-select-option value="Prof. Dr." label="Prof. Dr."></ui-select-option>
<ui-select-option value="RA" label="RA"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control label="Nachname" variant="inline">
<input uiInput type="text" formControlName="lastName" tabindex="6" />
</ui-form-control>
<ui-form-control label="Vorname" variant="inline">
<input uiInput type="text" formControlName="firstName" tabindex="7" />
</ui-form-control>
<ng-container formGroupName="communicationDetails">
<ui-form-control label="E-Mail" variant="inline">
<input uiInput type="mail" formControlName="email" tabindex="8" />
</ui-form-control>
<ui-form-control label="Festnetznummer" variant="inline">
<input uiInput type="tel" formControlName="phone" tabindex="9" />
</ui-form-control>
<ui-form-control label="Mobilnummer" variant="inline">
<input uiInput type="tel" formControlName="mobile" tabindex="10" />
</ui-form-control>
</ng-container>
<ng-container formGroupName="address">
<ui-form-control label="Straße" variant="inline">
<input uiInput type="text" formControlName="street" tabindex="11" />
</ui-form-control>
<ui-form-control label="Hausnummer" variant="inline">
<input uiInput type="text" formControlName="streetNumber" tabindex="12" />
</ui-form-control>
<ui-form-control label="PLZ" variant="inline">
<input uiInput type="text" formControlName="zipCode" tabindex="13" />
</ui-form-control>
<ui-form-control label="Ort" variant="inline">
<input uiInput type="text" formControlName="city" tabindex="14" />
</ui-form-control>
<ui-form-control label="Adresszusatz" variant="inline">
<input uiInput type="text" formControlName="info" tabindex="15" />
</ui-form-control>
<ui-form-control [clearable]="true" label="Land" variant="inline">
<ui-select formControlName="country" tabindex="16">
<ui-select-option
*ngFor="let country of countries$ | async"
[label]="country.name"
[value]="country.isO3166_A_3"
></ui-select-option>
@if (control) {
<form [formGroup]="control" (ngSubmit)="submit()">
<ng-container formGroupName="organisation">
<ui-form-control label="Firmenname" variant="inline">
<input uiInput type="text" formControlName="name" tabindex="1" />
</ui-form-control>
<ui-form-control label="Abteilung" variant="inline">
<input uiInput type="text" formControlName="department" tabindex="2" />
</ui-form-control>
<ui-form-control label="USt ID" variant="inline">
<input uiInput type="text" formControlName="vatId" tabindex="3" />
</ui-form-control>
</ng-container>
<ui-form-control [clearable]="true" label="Anrede" variant="inline">
<ui-select formControlName="gender" tabindex="4">
@for (gender of genderSettings.genders; track gender) {
<ui-select-option [value]="gender.value" [label]="gender.label"></ui-select-option>
}
</ui-select>
</ui-form-control>
</ng-container>
<div class="actions">
<button class="btn-cancel" type="button" (click)="cancel()">Abbrechen</button>
<button class="btn-save" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled">
<ng-container *ngSwitchCase="true">Speichern</ng-container>
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon>
</button>
</div>
</form>
<ui-form-control [clearable]="true" label="Titel" variant="inline">
<ui-select formControlName="title" tabindex="5">
<ui-select-option value="Dipl.-Ing." label="Dipl.-Ing."></ui-select-option>
<ui-select-option value="Dr." label="Dr."></ui-select-option>
<ui-select-option value="Dr. med." label="Dr. med."></ui-select-option>
<ui-select-option value="Prof." label="Prof."></ui-select-option>
<ui-select-option value="Prof. Dr." label="Prof. Dr."></ui-select-option>
<ui-select-option value="RA" label="RA"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control label="Nachname" variant="inline">
<input uiInput type="text" formControlName="lastName" tabindex="6" />
</ui-form-control>
<ui-form-control label="Vorname" variant="inline">
<input uiInput type="text" formControlName="firstName" tabindex="7" />
</ui-form-control>
<ng-container formGroupName="communicationDetails">
<ui-form-control label="E-Mail" variant="inline">
<input uiInput type="mail" formControlName="email" tabindex="8" />
</ui-form-control>
<ui-form-control label="Festnetznummer" variant="inline">
<input uiInput type="tel" formControlName="phone" tabindex="9" />
</ui-form-control>
<ui-form-control label="Mobilnummer" variant="inline">
<input uiInput type="tel" formControlName="mobile" tabindex="10" />
</ui-form-control>
</ng-container>
<ng-container formGroupName="address">
<ui-form-control label="Straße" variant="inline">
<input uiInput type="text" formControlName="street" tabindex="11" />
</ui-form-control>
<ui-form-control label="Hausnummer" variant="inline">
<input uiInput type="text" formControlName="streetNumber" tabindex="12" />
</ui-form-control>
<ui-form-control label="PLZ" variant="inline">
<input uiInput type="text" formControlName="zipCode" tabindex="13" />
</ui-form-control>
<ui-form-control label="Ort" variant="inline">
<input uiInput type="text" formControlName="city" tabindex="14" />
</ui-form-control>
<ui-form-control label="Adresszusatz" variant="inline">
<input uiInput type="text" formControlName="info" tabindex="15" />
</ui-form-control>
<ui-form-control [clearable]="true" label="Land" variant="inline">
<ui-select formControlName="country" tabindex="16">
@for (country of countries$ | async; track country) {
<ui-select-option
[label]="country.name"
[value]="country.isO3166_A_3"
></ui-select-option>
}
</ui-select>
</ui-form-control>
</ng-container>
<div class="actions">
<button class="btn-cancel" type="button" (click)="cancel()">Abbrechen</button>
<button class="btn-save" type="submit" [disabled]="control.invalid || control.disabled">
@switch (control.enabled) {
@case (true) {
Speichern
}
@case (false) {
<ui-icon class="spin" icon="loading" size="18px"></ui-icon>
}
}
</button>
</div>
</form>
}

View File

@@ -1,101 +1,110 @@
<div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1">
<a
*ngIf="detailsRoute$ | async; let route"
[routerLink]="route.path"
[queryParams]="route.queryParams"
[queryParamsHandling]="'merge'"
class="btn btn-label"
>
<ui-icon [icon]="'close'"></ui-icon>
</a>
@if (detailsRoute$ | async; as route) {
<a
[routerLink]="route.path"
[queryParams]="route.queryParams"
[queryParamsHandling]="'merge'"
class="btn btn-label"
>
<ui-icon [icon]="'close'"></ui-icon>
</a>
}
</div>
<div class="header">
<h1>Kundendetails</h1>
</div>
<form *ngIf="control" [formGroup]="control" (ngSubmit)="submit()">
<ui-form-control [clearable]="true" label="Anrede" variant="inline">
<ui-select formControlName="gender" tabindex="1">
<ui-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value" [label]="gender.label"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control [clearable]="true" label="Titel" variant="inline">
<ui-select formControlName="title" tabindex="2">
<ui-select-option value="Dipl.-Ing." label="Dipl.-Ing."></ui-select-option>
<ui-select-option value="Dr." label="Dr."></ui-select-option>
<ui-select-option value="Dr. med." label="Dr. med."></ui-select-option>
<ui-select-option value="Prof." label="Prof."></ui-select-option>
<ui-select-option value="Prof. Dr." label="Prof. Dr."></ui-select-option>
<ui-select-option value="RA" label="RA"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control label="Nachname" variant="inline">
<input uiInput type="text" formControlName="lastName" tabindex="3" />
</ui-form-control>
<ui-form-control label="Vorname" variant="inline">
<input uiInput type="text" formControlName="firstName" tabindex="4" />
</ui-form-control>
<ui-form-control label="E-Mail" formGroupName="communicationDetails" variant="inline">
<input uiInput type="mail" formControlName="email" tabindex="5" />
</ui-form-control>
<ng-container formGroupName="address">
<ui-form-control label="Straße" variant="inline">
<input uiInput type="text" formControlName="street" tabindex="6" />
</ui-form-control>
<ui-form-control label="Hausnummer" variant="inline">
<input uiInput type="text" formControlName="streetNumber" tabindex="7" />
</ui-form-control>
<ui-form-control label="PLZ" variant="inline">
<input uiInput type="text" formControlName="zipCode" tabindex="8" />
</ui-form-control>
<ui-form-control label="Ort" variant="inline">
<input uiInput type="text" formControlName="city" tabindex="9" />
</ui-form-control>
<ui-form-control label="Adresszusatz" variant="inline">
<input uiInput type="text" formControlName="info" tabindex="10" />
</ui-form-control>
<ui-form-control [clearable]="true" label="Land" variant="inline">
<ui-select formControlName="country" tabindex="11">
<ui-select-option
*ngFor="let country of countries$ | async"
[label]="country.name"
[value]="country.isO3166_A_3"
></ui-select-option>
@if (control) {
<form [formGroup]="control" (ngSubmit)="submit()">
<ui-form-control [clearable]="true" label="Anrede" variant="inline">
<ui-select formControlName="gender" tabindex="1">
@for (gender of genderSettings.genders; track gender) {
<ui-select-option [value]="gender.value" [label]="gender.label"></ui-select-option>
}
</ui-select>
</ui-form-control>
</ng-container>
<ng-container formGroupName="communicationDetails">
<ui-form-control label="Festnetznummer" variant="inline">
<input uiInput type="tel" formControlName="phone" tabindex="12" />
<ui-form-control [clearable]="true" label="Titel" variant="inline">
<ui-select formControlName="title" tabindex="2">
<ui-select-option value="Dipl.-Ing." label="Dipl.-Ing."></ui-select-option>
<ui-select-option value="Dr." label="Dr."></ui-select-option>
<ui-select-option value="Dr. med." label="Dr. med."></ui-select-option>
<ui-select-option value="Prof." label="Prof."></ui-select-option>
<ui-select-option value="Prof. Dr." label="Prof. Dr."></ui-select-option>
<ui-select-option value="RA" label="RA"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control label="Mobilnummer" variant="inline">
<input uiInput type="tel" formControlName="mobile" tabindex="13" />
<ui-form-control label="Nachname" variant="inline">
<input uiInput type="text" formControlName="lastName" tabindex="3" />
</ui-form-control>
</ng-container>
<ui-form-control label="Geburtsdatum" variant="inline">
<input uiDateInput type="text" formControlName="dateOfBirth" tabindex="14" />
</ui-form-control>
<ng-container formGroupName="organisation">
<ui-form-control label="Firmenname" variant="inline">
<input uiInput type="text" formControlName="name" tabindex="15" />
<ui-form-control label="Vorname" variant="inline">
<input uiInput type="text" formControlName="firstName" tabindex="4" />
</ui-form-control>
<ng-container *ngIf="!(isOnlineOrCustomerCardUser$ | async)">
<ui-form-control label="Abteilung" variant="inline">
<input uiInput type="text" formControlName="department" tabindex="16" />
<ui-form-control label="E-Mail" formGroupName="communicationDetails" variant="inline">
<input uiInput type="mail" formControlName="email" tabindex="5" />
</ui-form-control>
<ng-container formGroupName="address">
<ui-form-control label="Straße" variant="inline">
<input uiInput type="text" formControlName="street" tabindex="6" />
</ui-form-control>
<ui-form-control label="USt ID" variant="inline">
<input uiInput type="text" formControlName="vatId" tabindex="17" />
<ui-form-control label="Hausnummer" variant="inline">
<input uiInput type="text" formControlName="streetNumber" tabindex="7" />
</ui-form-control>
<ui-form-control label="PLZ" variant="inline">
<input uiInput type="text" formControlName="zipCode" tabindex="8" />
</ui-form-control>
<ui-form-control label="Ort" variant="inline">
<input uiInput type="text" formControlName="city" tabindex="9" />
</ui-form-control>
<ui-form-control label="Adresszusatz" variant="inline">
<input uiInput type="text" formControlName="info" tabindex="10" />
</ui-form-control>
<ui-form-control [clearable]="true" label="Land" variant="inline">
<ui-select formControlName="country" tabindex="11">
@for (country of countries$ | async; track country) {
<ui-select-option
[label]="country.name"
[value]="country.isO3166_A_3"
></ui-select-option>
}
</ui-select>
</ui-form-control>
</ng-container>
</ng-container>
<div class="actions">
<button class="btn-cancel" type="button" (click)="cancel()">Abbrechen</button>
<button class="btn-save" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled">
<ng-container *ngSwitchCase="true">Speichern</ng-container>
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon>
</button>
</div>
</form>
<ng-container formGroupName="communicationDetails">
<ui-form-control label="Festnetznummer" variant="inline">
<input uiInput type="tel" formControlName="phone" tabindex="12" />
</ui-form-control>
<ui-form-control label="Mobilnummer" variant="inline">
<input uiInput type="tel" formControlName="mobile" tabindex="13" />
</ui-form-control>
</ng-container>
<ui-form-control label="Geburtsdatum" variant="inline">
<input uiDateInput type="text" formControlName="dateOfBirth" tabindex="14" />
</ui-form-control>
<ng-container formGroupName="organisation">
<ui-form-control label="Firmenname" variant="inline">
<input uiInput type="text" formControlName="name" tabindex="15" />
</ui-form-control>
@if (!(isOnlineOrCustomerCardUser$ | async)) {
<ui-form-control label="Abteilung" variant="inline">
<input uiInput type="text" formControlName="department" tabindex="16" />
</ui-form-control>
<ui-form-control label="USt ID" variant="inline">
<input uiInput type="text" formControlName="vatId" tabindex="17" />
</ui-form-control>
}
</ng-container>
<div class="actions">
<button class="btn-cancel" type="button" (click)="cancel()">Abbrechen</button>
<button class="btn-save" type="submit" [disabled]="control.invalid || control.disabled">
@switch (control.enabled) {
@case (true) {
Speichern
}
@case (false) {
<ui-icon class="spin" icon="loading" size="18px"></ui-icon>
}
}
</button>
</div>
</form>
}

View File

@@ -1,17 +1,18 @@
<div class="flex flex-row justify-end -mt-4 -mr-2">
<a
*ngIf="detailsRoute$ | async; let detailsRoute"
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
@if (detailsRoute$ | async; as detailsRoute) {
<a
[routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
>
<shared-icon icon="close" [size]="32"></shared-icon>
</a>
}
</div>
<h1 class="text-2xl text-center font-bold mb-6">Lieferadresse bearbeiten</h1>
<form [formGroup]="formGroup" (ngSubmit)="save()">
<ng-container *ngIf="isBusinessKonto$ | async">
@if (isBusinessKonto$ | async) {
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Firma *' : 'Firma'"
class="col-span-2"
@@ -19,175 +20,176 @@
formGroup.controls.organisation.errors?.required ||
formGroup.errors?.eitherCompanyOrPersonalRequired
"
>
>
<input
class="input-control"
placeholder="Firma"
type="text"
formControlName="organisation"
tabindex="1"
/>
</shared-form-control>
/>
</shared-form-control>
<shared-form-control label="Abteilung">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="department"
tabindex="2"
/>
</shared-form-control>
<shared-form-control label="USt-ID">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="vatId"
tabindex="3"
/>
</shared-form-control>
}
<shared-form-control label="Abteilung">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="department"
tabindex="2"
/>
</shared-form-control>
<shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
@for (gender of genderSettings.genders; track gender) {
<shared-select-option [value]="gender.value">{{
gender.label
}}</shared-select-option>
}
</shared-select>
</shared-form-control>
<shared-form-control label="USt-ID">
<input
class="input-control"
placeholder="Abteilung"
type="text"
formControlName="vatId"
tabindex="3"
/>
</shared-form-control>
</ng-container>
<shared-form-control label="Titel">
<shared-select formControlName="title" placeholder="Titel" tabindex="5">
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
<shared-select-option value="Dr.">Dr.</shared-select-option>
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
<shared-select-option value="Prof.">Prof.</shared-select-option>
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
<shared-select-option value="RA">RA</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
<shared-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{
gender.label
}}</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control label="Titel">
<shared-select formControlName="title" placeholder="Titel" tabindex="5">
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
<shared-select-option value="Dr.">Dr.</shared-select-option>
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
<shared-select-option value="Prof.">Prof.</shared-select-option>
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
<shared-select-option value="RA">RA</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Nachname *' : 'Nachname'"
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Nachname *' : 'Nachname'"
[hasRequiredMark]="
formGroup.controls.lastName.errors?.required ||
formGroup.errors?.eitherCompanyOrPersonalRequired
"
>
<input
class="input-control"
placeholder="Nachname"
type="text"
formControlName="lastName"
tabindex="6"
/>
</shared-form-control>
>
<input
class="input-control"
placeholder="Nachname"
type="text"
formControlName="lastName"
tabindex="6"
/>
</shared-form-control>
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Vorname *' : 'Vorname'"
<shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Vorname *' : 'Vorname'"
[hasRequiredMark]="
formGroup.controls.firstName.errors?.required ||
formGroup.errors?.eitherCompanyOrPersonalRequired
"
>
<input
class="input-control"
placeholder="Vorname"
type="text"
formControlName="firstName"
tabindex="7"
/>
</shared-form-control>
>
<input
class="input-control"
placeholder="Vorname"
type="text"
formControlName="firstName"
tabindex="7"
/>
</shared-form-control>
<ng-container *ngIf="!(isBusinessKonto$ | async)">
<shared-form-control label="Firma" class="col-span-2">
<input
class="input-control"
placeholder="Firma"
type="text"
formControlName="organisation"
tabindex="8"
/>
</shared-form-control>
</ng-container>
@if (!(isBusinessKonto$ | async)) {
<shared-form-control label="Firma" class="col-span-2">
<input
class="input-control"
placeholder="Firma"
type="text"
formControlName="organisation"
tabindex="8"
/>
</shared-form-control>
}
<shared-form-control label="Straße">
<input
class="input-control"
placeholder="Straße"
type="text"
formControlName="street"
tabindex="9"
/>
</shared-form-control>
<shared-form-control label="Straße">
<input
class="input-control"
placeholder="Straße"
type="text"
formControlName="street"
tabindex="9"
/>
</shared-form-control>
<shared-form-control label="Hausnummer">
<input
class="input-control"
placeholder="Hausnummer"
type="text"
formControlName="streetNumber"
tabindex="10"
/>
</shared-form-control>
<shared-form-control label="Hausnummer">
<input
class="input-control"
placeholder="Hausnummer"
type="text"
formControlName="streetNumber"
tabindex="10"
/>
</shared-form-control>
<shared-form-control label="PLZ">
<input
class="input-control"
placeholder="PLZ"
type="text"
formControlName="zipCode"
tabindex="11"
/>
</shared-form-control>
<shared-form-control label="PLZ">
<input
class="input-control"
placeholder="PLZ"
type="text"
formControlName="zipCode"
tabindex="11"
/>
</shared-form-control>
<shared-form-control label="Ort">
<input
class="input-control"
placeholder="Ort"
type="text"
formControlName="city"
tabindex="12"
/>
</shared-form-control>
<shared-form-control label="Ort">
<input
class="input-control"
placeholder="Ort"
type="text"
formControlName="city"
tabindex="12"
/>
</shared-form-control>
<shared-form-control label="Adresszusatz" class="col-span-2">
<input
class="input-control"
placeholder="Adresszusatz"
type="text"
formControlName="info"
tabindex="13"
/>
</shared-form-control>
<shared-form-control label="Adresszusatz" class="col-span-2">
<input
class="input-control"
placeholder="Adresszusatz"
type="text"
formControlName="info"
tabindex="13"
/>
</shared-form-control>
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="14">
<shared-select-option
*ngFor="let country of countries$ | async"
[value]="country.isO3166_A_3"
>
{{ country.name }}
</shared-select-option>
</shared-select>
</shared-form-control>
<shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="14">
@for (country of countries$ | async; track country) {
<shared-select-option
[value]="country.isO3166_A_3"
>
{{ country.name }}
</shared-select-option>
}
</shared-select>
</shared-form-control>
<div class="text-center col-span-2">
<shared-checkbox formControlName="isDefault"
>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox
>
</div>
<div class="mt-6 text-center col-span-2">
<button
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
tabindex="15"
>
Speichern
</button>
</div>
</form>
<div class="text-center col-span-2">
<shared-checkbox formControlName="isDefault"
>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox
>
</div>
<div class="mt-6 text-center col-span-2">
<button
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
tabindex="15"
>
Speichern
</button>
</div>
</form>

View File

@@ -13,7 +13,7 @@ import { FormControlComponent } from '@shared/components/form-control';
import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, Gender, ShippingAddressDTO } from '@generated/swagger/crm-api';
import { map, switchMap, takeUntil } from 'rxjs/operators';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { AddressSelectionModalService } from '@modal/address-selection';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation';
@@ -39,13 +39,11 @@ export interface EditShippingAddressMainViewState {
IconComponent,
RouterLink,
AsyncPipe,
NgIf,
NgForOf,
ReactiveFormsModule,
SelectModule,
FormControlComponent,
CheckboxComponent,
],
CheckboxComponent
],
})
export class EditShippingAddressMainViewComponent
extends ComponentStore<EditShippingAddressMainViewState>

View File

@@ -1,46 +1,48 @@
<ng-container *ngIf="fetchingFilterSettings$ | async; else filterTemplate"></ng-container>
<ng-template #filterTemplate>
<div *ngIf="filter$ | async; let filter">
<div class="customer-filter-header">
<div class="customer-filter-header-actions flex flex-row justify-end pt-1 px-1">
<button (click)="clearFilter(filter)" class="text-[#0556B4] mr-2 h-12">Alle Filter entfernen</button>
<button (click)="close()" class="btn btn-label" *ngIf="!isOnMainRoute">
<ui-icon [icon]="'close'"></ui-icon>
@if (fetchingFilterSettings$ | async) {
} @else {
@if (filter$ | async; as filter) {
<div>
<div class="customer-filter-header">
<div class="customer-filter-header-actions flex flex-row justify-end pt-1 px-1">
<button (click)="clearFilter(filter)" class="text-[#0556B4] mr-2 h-12">Alle Filter entfernen</button>
@if (!isOnMainRoute) {
<button (click)="close()" class="btn btn-label">
<ui-icon [icon]="'close'"></ui-icon>
</button>
}
</div>
<div class="customer-filter-header-body text-center -mt-3">
<h1 class="text-[1.625rem] font-bold">Filter</h1>
</div>
</div>
<div class="px-3 bg-surface text-surface-content">
<shared-filter
[filter]="filter"
[loading]="fetching$ | async"
(search)="search(filter)"
[hint]="message$ | async"
[scanner]="true"
></shared-filter>
</div>
<div class="grid grid-flow-col gap-6 items-center justify-center mt-6">
<button
type="button"
(click)="reset()"
class="bg-white border-2 border-solid border-brand text-brand text-xl font-bold rounded-full px-6 py-3 disabled:border-components-button-disabled-content disabled:text-components-button-disabled-content"
[disabled]="fetching$ | async"
>
<shared-loader [loading]="fetching$ | async">Filter zurücksetzen</shared-loader>
</button>
<button
type="button"
(click)="search(filter)"
class="bg-brand border-2 border-solid border-brand text-white text-xl font-bold rounded-full px-6 py-3 disabled:bg-components-button-disabled-content disabled:border-components-button-disabled-content"
[disabled]="(fetching$ | async) || !hasSelectedOptions(filter)"
>
<shared-loader [loading]="fetching$ | async">Filter anwenden</shared-loader>
</button>
</div>
<div class="customer-filter-header-body text-center -mt-3">
<h1 class="text-[1.625rem] font-bold">Filter</h1>
</div>
</div>
<div class="px-3 bg-surface text-surface-content">
<shared-filter
[filter]="filter"
[loading]="fetching$ | async"
(search)="search(filter)"
[hint]="message$ | async"
[scanner]="true"
></shared-filter>
</div>
}
}
<div class="grid grid-flow-col gap-6 items-center justify-center mt-6">
<button
type="button"
(click)="reset()"
class="bg-white border-2 border-solid border-brand text-brand text-xl font-bold rounded-full px-6 py-3 disabled:border-components-button-disabled-content disabled:text-components-button-disabled-content"
[disabled]="fetching$ | async"
>
<shared-loader [loading]="fetching$ | async">Filter zurücksetzen</shared-loader>
</button>
<button
type="button"
(click)="search(filter)"
class="bg-brand border-2 border-solid border-brand text-white text-xl font-bold rounded-full px-6 py-3 disabled:bg-components-button-disabled-content disabled:border-components-button-disabled-content"
[disabled]="(fetching$ | async) || !hasSelectedOptions(filter)"
>
<shared-loader [loading]="fetching$ | async">Filter anwenden</shared-loader>
</button>
</div>
</div>
</ng-template>

View File

@@ -2,24 +2,32 @@
<page-customer-menu [customerId]="customerId$ | async" [processId]="processId$ | async" [showCustomerCard]="false"></page-customer-menu>
</div>
<h1 class="text-center text-2xl font-bold">Kundenkarte</h1>
<p class="text-center text-xl" *ngIf="!(noDataFound$ | async)">
Alle Infos zu Ihrer Kundenkarte
<br />
und allen Partnerkarten.
</p>
<p class="text-center text-xl" *ngIf="noDataFound$ | async">Keine Kundenkarte gefunden.</p>
<page-customer-kundenkarte
class="justify-self-center"
*ngFor="let karte of primaryKundenkarte$ | async"
[cardDetails]="karte"
[isCustomerCard]="true"
></page-customer-kundenkarte>
@if (!(noDataFound$ | async)) {
<p class="text-center text-xl">
Alle Infos zu Ihrer Kundenkarte
<br />
und allen Partnerkarten.
</p>
}
@if (noDataFound$ | async) {
<p class="text-center text-xl">Keine Kundenkarte gefunden.</p>
}
@for (karte of primaryKundenkarte$ | async; track karte) {
<page-customer-kundenkarte
class="justify-self-center"
[cardDetails]="karte"
[isCustomerCard]="true"
></page-customer-kundenkarte>
}
<p class="text-center text-xl font-bold" *ngIf="(partnerKundenkarte$ | async)?.length">Partnerkarten</p>
@if ((partnerKundenkarte$ | async)?.length) {
<p class="text-center text-xl font-bold">Partnerkarten</p>
}
<page-customer-kundenkarte
class="justify-self-center"
*ngFor="let karte of partnerKundenkarte$ | async"
[cardDetails]="karte"
[isCustomerCard]="false"
></page-customer-kundenkarte>
@for (karte of partnerKundenkarte$ | async; track karte) {
<page-customer-kundenkarte
class="justify-self-center"
[cardDetails]="karte"
[isCustomerCard]="false"
></page-customer-kundenkarte>
}

View File

@@ -5,7 +5,7 @@ import { Subject, combineLatest, of } from 'rxjs';
import { catchError, map, share, switchMap } from 'rxjs/operators';
import { CrmCustomerService } from '@domain/crm';
import { KundenkarteComponent } from '../../components/kundenkarte';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { IconComponent } from '@shared/components/icon';
import { CustomerSearchNavigation } from '@shared/services/navigation';
import { BonusCardInfoDTO } from '@generated/swagger/crm-api';
@@ -17,7 +17,7 @@ import { CustomerMenuComponent } from '../../components/customer-menu';
styleUrls: ['kundenkarte-main-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-customer-kundenkarte-main-view' },
imports: [CustomerMenuComponent, KundenkarteComponent, NgFor, AsyncPipe, NgIf, IconComponent, RouterLink],
imports: [CustomerMenuComponent, KundenkarteComponent, AsyncPipe, IconComponent, RouterLink],
})
export class KundenkarteMainViewComponent implements OnInit, OnDestroy {
private _store = inject(CustomerSearchStore);

View File

@@ -1,17 +1,20 @@
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
<p class="text-lg mt-2 mb-6">Haben Sie ein Konto bei uns?</p>
<shared-filter-input-group-main
*ngIf="filter$ | async; let filter"
[inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)"
[loading]="fetching$ | async"
[hint]="message$ | async"
></shared-filter-input-group-main>
@if (filter$ | async; as filter) {
<shared-filter-input-group-main
[inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)"
[loading]="fetching$ | async"
[hint]="message$ | async"
></shared-filter-input-group-main>
}
<p class="mt-6">
Kunde nicht gefunden?
<a class="text-brand" *ngIf="createRoute$ | async; let route" [routerLink]="route.path" [queryParams]="route.queryParams">
Neue Kundendaten erfassen
</a>
@if (createRoute$ | async; as route) {
<a class="text-brand" [routerLink]="route.path" [queryParams]="route.queryParams">
Neue Kundendaten erfassen
</a>
}
</p>
</div>

View File

@@ -1,4 +1,4 @@
import { AsyncPipe, CommonModule, NgIf } from '@angular/common';
import { AsyncPipe, CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { RouterModule } from '@angular/router';
import { Filter, FilterModule } from '@shared/components/filter';
@@ -13,7 +13,7 @@ import { CustomerInfoDTO } from '@generated/swagger/crm-api';
templateUrl: 'main-side-view.component.html',
styleUrls: ['main-side-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, RouterModule, FilterModule, AsyncPipe, NgIf],
imports: [CommonModule, RouterModule, FilterModule, AsyncPipe],
})
export class MainSideViewComponent {
private _store = inject(CustomerSearchStore);

View File

@@ -3,32 +3,36 @@
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
<p class="text-lg mt-2 mb-6">Haben Sie ein Konto bei uns?</p>
<div class="grid grid-cols-[1fr_auto] items-center gap-2">
<shared-filter-input-group-main
class="grow"
*ngIf="filter$ | async; let filter"
[inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)"
[loading]="fetching$ | async"
[hint]="message$ | async"
[scanner]="true"
></shared-filter-input-group-main>
<a
*ngIf="filterRoute$ | async; let filterRoute"
class="filter-btn h-14 px-4 rounded font-bold text-xl grid grid-flow-col items-center gap-2"
[routerLink]="filterRoute.path"
[queryParams]="filterRoute.queryParams"
[queryParamsHandling]="'merge'"
[class.active]="hasFilter$ | async"
>
<shared-icon icon="filter-variant"></shared-icon>
<span>Filter</span>
</a>
@if (filter$ | async; as filter) {
<shared-filter-input-group-main
class="grow"
[inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)"
[loading]="fetching$ | async"
[hint]="message$ | async"
[scanner]="true"
></shared-filter-input-group-main>
}
@if (filterRoute$ | async; as filterRoute) {
<a
class="filter-btn h-14 px-4 rounded font-bold text-xl grid grid-flow-col items-center gap-2"
[routerLink]="filterRoute.path"
[queryParams]="filterRoute.queryParams"
[queryParamsHandling]="'merge'"
[class.active]="hasFilter$ | async"
>
<shared-icon icon="filter-variant"></shared-icon>
<span>Filter</span>
</a>
}
</div>
<p class="mt-6">
Kunde nicht gefunden?
<a class="text-brand" *ngIf="createRoute$ | async; let route" [routerLink]="route.path" [queryParams]="route.queryParams">
Neue Kundendaten erfassen
</a>
@if (createRoute$ | async; as route) {
<a class="text-brand" [routerLink]="route.path" [queryParams]="route.queryParams">
Neue Kundendaten erfassen
</a>
}
</p>
</div>
</div>

View File

@@ -2,7 +2,7 @@ import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { CustomerSearchStore } from '../store';
import { Filter, FilterModule } from '@shared/components/filter';
import { map } from 'rxjs/operators';
import { AsyncPipe, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { Router, RouterLink } from '@angular/router';
import { IconComponent } from '@shared/components/icon';
import { combineLatest } from 'rxjs';
@@ -17,7 +17,7 @@ import { CustomerInfoDTO } from '@generated/swagger/crm-api';
styleUrls: ['main-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-customer-main-view' },
imports: [AsyncPipe, RouterLink, FilterModule, NgIf, IconComponent, CustomerFilterMainViewModule],
imports: [AsyncPipe, RouterLink, FilterModule, IconComponent, CustomerFilterMainViewModule],
})
export class CustomerMainViewComponent {
private _searchNavigation = inject(CustomerSearchNavigation);

View File

@@ -1,12 +1,13 @@
<ng-container *ngIf="fetching$ | async; else historyTemplate"></ng-container>
<ng-template #historyTemplate>
@if (fetching$ | async) {
} @else {
<div>
<div class="customer-history-header">
<div class="customer-history-header-actions flex flex-row justify-end pt-1 px-1">
<a *ngIf="detailsRoute$ | async; let route" [routerLink]="route.path" [queryParams]="route.queryParams" class="btn btn-label">
<shared-icon [icon]="'close'" [size]="32"></shared-icon>
</a>
@if (detailsRoute$ | async; as route) {
<a [routerLink]="route.path" [queryParams]="route.queryParams" class="btn btn-label">
<shared-icon [icon]="'close'" [size]="32"></shared-icon>
</a>
}
</div>
<div class="customer-history-header-body text-center -mt-3">
<h1 class="text-[1.625rem] font-bold">Historie</h1>
@@ -26,4 +27,5 @@
<shared-history-list [history]="history$ | async"></shared-history-list>
</div>
</div>
</ng-template>
}

View File

@@ -7,7 +7,7 @@ import { Observable, Subject, combineLatest } from 'rxjs';
import { map, switchMap, takeUntil, tap } from 'rxjs/operators';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation';
import { AsyncPipe, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { IconModule } from '@shared/components/icon';
import { SharedHistoryListModule } from '@shared/components/history';
import { ActivatedRoute, RouterLink } from '@angular/router';
@@ -23,7 +23,7 @@ export interface CustomerHistoryViewMainState {
templateUrl: 'order-details-history-main-view.component.html',
styleUrls: ['order-details-history-main-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [AsyncPipe, RouterLink, NgIf, IconModule, SharedHistoryListModule],
imports: [AsyncPipe, RouterLink, IconModule, SharedHistoryListModule],
})
export class CustomerOrderDetailsHistoryMainViewComponent
extends ComponentStore<CustomerHistoryViewMainState>

View File

@@ -5,15 +5,16 @@
<div class="grid grid-flow-row gap-2">
<div class="grid grid-flow-col justify-between items-end">
<span>{{ orderItem.product?.contributors }}</span>
<a
*ngIf="orderDetailsHistoryRoute$ | async; let orderDetailsHistoryRoute"
[routerLink]="orderDetailsHistoryRoute.path"
[queryParams]="orderDetailsHistoryRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
class="text-brand font-bold text-xl"
>
Historie
</a>
@if (orderDetailsHistoryRoute$ | async; as orderDetailsHistoryRoute) {
<a
[routerLink]="orderDetailsHistoryRoute.path"
[queryParams]="orderDetailsHistoryRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'"
class="text-brand font-bold text-xl"
>
Historie
</a>
}
</div>
<div class="font-bold text-lg">
{{ orderItem?.product?.name }}
@@ -23,82 +24,90 @@
{{ processingStatus$ | async | orderItemProcessingStatus }}
</span>
</div>
<div class="grid grid-flow-row gap-2" *ngIf="orderItemSubsetItem$ | async; let orderItemSubsetItem">
<div class="col-data">
<div class="col-label">Menge</div>
<div class="col-value">{{ orderItem?.quantity?.quantity }}x</div>
</div>
<div class="col-data">
<div class="col-label">Format</div>
<div class="col-value grid-flow-col grid gap-3 items-center justify-start">
<shared-icon [icon]="orderItem?.product?.format"></shared-icon>
<span>{{ orderItem?.product?.formatDetail }}</span>
@if (orderItemSubsetItem$ | async; as orderItemSubsetItem) {
<div class="grid grid-flow-row gap-2">
<div class="col-data">
<div class="col-label">Menge</div>
<div class="col-value">{{ orderItem?.quantity?.quantity }}x</div>
</div>
<div class="col-data">
<div class="col-label">Format</div>
<div class="col-value grid-flow-col grid gap-3 items-center justify-start">
<shared-icon [icon]="orderItem?.product?.format"></shared-icon>
<span>{{ orderItem?.product?.formatDetail }}</span>
</div>
</div>
<div class="col-data">
<div class="col-label">ISBN/EAN</div>
<div class="col-value">{{ orderItem?.product?.ean }}</div>
</div>
<div class="col-data">
<div class="col-label">Preis</div>
<div class="col-value">{{ orderItem?.unitPrice?.value?.value | currency: orderItem?.unitPrice?.value?.currency : 'code' }}</div>
</div>
<div class="col-data">
<div class="col-label">MwSt</div>
<div class="col-value">{{ orderItem?.unitPrice?.vat?.inPercent }}%</div>
</div>
<hr />
<div class="col-data">
<div class="col-label">Lieferant</div>
<div class="col-value">
{{ orderItemSubsetItem?.supplier?.data?.name }}
</div>
</div>
<div class="col-data">
<div class="col-label">Meldenummer</div>
<div class="col-value">{{ orderItemSubsetItem?.ssc }} - {{ orderItemSubsetItem?.sscText }}</div>
</div>
<div class="col-data">
<div class="col-label">Vsl. Lieferdatum</div>
<div class="col-value">
{{ orderItemSubsetItem?.estimatedShippingDate | date: 'dd.MM.yyyy' }}
</div>
</div>
@if (orderItemSubsetItem?.preferredPickUpDate) {
<div class="col-data">
<div class="col-label">Zurücklegen bis</div>
<div class="col-value">
{{ orderItemSubsetItem?.preferredPickUpDate | date: 'dd.MM.yyyy' }}
</div>
</div>
}
<hr />
@if (orderItemSubsetItem?.compartmentCode) {
<div class="col-data">
<div class="col-label">Abholfachnummer</div>
<div class="col-value">
<span>{{ orderItemSubsetItem?.compartmentCode }}</span>
@if (orderItemSubsetItem?.compartmentInfo) {
<span>_{{ orderItemSubsetItem?.compartmentInfo }}</span>
}
</div>
</div>
}
<div class="col-data">
<div class="col-label">Vormerker</div>
<div class="col-value">{{ isPrebooked$ | async }}</div>
</div>
<hr />
<div class="col-data">
<div class="col-label">Zahlungsweg</div>
<div class="col-value">-</div>
</div>
<div class="col-data">
<div class="col-label">Zahlungsart</div>
<div class="col-value">
{{ orderPaymentType$ | async | paymentType }}
</div>
</div>
<div class="col-data">
<div class="col-label">Anmerkung</div>
<div class="col-value">
{{ orderItemSubsetItem?.specialComment || '-' }}
</div>
</div>
</div>
<div class="col-data">
<div class="col-label">ISBN/EAN</div>
<div class="col-value">{{ orderItem?.product?.ean }}</div>
</div>
<div class="col-data">
<div class="col-label">Preis</div>
<div class="col-value">{{ orderItem?.unitPrice?.value?.value | currency: orderItem?.unitPrice?.value?.currency : 'code' }}</div>
</div>
<div class="col-data">
<div class="col-label">MwSt</div>
<div class="col-value">{{ orderItem?.unitPrice?.vat?.inPercent }}%</div>
</div>
<hr />
<div class="col-data">
<div class="col-label">Lieferant</div>
<div class="col-value">
{{ orderItemSubsetItem?.supplier?.data?.name }}
</div>
</div>
<div class="col-data">
<div class="col-label">Meldenummer</div>
<div class="col-value">{{ orderItemSubsetItem?.ssc }} - {{ orderItemSubsetItem?.sscText }}</div>
</div>
<div class="col-data">
<div class="col-label">Vsl. Lieferdatum</div>
<div class="col-value">
{{ orderItemSubsetItem?.estimatedShippingDate | date: 'dd.MM.yyyy' }}
</div>
</div>
<div class="col-data" *ngIf="orderItemSubsetItem?.preferredPickUpDate">
<div class="col-label">Zurücklegen bis</div>
<div class="col-value">
{{ orderItemSubsetItem?.preferredPickUpDate | date: 'dd.MM.yyyy' }}
</div>
</div>
<hr />
<div class="col-data" *ngIf="orderItemSubsetItem?.compartmentCode">
<div class="col-label">Abholfachnummer</div>
<div class="col-value">
<span>{{ orderItemSubsetItem?.compartmentCode }}</span>
<span *ngIf="orderItemSubsetItem?.compartmentInfo">_{{ orderItemSubsetItem?.compartmentInfo }}</span>
</div>
</div>
<div class="col-data">
<div class="col-label">Vormerker</div>
<div class="col-value">{{ isPrebooked$ | async }}</div>
</div>
<hr />
<div class="col-data">
<div class="col-label">Zahlungsweg</div>
<div class="col-value">-</div>
</div>
<div class="col-data">
<div class="col-label">Zahlungsart</div>
<div class="col-value">
{{ orderPaymentType$ | async | paymentType }}
</div>
</div>
<div class="col-data">
<div class="col-label">Anmerkung</div>
<div class="col-value">
{{ orderItemSubsetItem?.specialComment || '-' }}
</div>
</div>
</div>
}
</div>
</div>

View File

@@ -1,4 +1,4 @@
import { AsyncPipe, CurrencyPipe, DatePipe, NgIf } from '@angular/common';
import { AsyncPipe, CurrencyPipe, DatePipe } from '@angular/common';
import { Component, ChangeDetectionStrategy, Input, OnDestroy, OnInit, inject } from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { ProductImagePipe } from '@cdn/product-image';
@@ -19,7 +19,6 @@ import { PaymentTypePipe } from '@shared/pipes/customer';
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-customer-order-item-list-item' },
imports: [
NgIf,
AsyncPipe,
DatePipe,
OrderProcessingStatusPipe,
@@ -30,8 +29,8 @@ import { PaymentTypePipe } from '@shared/pipes/customer';
IconComponent,
RouterLink,
PaymentTypePipe,
OrderItemProcessingStatusPipe,
],
OrderItemProcessingStatusPipe
],
})
export class CustomerOrderItemListItemComponent implements OnInit, OnDestroy {
private _activatedRoute = inject(ActivatedRoute);

View File

@@ -2,23 +2,25 @@
{{ customer$ | async | customerName }}
</div>
<div class="bg-surface-2 text-surface-2-content p-4 text-right">{{ (orderItems$ | async)?.length }} Artikel</div>
<div class="grid grid-flow-row gap-1" *ngIf="selectedOrderItemId$ | async; let selectedOrderItemId">
<ng-container *ngFor="let orderItem of orderItems$ | async">
<div
[class.order-item-active]="selectedOrderItemId === orderItem?.id"
class="grid grid-cols-[auto_1fr] gap-4 p-4 border border-solid bg-surface text-surface-content rounded first:rounded-t-none"
(click)="selectOrderItem(orderItem?.id)"
>
<div>
<img [src]="orderItem?.product?.ean | productImage" [alt]="orderItem?.product?.name" class="rounded shadow mx-auto w-[3.75rem]" />
@if (selectedOrderItemId$ | async; as selectedOrderItemId) {
<div class="grid grid-flow-row gap-1">
@for (orderItem of orderItems$ | async; track orderItem) {
<div
[class.order-item-active]="selectedOrderItemId === orderItem?.id"
class="grid grid-cols-[auto_1fr] gap-4 p-4 border border-solid bg-surface text-surface-content rounded first:rounded-t-none"
(click)="selectOrderItem(orderItem?.id)"
>
<div>
<img [src]="orderItem?.product?.ean | productImage" [alt]="orderItem?.product?.name" class="rounded shadow mx-auto w-[3.75rem]" />
</div>
<div class="grid grid-flow-row gap-1">
<span>{{ orderItem?.product?.contributors }}</span>
<span class="font-bold truncate whitespace-nowrap">{{ orderItem?.product?.name }}</span>
<span>
<span class="isa-label">{{ orderItem?.subsetItems?.[0].data?.processingStatus | orderItemProcessingStatus }}</span>
</span>
</div>
</div>
<div class="grid grid-flow-row gap-1">
<span>{{ orderItem?.product?.contributors }}</span>
<span class="font-bold truncate whitespace-nowrap">{{ orderItem?.product?.name }}</span>
<span>
<span class="isa-label">{{ orderItem?.subsetItems?.[0].data?.processingStatus | orderItemProcessingStatus }}</span>
</span>
</div>
</div>
</ng-container>
</div>
}
</div>
}

View File

@@ -2,7 +2,7 @@ import { Component, ChangeDetectionStrategy } from '@angular/core';
import { CustomerSearchStore } from '../store';
import { map } from 'rxjs/operators';
import { CustomerNamePipe } from '@shared/pipes/customer';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { ProductImagePipe } from '@cdn/product-image';
import { CustomerSearchNavigation } from '@shared/services/navigation';
import { RouterLink, RouterLinkActive } from '@angular/router';
@@ -17,13 +17,11 @@ import { OrderItemProcessingStatusPipe } from '@shared/pipes/order';
imports: [
CustomerNamePipe,
AsyncPipe,
NgFor,
ProductImagePipe,
RouterLink,
NgIf,
RouterLinkActive,
OrderItemProcessingStatusPipe,
],
OrderItemProcessingStatusPipe
],
})
export class OrderDetailsSideViewComponent {
customer$ = this._store.customer$;

Some files were not shown because too many files have changed in this diff Show More