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 1 Firefox version
last 2 Edge major versions last 2 Edge major versions
last 2 iOS 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 { import {
Component, Component,
effect, effect,
@@ -10,6 +10,7 @@ import {
Renderer2, Renderer2,
signal, signal,
untracked, untracked,
DOCUMENT
} from '@angular/core'; } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { SwUpdate } from '@angular/service-worker'; import { SwUpdate } from '@angular/service-worker';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
<div class="notification-list scroll-bar"> <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> <modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
<hr /> <hr />
</ng-container> }
</div> </div>
<div class="actions"> <div class="actions">

View File

@@ -1,8 +1,8 @@
<div class="notification-list scroll-bar"> <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> <modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
<hr /> <hr />
</ng-container> }
</div> </div>
<div class="actions"> <div class="actions">

View File

@@ -1,8 +1,8 @@
<div class="notification-list scroll-bar"> <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> <modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
<hr /> <hr />
</ng-container> }
</div> </div>
<div class="actions"> <div class="actions">

View File

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

View File

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

View File

@@ -2,13 +2,17 @@
<div class="header"> <div class="header">
<h1>Wählen Sie einen Drucker aus</h1> <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>
<div class="body"> <div class="body">
<ui-spinner [show]="!loaded"> <ui-spinner [show]="!loaded">
<ui-select class="select" [(ngModel)]="selectedPrinterKey"> <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-select>
</ui-spinner> </ui-spinner>
</div> </div>

View File

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

View File

@@ -15,147 +15,171 @@
</div> </div>
<div class="shared-purchase-options-list-item__manufacturer-and-ean"> <div class="shared-purchase-options-list-item__manufacturer-and-ean">
{{ product?.manufacturer }} {{ product?.manufacturer }}
<span *ngIf="product?.manufacturer && product?.ean">|</span> @if (product?.manufacturer && product?.ean) {
<span>|</span>
}
{{ product?.ean }} {{ product?.ean }}
</div> </div>
<div class="shared-purchase-options-list-item__volume-and-publication-date"> <div class="shared-purchase-options-list-item__volume-and-publication-date">
{{ product?.volume }} {{ product?.volume }}
<span *ngIf="product?.volume && product?.publicationDate">|</span> @if (product?.volume && product?.publicationDate) {
<span>|</span>
}
{{ product?.publicationDate | date: 'dd. MMMM yyyy' }} {{ product?.publicationDate | date: 'dd. MMMM yyyy' }}
</div> </div>
<div class="shared-purchase-options-list-item__availabilities mt-3 grid grid-flow-row gap-2 justify-start"> <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> @if ((availabilities$ | async)?.length) {
<div *ngFor="let availability of availabilities$ | async" class="grid grid-flow-col gap-4 justify-start"> <div class="whitespace-nowrap self-center">Verfügbar als</div>
<div }
[ngSwitch]="availability.purchaseOption" @for (availability of availabilities$ | async; track availability) {
class="shared-purchase-options-list-item__availability grid grid-flow-col gap-2 items-center" <div class="grid grid-flow-col gap-4 justify-start">
[attr.data-option]="availability.purchaseOption" <div
> class="shared-purchase-options-list-item__availability grid grid-flow-col gap-2 items-center"
<ng-container *ngSwitchCase="'delivery'"> [attr.data-option]="availability.purchaseOption"
<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"
> >
<b>{{ availability.data?.orderDeadline | orderDeadline }}</b> @switch (availability.purchaseOption) {
</ui-tooltip> @case ('delivery') {
</ng-container> <shared-icon icon="isa-truck" [size]="22"></shared-icon>
<ng-container *ngSwitchCase="'in-store'"> {{ availability.data.estimatedDelivery?.start | date: 'EE dd.MM.' }}
<shared-icon icon="isa-shopping-bag" [size]="18"></shared-icon> -
{{ availability.data.inStock }}x {{ availability.data.estimatedDelivery?.stop | date: 'EE dd.MM.' }}
<ng-container *ngIf="isEVT; else noEVT">ab {{ isEVT | date: 'dd. MMMM yyyy' }}</ng-container> }
<ng-template #noEVT>ab sofort</ng-template> @case ('dig-delivery') {
</ng-container> <shared-icon icon="isa-truck" [size]="22"></shared-icon>
<ng-container *ngSwitchCase="'download'"> {{ availability.data.estimatedDelivery?.start | date: 'EE dd.MM.' }}
<shared-icon icon="isa-download" [size]="22"></shared-icon> -
Download {{ availability.data.estimatedDelivery?.stop | date: 'EE dd.MM.' }}
</ng-container> }
@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>
</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 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="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"> <div class="relative flex flex-row justify-end items-start">
<ui-select @if (canEditVat$ | async) {
*ngIf="canEditVat$ | async" <ui-select
class="w-[6.5rem] min-h-[3.4375rem] p-4 rounded-card border border-solid border-[#AEB7C1] mr-4" class="w-[6.5rem] min-h-[3.4375rem] p-4 rounded-card border border-solid border-[#AEB7C1] mr-4"
tabindex="-1" tabindex="-1"
[formControl]="manualVatFormControl" [formControl]="manualVatFormControl"
[defaultLabel]="'MwSt'" [defaultLabel]="'MwSt'"
> >
<ui-select-option *ngFor="let vat of vats$ | async" [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option> @for (vat of vats$ | async; track vat) {
</ui-select> <ui-select-option [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
<shared-input-control }
[class.ml-6]="priceFormControl?.invalid && priceFormControl?.dirty" </ui-select>
*ngIf="canEditPrice$ | async; else priceTmpl" }
> @if (canEditPrice$ | async) {
<shared-input-control-indicator> <shared-input-control
<shared-icon *ngIf="priceFormControl?.invalid && priceFormControl?.dirty" icon="mat-info"></shared-icon> [class.ml-6]="priceFormControl?.invalid && priceFormControl?.dirty"
</shared-input-control-indicator> >
<input <shared-input-control-indicator>
[uiOverlayTrigger]="giftCardTooltip" @if (priceFormControl?.invalid && priceFormControl?.dirty) {
triggerOn="none" <shared-icon icon="mat-info"></shared-icon>
#quantityInput }
#priceOverlayTrigger="uiOverlayTrigger" </shared-input-control-indicator>
sharedInputControlInput <input
type="string" [uiOverlayTrigger]="giftCardTooltip"
class="w-24" triggerOn="none"
[formControl]="priceFormControl" #quantityInput
placeholder="00,00" #priceOverlayTrigger="uiOverlayTrigger"
(sharedOnInit)="onPriceInputInit(quantityInput, priceOverlayTrigger)" sharedInputControlInput
sharedNumberValue type="string"
/> class="w-24"
<shared-input-control-suffix>EUR</shared-input-control-suffix> [formControl]="priceFormControl"
<shared-input-control-error error="required">Preis ist ungültig</shared-input-control-error> placeholder="00,00"
<shared-input-control-error error="pattern">Preis ist ungültig</shared-input-control-error> (sharedOnInit)="onPriceInputInit(quantityInput, priceOverlayTrigger)"
<shared-input-control-error error="min">Preis ist ungültig</shared-input-control-error> sharedNumberValue
<shared-input-control-error error="max">Preis ist ungültig</shared-input-control-error> />
</shared-input-control> <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> <ui-tooltip [warning]="true" xPosition="after" yPosition="below" [xOffset]="-55" [yOffset]="18" [closeable]="true" #giftCardTooltip>
Tragen Sie hier den Tragen Sie hier den
<br /> <br />
Gutscheinbetrag ein. Gutscheinbetrag ein.
</ui-tooltip> </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> </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"> @if (canAddResult$ | async; as canAddResult) {
<span *ngIf="!canAddResult.canAdd" class="inline-block font-bold text-[#BE8100] mt-[14px] max-w-[19rem]"> @if (!canAddResult.canAdd) {
{{ canAddResult.message }} <span class="inline-block font-bold text-[#BE8100] mt-[14px] max-w-[19rem]">
</span> {{ canAddResult.message }}
</ng-container> </span>
}
}
<span *ngIf="showMaxAvailableQuantity$ | async" class="font-bold text-[#BE8100] mt-[14px]"> @if (showMaxAvailableQuantity$ | async) {
{{ (availability$ | async)?.inStock }} Exemplare sofort lieferbar <span class="font-bold text-[#BE8100] mt-[14px]">
</span> {{ (availability$ | async)?.inStock }} Exemplare sofort lieferbar
<span *ngIf="showNotAvailable$ | async" class="font-bold text-[#BE8100] mt-[14px]">Derzeit nicht bestellbar</span> </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>
<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> <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> <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"> <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)"> @if (!(isDownloadOnly$ | async)) {
<ng-container *ngIf="!(isGiftCardOnly$ | async)"> @if (!(isGiftCardOnly$ | async)) {
<app-in-store-purchase-options-tile *ngIf="showOption('in-store')"></app-in-store-purchase-options-tile> @if (showOption('in-store')) {
<app-pickup-purchase-options-tile *ngIf="showOption('pickup')"></app-pickup-purchase-options-tile> <app-in-store-purchase-options-tile></app-in-store-purchase-options-tile>
</ng-container> }
<app-delivery-purchase-options-tile *ngIf="showOption('delivery')"></app-delivery-purchase-options-tile> @if (showOption('pickup')) {
</ng-container> <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"> @if (hasDownload$ | async) {
<app-download-purchase-options-tile *ngIf="showOption('download')"></app-download-purchase-options-tile> @if (showOption('download')) {
</ng-container> <app-download-purchase-options-tile></app-download-purchase-options-tile>
}
}
</div> </div>
<shared-purchase-options-list-header></shared-purchase-options-list-header> <shared-purchase-options-list-header></shared-purchase-options-list-header>
<div class="shared-purchase-options-modal__items -mx-4"> <div class="shared-purchase-options-modal__items -mx-4">
<shared-purchase-options-list-item @for (item of items$ | async; track itemTrackBy($index, item)) {
class="border-t border-gray-200 p-4 border-solid" <shared-purchase-options-list-item
*ngFor="let item of items$ | async; trackBy: itemTrackBy" class="border-t border-gray-200 p-4 border-solid"
[item]="item" [item]="item"
></shared-purchase-options-list-item> ></shared-purchase-options-list-item>
}
</div> </div>
<div class="text-center -mx-4 border-t border-gray-200 p-4 border-solid"> <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')"> <button type="button" class="isa-cta-button" [disabled]="!(canContinue$ | async) || saving" (click)="save('continue-shopping')">
Weiter einkaufen Weiter einkaufen
</button> </button>
@@ -31,18 +40,18 @@
class="ml-4 isa-cta-button isa-button-primary" class="ml-4 isa-cta-button isa-button-primary"
[disabled]="!(canContinue$ | async) || saving" [disabled]="!(canContinue$ | async) || saving"
(click)="save('continue')" (click)="save('continue')"
> >
Fortfahren Fortfahren
</button> </button>
</ng-container> }
<ng-container *ngIf="type === 'update'"> @if (type === 'update') {
<button <button
type="button" type="button"
class="ml-4 isa-cta-button isa-button-primary" class="ml-4 isa-cta-button isa-button-primary"
[disabled]="!(canContinue$ | async) || saving" [disabled]="!(canContinue$ | async) || saving"
(click)="save('continue')" (click)="save('continue')"
> >
Fortfahren Fortfahren
</button> </button>
</ng-container> }
</div> </div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,17 +5,20 @@
id="asortment-filter-button" 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" 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" type="button"
> >
<shared-icon class="mr-2" icon="filter-variant"></shared-icon> <shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter Filter
</button> </button>
</div> </div>
<page-price-update-list @if (showList$ | async) {
*ngIf="showList$ | async; else noResults" <page-price-update-list
[items]="store.items$ | async" [items]="store.items$ | async"
[fetching]="store.fetching$ | async" [fetching]="store.fetching$ | async"
></page-price-update-list> ></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"> <shell-filter-overlay #filterOverlay class="relative">
<div class="relative"> <div class="relative">
@@ -26,22 +29,23 @@
<h3 class="text-3xl text-center font-bold mt-8">Filter</h3> <h3 class="text-3xl text-center font-bold mt-8">Filter</h3>
<ui-filter @if (filterOverlay.isOpen) {
*ngIf="filterOverlay.isOpen" <ui-filter
#filter #filter
class="mx-4" class="mx-4"
[filter]="store.pendingFilter$ | async" [filter]="store.pendingFilter$ | async"
(search)="applyFilter()" (search)="applyFilter()"
[loading]="store.fetching$ | async" [loading]="store.fetching$ | async"
[hint]="hint$ | async" [hint]="hint$ | async"
></ui-filter> ></ui-filter>
}
<div class="absolute bottom-8 left-0 right-0 grid grid-flow-col gap-4 justify-center"> <div class="absolute bottom-8 left-0 right-0 grid grid-flow-col gap-4 justify-center">
<button <button
type="button" type="button"
class="px-6 py-4 font-bold bg-white text-brand border-2 border-solid border-brand rounded-full" class="px-6 py-4 font-bold bg-white text-brand border-2 border-solid border-brand rounded-full"
(click)="store.resetPendingFilter()" (click)="store.resetPendingFilter()"
> >
Filter zurücksetzen Filter zurücksetzen
</button> </button>
<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" 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()" (click)="applyFilter()"
[disabled]="store.fetching$ | async" [disabled]="store.fetching$ | async"
> >
<ui-spinner [show]="store.fetching$ | async">Filter anwenden</ui-spinner> <ui-spinner [show]="store.fetching$ | async">Filter anwenden</ui-spinner>
</button> </button>
</div> </div>
</shell-filter-overlay> </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"> @for (line of lines; track line) {
<ng-container [ngSwitch]="line | lineType"> @switch (line | lineType) {
<ng-container *ngSwitchCase="'reihe'"> @case ('reihe') {
<page-article-details-text-link *ngFor="let reihe of getReihen(line)" [route]="reihe | reiheRoute"> @for (reihe of getReihen(line); track reihe) {
{{ reihe }} <page-article-details-text-link [route]="reihe | reiheRoute">
</page-article-details-text-link> {{ reihe }}
</page-article-details-text-link>
}
<br /> <br />
</ng-container> }
<ng-container *ngSwitchDefault> @default {
{{ line }} {{ line }}
<br /> <br />
</ng-container> }
</ng-container> }
</ng-container> }

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, Input } from '@angular/core'; import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { TextDTO } from '@generated/swagger/cat-search-api'; import { TextDTO } from '@generated/swagger/cat-search-api';
import { ArticleDetailsTextLinkComponent } from './article-details-text-link.component'; import { ArticleDetailsTextLinkComponent } from './article-details-text-link.component';
import { NgFor, NgSwitch, NgSwitchCase, NgSwitchDefault } from '@angular/common';
import { LineTypePipe } from './line-type.pipe'; import { LineTypePipe } from './line-type.pipe';
import { ReiheRoutePipe } from './reihe-route.pipe'; import { ReiheRoutePipe } from './reihe-route.pipe';
@@ -13,13 +13,9 @@ import { ReiheRoutePipe } from './reihe-route.pipe';
host: { class: 'page-article-details-text' }, host: { class: 'page-article-details-text' },
imports: [ imports: [
ArticleDetailsTextLinkComponent, ArticleDetailsTextLinkComponent,
NgFor,
NgSwitch,
NgSwitchCase,
NgSwitchDefault,
LineTypePipe, LineTypePipe,
ReiheRoutePipe, ReiheRoutePipe
], ],
}) })
export class ArticleDetailsTextComponent { export class ArticleDetailsTextComponent {
@Input() @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 <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" 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()" (click)="close.emit()"
> >
{{ item?.product?.name }} {{ item?.product?.name }}
</button> </button>
<h1>Empfehlungen für Sie</h1> <h1>Empfehlungen für Sie</h1>
<p>Neben dem Titel "{{ item.product?.name }}" gibt es noch andere Artikel, die Sie interessieren könnten.</p> <p>Neben dem Titel "{{ item.product?.name }}" gibt es noch andere Artikel, die Sie interessieren könnten.</p>
<div class="articles"> <div class="articles">
<span class="label mb-2"> <span class="label mb-2">
<ui-icon icon="recommendation" size="20px"></ui-icon> <ui-icon icon="recommendation" size="20px"></ui-icon>
Artikel Artikel
</span> </span>
@if (store.recommendations$ | async; as recommendations) {
<ng-container *ngIf="store.recommendations$ | async; let recommendations"> @if (recommendations.length === 0) {
<span *ngIf="recommendations.length === 0" class="empty-message">Keine Empfehlungen verfügbar</span> <span class="empty-message">Keine Empfehlungen verfügbar</span>
}
<ui-slider *ngIf="recommendations.length > 0" [scrollDistance]="210"> @if (recommendations.length > 0) {
<a <ui-slider [scrollDistance]="210">
class="article" @for (recommendation of store.recommendations$ | async; track recommendation) {
*ngFor="let recommendation of store.recommendations$ | async" <a
[routerLink]="getDetailsPath(recommendation.product.ean)" class="article"
[queryParams]="{ main_qs: recommendation.product.ean, filter_format: '' }" [routerLink]="getDetailsPath(recommendation.product.ean)"
(click)="close.emit()" [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"> <img [src]="recommendation.product?.ean | productImage: 195 : 315 : true" alt="product-image" />
<span class="format">{{ recommendation.product?.formatDetail }}</span> <div class="flex flex-col">
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span> <span class="format">{{ recommendation.product?.formatDetail }}</span>
</div> <span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
</a> </div>
</ui-slider> </a>
</ng-container> }
</ui-slider>
}
}
</div> </div>
</ng-container> }

View File

@@ -1,19 +1,19 @@
<div class="hidden desktop-large:block" [class.show-filter]="showFilter"> <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="catalog-search-filter-content">
<div class="w-full flex flex-row justify-end items-center"> <div class="w-full flex flex-row justify-end items-center">
<button (click)="clearFilter(filter)" class="text-[#0556B4] p-4">Alle Filter entfernen</button> <button (click)="clearFilter(filter)" class="text-[#0556B4] p-4">Alle Filter entfernen</button>
<a @if (showFilterClose$ | async) {
*ngIf="showFilterClose$ | async" <a
class="text-black p-4 outline-none border-none bg-transparent" class="text-black p-4 outline-none border-none bg-transparent"
[routerLink]="closeFilterRoute" [routerLink]="closeFilterRoute"
(click)="showFilter = false" (click)="showFilter = false"
queryParamsHandling="preserve" queryParamsHandling="preserve"
> >
<shared-icon icon="close" [size]="25"></shared-icon> <shared-icon icon="close" [size]="25"></shared-icon>
</a> </a>
}
</div> </div>
<div class="catalog-search-filter-content-main -mt-14 desktop-small:-mt-8 desktop-large:-mt-12"> <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> <h1 class="text-h3 text-[1.625rem] font-bold text-center pt-6 pb-10">Filter</h1>
<shared-filter <shared-filter
@@ -24,16 +24,14 @@
[scanner]="true" [scanner]="true"
></shared-filter> ></shared-filter>
</div> </div>
<div class="cta-wrapper"> <div class="cta-wrapper">
<button class="cta-reset-filter" (click)="resetFilter(filter)" [disabled]="fetching$ | async">Filter zurücksetzen</button> <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)"> <button class="cta-apply-filter" (click)="applyFilter(filter)" [disabled]="(fetching$ | async) || !hasSelectedOptions(filter)">
<ui-spinner [show]="fetching$ | async">Filter anwenden</ui-spinner> <ui-spinner [show]="fetching$ | async">Filter anwenden</ui-spinner>
</button> </button>
</div> </div>
</div> </div>
</ng-container> }
</div> </div>
<div class="desktop-large:hidden" [class.hidden]="showFilter"> <div class="desktop-large:hidden" [class.hidden]="showFilter">
<page-article-search-main (showFilter)="showFilter = true"></page-article-search-main> <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"> <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> <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> <p class="text-lg mb-10">Welchen Artikel suchen Sie?</p>
<ng-container *ngIf="filter$ | async; let filter"> @if (filter$ | async; as filter) {
<shared-filter-filter-group-main @if (!(isDesktop$ | async)) {
class="mb-8 w-full" <shared-filter-filter-group-main
*ngIf="!(isDesktop$ | async)" class="mb-8 w-full"
[inputGroup]="filter?.filter | group: 'main'" [inputGroup]="filter?.filter | group: 'main'"
></shared-filter-filter-group-main> ></shared-filter-filter-group-main>
}
<div class="flex flex-row px-12 justify-center desktop-large:px-0"> <div class="flex flex-row px-12 justify-center desktop-large:px-0">
<shared-filter-input-group-main <shared-filter-input-group-main
class="block w-full mr-3 desktop-large:mx-auto" class="block w-full mr-3 desktop-large:mx-auto"
@@ -17,38 +18,40 @@
[showDescription]="false" [showDescription]="false"
[scanner]="true" [scanner]="true"
></shared-filter-input-group-main> ></shared-filter-input-group-main>
<button @if (!(isDesktop$ | async)) {
type="button" <button
*ngIf="!(isDesktop$ | async)" type="button"
(click)="showFilter.emit()" (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="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" [class.active]="hasFilter$ | async"
> >
<shared-icon class="mr-2" icon="filter-variant"></shared-icon> <shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter Filter
</button> </button>
}
</div> </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)]"> <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> <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"> <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"> @for (recentQuery of history$ | async; track recentQuery) {
<button <li class="list-none pb-3">
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0" <button
(click)="setQueryHistory(filter, recentQuery.friendlyName)" class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0"
matomoClickCategory="search" (click)="setQueryHistory(filter, recentQuery.friendlyName)"
matomoClickAction="click" matomoClickCategory="search"
matomoClickName="recent-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]" <shared-icon
icon="magnify" class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
[size]="20" icon="magnify"
></shared-icon> [size]="20"
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ recentQuery.friendlyName }}</p> ></shared-icon>
</button> <p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ recentQuery.friendlyName }}</p>
</li> </button>
</li>
}
</ul> </ul>
</div> </div>
</ng-container> }
</div> </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"> <div class="actions">
<button (click)="continue()" class="cta cta-action-secondary">Weiter Einkaufen</button> <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="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="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> <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 class="h-4 bg-ucla-blue ml-4 w-[7.8125rem] animate-[load_1s_linear_infinite]"></div>
</div> </div>
</div> </div>
</ng-container> } @else {
<ng-template #primaryOutlet>
<div class="bg-ucla-blue rounded w-[3rem] h-[4.125rem] animate-[load_1s_linear_infinite]"></div> <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="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> <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 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 class="h-4 bg-ucla-blue w-[8.8125rem] animate-[load_1s_linear_infinite]"></div>
</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 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.page-search-result-item__item-card-primary]="primaryOutletActive"
[class.active]="isActive" [class.active]="isActive"
> >
<div class="page-search-result-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]"> <div class="page-search-result-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]">
<img @if (item?.imageId | thumbnailUrl; as thumbnailUrl) {
class="page-search-result-item__item-image w-[3.125rem] max-h-[4.9375rem]" <img
loading="lazy" class="page-search-result-item__item-image w-[3.125rem] max-h-[4.9375rem]"
*ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl" loading="lazy"
[src]="thumbnailUrl" [src]="thumbnailUrl"
[alt]="item?.product?.name" [alt]="item?.product?.name"
/> />
}
</div> </div>
<div <div
class="page-search-result-item__item-grid-container" class="page-search-result-item__item-grid-container"
[class.page-search-result-item__item-grid-container-primary]="primaryOutletActive" [class.page-search-result-item__item-grid-container-primary]="primaryOutletActive"
> >
<div <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" 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 ? '' : ';' }} @for (contributor of contributors; track contributor; let last = $last) {
</a> <a
[routerLink]="resultsPath"
[queryParams]="{ main_qs: contributor, main_author: 'author' }"
(click)="$event?.stopPropagation()"
>
{{ contributor }}{{ last ? '' : ';' }}
</a>
}
</div> </div>
<div <div
@@ -37,21 +39,24 @@
[class.text-md]="item?.product?.name?.length >= 50 && isTablet" [class.text-md]="item?.product?.name?.length >= 50 && isTablet"
[class.text-p3]="item?.product?.name?.length >= 60 || !isTablet" [class.text-p3]="item?.product?.name?.length >= 60 || !isTablet"
[class.text-xs]="item?.product?.name?.length >= 100" [class.text-xs]="item?.product?.name?.length >= 100"
> >
{{ item?.product?.name }} {{ item?.product?.name }}
</div> </div>
<div class="page-search-result-item__item-format desktop-small:text-p3"> <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"> @if (item?.product?.format && item?.product?.formatDetail) {
<img <div class="font-bold flex flex-row">
class="mr-3" @if (item?.product?.format !== '--') {
*ngIf="item?.product?.format !== '--'" <img
loading="lazy" class="mr-3"
src="assets/images/Icon_{{ item?.product?.format }}.svg" loading="lazy"
[alt]="item?.product?.formatDetail" src="assets/images/Icon_{{ item?.product?.format }}.svg"
/> [alt]="item?.product?.formatDetail"
{{ item?.product?.formatDetail | substr: 30 }} />
</div> }
{{ item?.product?.formatDetail | substr: 30 }}
</div>
}
</div> </div>
<div class="page-search-result-item__item-manufacturer desktop-small:text-p3"> <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"> <div class="page-search-result-item__item-misc desktop-small:text-p3">
{{ item?.product?.volume }} {{ item?.product?.volume }}
<span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span> @if (item?.product?.volume && item?.product?.publicationDate) {
<span>|</span>
}
{{ publicationDate }} {{ publicationDate }}
</div> </div>
<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 desktop-small:text-p3 font-bold justify-self-end"
[class.page-search-result-item__item-price-primary]="primaryOutletActive" [class.page-search-result-item__item-price-primary]="primaryOutletActive"
> >
{{ item?.catalogAvailability?.price?.value?.value | currency: 'EUR' : 'code' }} {{ item?.catalogAvailability?.price?.value?.value | currency: 'EUR' : 'code' }}
</div> </div>
<div class="page-search-result-item__item-select-bullet justify-self-end"> <div class="page-search-result-item__item-select-bullet justify-self-end">
<input @if (selectable) {
*ngIf="selectable" <input
(click)="$event.stopPropagation()" (click)="$event.stopPropagation()"
[ngModel]="selected" [ngModel]="selected"
(ngModelChange)=" (ngModelChange)="
setSelected(); setSelected();
tracker.trackEvent({ category: 'Trefferliste', action: 'select', name: item.product.name, value: selected ? 1 : 0 }) tracker.trackEvent({ category: 'Trefferliste', action: 'select', name: item.product.name, value: selected ? 1 : 0 })
" "
class="isa-select-bullet" class="isa-select-bullet"
type="checkbox" type="checkbox"
matomoTracker matomoTracker
#tracker="matomo" #tracker="matomo"
/> />
}
</div> </div>
<button <button
@@ -94,20 +102,21 @@
[overlayTriggerDisabled]="!(stockTooltipText$ | async)" [overlayTriggerDisabled]="!(stockTooltipText$ | async)"
type="button" type="button"
(click)="$event.stopPropagation(); $event.preventDefault(); showTooltip()" (click)="$event.stopPropagation(); $event.preventDefault(); showTooltip()"
> >
<ui-icon class="mr-[0.125rem] -mt-[0.275rem]" icon="home" size="1rem"></ui-icon> <ui-icon class="mr-[0.125rem] -mt-[0.275rem]" icon="home" size="1rem"></ui-icon>
<ng-container *ngIf="isOrderBranch$ | async"> @if (isOrderBranch$ | async) {
<span @if (inStock$ | async; as stock) {
*ngIf="inStock$ | async; let stock" <span
[class.skeleton]="stock.inStock === undefined" [class.skeleton]="stock.inStock === undefined"
class="min-w-[0.75rem] text-right inline-block" class="min-w-[0.75rem] text-right inline-block"
> >
{{ stock?.inStock }} {{ stock?.inStock }}
</span> </span>
</ng-container> }
<ng-container *ngIf="!(isOrderBranch$ | async)"> }
@if (!(isOrderBranch$ | async)) {
<span class="min-w-[1rem] text-center inline-block">-</span> <span class="min-w-[1rem] text-center inline-block">-</span>
</ng-container> }
<span>x</span> <span>x</span>
</button> </button>
<ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-12" [closeable]="true"> <ui-tooltip #tooltip yPosition="above" xPosition="after" [yOffset]="-12" [closeable]="true">
@@ -117,14 +126,14 @@
<div <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 desktop-small:text-p3 w-full text-right overflow-hidden text-ellipsis whitespace-nowrap"
[class.page-search-result-item__item-ssc-primary]="primaryOutletActive" [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"> <div class="hidden" [class.page-search-result-item__item-ssc-tooltip]="primaryOutletActive">
{{ ssc?.ssc }} - {{ ssc?.sscText }} {{ ssc?.ssc }} - {{ ssc?.sscText }}
</div> </div>
<strong>{{ ssc?.ssc }}</strong> <strong>{{ ssc?.ssc }}</strong>
- {{ ssc?.sscText }} - {{ ssc?.sscText }}
</ng-container> }
</div> </div>
</div> </div>
</div> </div>

View File

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

View File

@@ -9,87 +9,93 @@
</p> </p>
</div> </div>
</div> </div>
<form *ngIf="control" [formGroup]="control" (submit)="submit()"> @if (control) {
<ui-form-control class="searchbox-control" label="EAN/ISBN"> <form [formGroup]="control" (submit)="submit()">
<ui-searchbox <ui-form-control class="searchbox-control" label="EAN/ISBN">
formControlName="ean" <ui-searchbox
[query]="query$ | async" formControlName="ean"
(queryChange)="setQuery($event)" [query]="query$ | async"
(search)="search($event)" (queryChange)="setQuery($event)"
(scan)="search($event)" (search)="search($event)"
[loading]="loading$ | async" (scan)="search($event)"
[hint]="message$ | async" [loading]="loading$ | async"
tabindex="0" [hint]="message$ | async"
[scanner]="true" tabindex="0"
></ui-searchbox> [scanner]="true"
</ui-form-control> ></ui-searchbox>
<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" />
</ui-form-control> </ui-form-control>
<ui-form-control class="datepicker" label="vsl. Lieferdatum" requiredMark="*"> <ui-form-control label="Titel" requiredMark="*">
<button <input tabindex="0" uiInput formControlName="name" />
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> </ui-form-control>
</div> <div class="control-row">
<ui-form-control label="Autor"> <ui-form-control label="Menge" requiredMark="*">
<input tabindex="0" uiInput formControlName="contributors" /> <input tabindex="0" uiInput formControlName="quantity" />
</ui-form-control> </ui-form-control>
<ui-form-control label="Verlag"> <ui-form-control class="datepicker" label="vsl. Lieferdatum" requiredMark="*">
<input tabindex="0" uiInput formControlName="manufacturer" /> <button
</ui-form-control> tabindex="-1"
<ui-form-control class="supplier-dropdown" label="Lieferant" requiredMark="*"> class="date-btn"
<ui-select tabindex="-1" formControlName="supplier"> type="button"
<ui-select-option *ngFor="let supplier of suppliers$ | async" [label]="supplier.name" [value]="supplier.id"></ui-select-option> [class.content-selected]="!!(estimatedShippingDate$ | async)"
</ui-select> [uiOverlayTrigger]="uiDatepicker"
</ui-form-control> #datepicker="uiOverlayTrigger"
<div class="control-row"> >
<ui-form-control class="price" label="Stückpreis" [suffix]="price.value ? '' : ''" requiredMark="*"> <strong>
<input tabindex="0" #price uiInput formControlName="price" /> {{ 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>
<ui-form-control class="mwst-dropdown" label="MwSt" requiredMark="*"> <ui-form-control label="Verlag">
<ui-select tabindex="-1" formControlName="vat"> <input tabindex="0" uiInput formControlName="manufacturer" />
<ui-select-option *ngFor="let vat of vats$ | async" [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option> </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-select>
</ui-form-control> </ui-form-control>
</div> <div class="control-row">
<div class="actions"> <ui-form-control class="price" label="Stückpreis" [suffix]="price.value ? '' : ''" requiredMark="*">
<button <input tabindex="0" #price uiInput formControlName="price" />
class="cta-secondary" </ui-form-control>
(click)="nextItem()" <ui-form-control class="mwst-dropdown" label="MwSt" requiredMark="*">
[disabled]="control.invalid || control.disabled || (loading$ | async)" <ui-select tabindex="-1" formControlName="vat">
type="button" @for (vat of vats$ | async; track vat) {
> <ui-select-option [label]="vat.name + '%'" [value]="vat.vatType"></ui-select-option>
Weitere Artikel hinzufügen }
</button> </ui-select>
<button class="cta-primary" [disabled]="control.invalid || control.disabled || (loading$ | async)" type="submit"> </ui-form-control>
Bestellung anlegen </div>
</button> <div class="actions">
</div> <button
</form> 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> </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="card stretch">
<div class="empty-message"> <div class="empty-message">
<span class="cart-icon flex items-center justify-center"> <span class="cart-icon flex items-center justify-center">
<shared-icon icon="shopping-cart-bold" [size]="24"></shared-icon> <shared-icon icon="shopping-cart-bold" [size]="24"></shared-icon>
</span> </span>
<h1>Ihr Warenkorb ist leer.</h1> <h1>Ihr Warenkorb ist leer.</h1>
<p> <p>
Sie haben alle Artikel aus dem Sie haben alle Artikel aus dem
@@ -13,84 +12,75 @@
<br /> <br />
keinen Artikel hinzugefügt. keinen Artikel hinzugefügt.
</p> </p>
<div class="btn-wrapper"> <div class="btn-wrapper">
<a class="cta-primary" [routerLink]="productSearchBasePath">Artikel suchen</a> <a class="cta-primary" [routerLink]="productSearchBasePath">Artikel suchen</a>
<button class="cta-secondary" (click)="openDummyModal({})">Neuanlage</button> <button class="cta-secondary" (click)="openDummyModal({})">Neuanlage</button>
</div> </div>
</div> </div>
</div> </div>
</ng-container> } @else {
@if (shoppingCart$ | async; as shoppingCart) {
<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">
<div class="card stretch"> <div class="card stretch">
<div class="cta-print-wrapper"> <div class="cta-print-wrapper">
<button class="cta-print" (click)="openPrintModal()">Drucken</button> <button class="cta-print" (click)="openPrintModal()">Drucken</button>
</div> </div>
<h1 class="header">Warenkorb</h1> <h1 class="header">Warenkorb</h1>
@if (!(isDesktop$ | async)) {
<ng-container *ngIf="!(isDesktop$ | async)">
<page-checkout-review-details></page-checkout-review-details> <page-checkout-review-details></page-checkout-review-details>
</ng-container> }
@for (group of groupedItems$ | async; track trackByGroupedItems($index, group); let lastGroup = $last) {
<ng-container *ngFor="let group of groupedItems$ | async; let lastGroup = last; trackBy: trackByGroupedItems"> @if (group?.orderType !== undefined) {
<ng-container *ngIf="group?.orderType !== undefined">
<hr /> <hr />
<div class="row item-group-header bg-[#F5F7FA]"> <div class="row item-group-header bg-[#F5F7FA]">
<shared-icon @if (group.orderType !== 'Dummy') {
*ngIf="group.orderType !== 'Dummy'" <shared-icon
class="icon-order-type" class="icon-order-type"
[size]="group.orderType === 'B2B-Versand' ? 36 : 24" [size]="group.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="group.orderType" [icon]="group.orderType"
></shared-icon> ></shared-icon>
}
<div class="label" [class.dummy]="group.orderType === 'Dummy'"> <div class="label" [class.dummy]="group.orderType === 'Dummy'">
{{ group.orderType !== 'Dummy' ? group.orderType : 'Manuelle Anlage / Dummy Bestellung' }} {{ group.orderType !== 'Dummy' ? group.orderType : 'Manuelle Anlage / Dummy Bestellung' }}
<button @if (group.orderType === 'Dummy') {
*ngIf="group.orderType === 'Dummy'" <button
class="text-brand border-none font-bold text-p1 outline-none pl-4" class="text-brand border-none font-bold text-p1 outline-none pl-4"
(click)="openDummyModal({ changeDataFromCart: true })" (click)="openDummyModal({ changeDataFromCart: true })"
> >
Hinzufügen Hinzufügen
</button> </button>
}
</div> </div>
<div class="grow"></div> <div class="grow"></div>
<div class="pl-4" *ngIf="group.orderType !== 'Download' && group.orderType !== 'Dummy'"> @if (group.orderType !== 'Download' && group.orderType !== 'Dummy') {
<button class="cta-edit" (click)="showPurchasingListModal(group.items)">Ändern</button> <div class="pl-4">
</div> <button class="cta-edit" (click)="showPurchasingListModal(group.items)">Ändern</button>
</div>
}
</div> </div>
<hr @if (
*ngIf=" group.orderType === 'Download' ||
group.orderType === 'Download' || group.orderType === 'Versand' ||
group.orderType === 'Versand' || group.orderType === 'B2B-Versand' ||
group.orderType === 'B2B-Versand' || group.orderType === 'DIG-Versand'
group.orderType === 'DIG-Versand' ) {
" <hr
/> />
</ng-container> }
<ng-container *ngFor="let item of group.items; let lastItem = last; let i = index; trackBy: trackByItemId"> }
<ng-container @for (item of group.items; track trackByItemId(i, item); let lastItem = $last; let i = $index) {
*ngIf="group?.orderType !== undefined && (item.features?.orderType === 'Abholung' || item.features?.orderType === 'Rücklage')" @if (group?.orderType !== undefined && (item.features?.orderType === 'Abholung' || item.features?.orderType === 'Rücklage')) {
> @if (item?.destination?.data?.targetBranch?.data; as targetBranch) {
<ng-container *ngIf="item?.destination?.data?.targetBranch?.data; let targetBranch"> @if (i === 0 || checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)) {
<ng-container *ngIf="i === 0 || checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)">
<div <div
class="flex flex-row items-center px-5 pt-0 pb-[0.875rem] -mt-2 bg-[#F5F7FA]" class="flex flex-row items-center px-5 pt-0 pb-[0.875rem] -mt-2 bg-[#F5F7FA]"
[class.multiple-destinations]="checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)" [class.multiple-destinations]="checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)"
> >
<span class="branch-name">{{ targetBranch?.name }} | {{ targetBranch | branchAddress }}</span> <span class="branch-name">{{ targetBranch?.name }} | {{ targetBranch | branchAddress }}</span>
</div> </div>
<hr /> <hr />
</ng-container> }
</ng-container> }
</ng-container> }
<page-shopping-cart-item <page-shopping-cart-item
(changeItem)="changeItem($event)" (changeItem)="changeItem($event)"
(changeDummyItem)="changeDummyItem($event)" (changeDummyItem)="changeDummyItem($event)"
@@ -101,19 +91,22 @@
[loadingOnItemChangeById]="loadingOnItemChangeById$ | async" [loadingOnItemChangeById]="loadingOnItemChangeById$ | async"
[loadingOnQuantityChangeById]="loadingOnQuantityChangeById$ | async" [loadingOnQuantityChangeById]="loadingOnQuantityChangeById$ | async"
></page-shopping-cart-item> ></page-shopping-cart-item>
@if (!lastItem) {
<hr *ngIf="!lastItem" /> <hr />
</ng-container> }
</ng-container> }
}
<div class="h-[8.9375rem]"></div> <div class="h-[8.9375rem]"></div>
</div> </div>
<div class="card footer flex flex-col justify-center items-center"> <div class="card footer flex flex-col justify-center items-center">
<div class="flex flex-row items-start justify-between w-full mb-1"> <div class="flex flex-row items-start justify-between w-full mb-1">
<ng-container *ngIf="totalItemCount$ | async; let totalItemCount"> @if (totalItemCount$ | async; as totalItemCount) {
<div *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="total-item-reading-points w-full"> @if (totalReadingPoints$ | async; as totalReadingPoints) {
{{ totalItemCount }} Artikel | {{ totalReadingPoints }} Lesepunkte <div class="total-item-reading-points w-full">
</div> {{ totalItemCount }} Artikel | {{ totalReadingPoints }} Lesepunkte
</ng-container> </div>
}
}
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<strong class="total-value"> <strong class="total-value">
Zwischensumme {{ shoppingCart?.total?.value | currency: shoppingCart?.total?.currency : 'code' }} Zwischensumme {{ shoppingCart?.total?.value | currency: shoppingCart?.total?.currency : 'code' }}
@@ -130,11 +123,18 @@
notificationsControl?.invalid || notificationsControl?.invalid ||
((primaryCtaLabel$ | async) === 'Bestellen' && ((checkingOla$ | async) || (checkoutIsInValid$ | async))) ((primaryCtaLabel$ | async) === 'Bestellen' && ((checkingOla$ | async) || (checkoutIsInValid$ | async)))
" "
> >
<ui-spinner [show]="showOrderButtonSpinner"> <ui-spinner [show]="showOrderButtonSpinner">
{{ primaryCtaLabel$ | async }} {{ primaryCtaLabel$ | async }}
</ui-spinner> </ui-spinner>
</button> </button>
</div> </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. Überprüfen Sie die Details.
</h1> </h1>
<ng-container *ngIf="buyer$ | async; let buyer"> @if (buyer$ | async; as buyer) {
<div *ngIf="!(showAddresses$ | async)" class="flex flex-row items-start justify-between p-5"> @if (!(showAddresses$ | async)) {
<div class="flex flex-row flex-wrap pr-4"> <div class="flex flex-row items-start justify-between p-5">
<ng-container *ngIf="getNameFromBuyer(buyer); let name"> <div class="flex flex-row flex-wrap pr-4">
<div class="mr-3">{{ name.label }}</div> @if (getNameFromBuyer(buyer); as name) {
<div class="font-bold">{{ name.value }}</div> <div class="mr-3">{{ name.label }}</div>
</ng-container> <div class="font-bold">{{ name.value }}</div>
</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 }}
</div> </div>
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div> </div>
}
}
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button> @if (showNotificationChannels$ | async) {
</div> @if (control) {
</ng-container> <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"> @if (payer$ | async; as payer) {
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between px-5"> @if (showAddresses$ | async) {
<div class="flex flex-row flex-wrap pr-4" data-address-type="Lieferadresse" data-which="Lieferadresse"> <div class="flex flex-row items-start justify-between p-5 pt-0">
<div class="mr-3" data-what="title">Lieferadresse</div> <div class="flex flex-row flex-wrap pr-4" data-address-type="Rechnungsadresse" data-which="Rechnungsadresse">
<div class="font-bold" data-what="address"> <div class="mr-3" data-what="title">Rechnungsadresse</div>
{{ shippingAddress$ | async | shippingAddress }} <div class="font-bold" data-what="address">
{{ payer | payerAddress }}
</div>
</div> </div>
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button>
</div> </div>
}
}
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">Ändern</button> @if (payer$ | async; as payer) {
</div> @if (showAddresses$ | async) {
</ng-container> <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 <page-special-comment
class="mb-6 mt-4" class="mb-6 mt-4"

View File

@@ -1,18 +1,21 @@
<div class="item-thumbnail"> <div class="item-thumbnail">
<a [routerLink]="productSearchDetailsPath" [queryParams]="{ main_qs: item?.product?.ean }"> <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> </a>
</div> </div>
<div class="item-contributors"> <div class="item-contributors">
<a @for (contributor of contributors$ | async; track contributor; let last = $last) {
*ngFor="let contributor of contributors$ | async; let last = last" <a
[routerLink]="productSearchResultsPath" [routerLink]="productSearchResultsPath"
[queryParams]="{ main_qs: contributor, main_author: 'author' }" [queryParams]="{ main_qs: contributor, main_author: 'author' }"
(click)="$event?.stopPropagation()" (click)="$event?.stopPropagation()"
> >
{{ contributor }}{{ last ? '' : ';' }} {{ contributor }}{{ last ? '' : ';' }}
</a> </a>
}
</div> </div>
<div <div
@@ -21,86 +24,106 @@
[class.text-p1]="item?.product?.name?.length >= 50 || !isTablet" [class.text-p1]="item?.product?.name?.length >= 50 || !isTablet"
[class.text-p2]="item?.product?.name?.length >= 60 && isTablet" [class.text-p2]="item?.product?.name?.length >= 60 && isTablet"
[class.text-p3]="item?.product?.name?.length >= 100" [class.text-p3]="item?.product?.name?.length >= 100"
> >
<a [routerLink]="productSearchDetailsPath" [queryParams]="{ main_qs: item?.product?.ean }">{{ item?.product?.name }}</a> <a [routerLink]="productSearchDetailsPath" [queryParams]="{ main_qs: item?.product?.ean }">{{ item?.product?.name }}</a>
</div> </div>
<div class="item-format" *ngIf="item?.product?.format && item?.product?.formatDetail"> @if (item?.product?.format && item?.product?.formatDetail) {
<img <div class="item-format">
*ngIf="item?.product?.format !== '--'" @if (item?.product?.format !== '--') {
src="assets/images/Icon_{{ item?.product?.format }}.svg" <img
[alt]="item?.product?.formatDetail" src="assets/images/Icon_{{ item?.product?.format }}.svg"
/> [alt]="item?.product?.formatDetail"
{{ item?.product?.formatDetail }} />
</div> }
{{ item?.product?.formatDetail }}
</div>
}
<div class="item-info text-p2"> <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?.manufacturer | substr: 25 }} | {{ item?.product?.ean }}</div>
<div class="mb-1"> <div class="mb-1">
{{ item?.product?.volume }} {{ 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 }} {{ item?.product?.publicationDate | date }}
</div> </div>
<div *ngIf="notAvailable$ | async"> @if (notAvailable$ | async) {
<span class="text-brand item-date">Nicht verfügbar</span> <div>
</div> <span class="text-brand item-date">Nicht verfügbar</span>
<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 }}
</div> </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>
<div class="item-price-stock flex flex-col"> <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-bold">{{ item?.availability?.price?.value?.value | currency: 'EUR' : 'code' }}</div>
<div class="text-p2 font-normal"> <div class="text-p2 font-normal">
<ui-quantity-dropdown @if (!(isDummy$ | async)) {
*ngIf="!(isDummy$ | async); else quantityDummy" <ui-quantity-dropdown
[ngModel]="item?.quantity" [ngModel]="item?.quantity"
(ngModelChange)="onChangeQuantity($event)" (ngModelChange)="onChangeQuantity($event)"
[showSpinner]="(loadingOnQuantityChangeById$ | async) === item?.id" [showSpinner]="(loadingOnQuantityChangeById$ | async) === item?.id"
[disabled]="(loadingOnItemChangeById$ | async) === item?.id" [disabled]="(loadingOnItemChangeById$ | async) === item?.id"
[range]="quantityRange$ | async" [range]="quantityRange$ | async"
></ui-quantity-dropdown> ></ui-quantity-dropdown>
<ng-template #quantityDummy> } @else {
<div class="mt-2">{{ item?.quantity }}x</div> <div class="mt-2">{{ item?.quantity }}x</div>
</ng-template> }
</div>
<div class="quantity-error" *ngIf="quantityError">
{{ quantityError }}
</div> </div>
@if (quantityError) {
<div class="quantity-error">
{{ quantityError }}
</div>
}
</div> </div>
<div class="actions" *ngIf="orderType !== 'Download'"> @if (orderType !== 'Download') {
<button <div class="actions">
[disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id" @if (!(hasOrderType$ | async)) {
(click)="onChangeItem()" <button
*ngIf="!(hasOrderType$ | async)" [disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id"
> (click)="onChangeItem()"
<ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg auswählen</ui-spinner> >
</button> <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()" @if (canEdit$ | async) {
*ngIf="canEdit$ | async" <button
> [disabled]="(loadingOnQuantityChangeById$ | async) === item?.id || (loadingOnItemChangeById$ | async) === item?.id"
<ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg ändern</ui-spinner> (click)="onChangeItem()"
</button> >
</div> <ui-spinner [show]="(loadingOnItemChangeById$ | async) === item?.id">Lieferweg ändern</ui-spinner>
</button>
}
</div>
}

View File

@@ -24,11 +24,15 @@
></textarea> ></textarea>
<div class="comment-actions py-4"> <div class="comment-actions py-4">
<button type="reset" class="clear pl-4" *ngIf="!disabled && !!value" (click)="clear(); triggerResize()"> @if (!disabled && !!value) {
<shared-icon icon="close" [size]="24"></shared-icon> <button type="reset" class="clear pl-4" (click)="clear(); triggerResize()">
</button> <shared-icon icon="close" [size]="24"></shared-icon>
</button>
}
</div> </div>
</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> </div>

View File

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

View File

@@ -15,7 +15,11 @@ import { CrmCustomerService } from '@domain/crm';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { DomainOmsService } from '@domain/oms'; import { DomainOmsService } from '@domain/oms';
import { DomainCatalogService } from '@domain/catalog'; 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 { BreadcrumbService } from '@core/breadcrumb';
import { ApplicationService } from '@core/application'; import { ApplicationService } from '@core/application';
import { DomainPrinterService } from '@domain/printer'; import { DomainPrinterService } from '@domain/printer';
@@ -49,45 +53,73 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
private _onDestroy$ = new Subject<void>(); private _onDestroy$ = new Subject<void>();
processId = Date.now(); processId = Date.now();
selectedDate = this.dateAdapter.today(); 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]) => { map(([orders, params]) => {
let filteredOrders: DisplayOrderDTO[] = []; let filteredOrders: DisplayOrderDTO[] = [];
if (params?.orderIds) { if (params?.orderIds) {
const orderIds: string[] = params.orderIds.split(','); 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 { } else {
return filteredOrders; return filteredOrders;
} }
// Ticket #4228 Für die korrekte Gruppierung der Items bei gleichem Bestellziel (Aufsplitten von Abholung und Rücklage) // Ticket #4228 Für die korrekte Gruppierung der Items bei gleichem Bestellziel (Aufsplitten von Abholung und Rücklage)
const ordersWithMultipleFeatures = filteredOrders.filter((order) => 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) { if (ordersWithMultipleFeatures) {
for (let orderWithMultipleFeatures of ordersWithMultipleFeatures) { for (let orderWithMultipleFeatures of ordersWithMultipleFeatures) {
if (orderWithMultipleFeatures?.items?.length > 1) { if (orderWithMultipleFeatures?.items?.length > 1) {
const itemsWithOrderFeature = orderWithMultipleFeatures.items.filter( const itemsWithOrderFeature =
(item) => item.features.orderType === orderWithMultipleFeatures.features.orderType, orderWithMultipleFeatures.items.filter(
); (item) =>
const itemsWithDifferentOrderFeature = orderWithMultipleFeatures.items.filter( item.features.orderType ===
(item) => item.features.orderType !== orderWithMultipleFeatures.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) { if (itemsWithOrderFeature?.length > 0) {
filteredOrders = [...filteredOrders, { ...orderWithMultipleFeatures, items: itemsWithOrderFeature }]; filteredOrders = [
...filteredOrders,
{ ...orderWithMultipleFeatures, items: itemsWithOrderFeature },
];
} }
if (itemsWithDifferentOrderFeature?.length > 0) { if (itemsWithDifferentOrderFeature?.length > 0) {
filteredOrders = [ filteredOrders = [
...filteredOrders, ...filteredOrders,
{ ...orderWithMultipleFeatures, items: itemsWithDifferentOrderFeature }, {
...orderWithMultipleFeatures,
items: itemsWithDifferentOrderFeature,
},
]; ];
} }
} }
@@ -97,7 +129,9 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
return filteredOrders?.map((order) => { return filteredOrders?.map((order) => {
return { return {
...order, ...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( 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( totalItemCount$ = this.displayOrders$.pipe(
map((displayOrders) => map((displayOrders) =>
displayOrders.reduce( displayOrders.reduce(
(total, displayOrder) => (total, displayOrder) =>
total + displayOrder?.items?.reduce((subTotal, order) => subTotal + order?.quantity, 0), total +
displayOrder?.items?.reduce(
(subTotal, order) => subTotal + order?.quantity,
0,
),
0, 0,
), ),
), ),
@@ -121,7 +164,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
totalReadingPoints$ = this.displayOrders$.pipe( totalReadingPoints$ = this.displayOrders$.pipe(
switchMap((displayOrders) => { switchMap((displayOrders) => {
const items = displayOrders const items = displayOrders
.reduce<DisplayOrderItemDTO[]>((items, order) => [...items, ...order.items], []) .reduce<DisplayOrderItemDTO[]>(
(items, order) => [...items, ...order.items],
[],
)
.map((i) => { .map((i) => {
if (i?.product?.catalogProductNumber) { if (i?.product?.catalogProductNumber) {
return { return {
@@ -135,7 +181,14 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
if (items.length !== 0) { if (items.length !== 0) {
return this.domainCatalogService return this.domainCatalogService
.getPromotionPoints({ items }) .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 { } else {
return NEVER; return NEVER;
} }
@@ -147,7 +200,11 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
displayOrders.reduce( displayOrders.reduce(
(total, displayOrder) => (total, displayOrder) =>
total + 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, 0,
), ),
), ),
@@ -162,22 +219,33 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
containsDeliveryOrder$ = this.displayOrders$.pipe( containsDeliveryOrder$ = this.displayOrders$.pipe(
map( map(
(displayOrders) => (displayOrders) =>
displayOrders.filter((o) => ['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(o.features?.orderType) > -1) displayOrders.filter(
?.length > 0, (o) =>
['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(
o.features?.orderType,
) > -1,
)?.length > 0,
), ),
); );
customer$ = this.displayOrders$.pipe( 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]), map((customers) => customers.result[0]),
shareReplay(), 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( takeNowOrders$ = this.displayOrders$.pipe(
map((displayOrders) => 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, private _cdr: ChangeDetectorRef,
) { ) {
this.breadcrumb this.breadcrumb
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['checkout']) .getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, [
'checkout',
])
.pipe(first()) .pipe(first())
.subscribe(async (crumbs) => { .subscribe(async (crumbs) => {
for await (const crumb of crumbs) { for await (const crumb of crumbs) {
@@ -264,7 +334,8 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
getProductSearchDetailsQueryParams(item: DisplayOrderItemDTO) { getProductSearchDetailsQueryParams(item: DisplayOrderItemDTO) {
return { return {
main_qs: item?.product?.ean, 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 { try {
const items = item ? [item] : await this.getAllOrderItems(); const items = item ? [item] : await this.getAllOrderItems();
const subsetItems = items 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); // .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())); subsetItems.forEach((item) => (data[`${item.id}`] = date?.toISOString()));
try { try {
@@ -310,7 +386,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
async getAllOrderItems() { async getAllOrderItems() {
const orders = await this.displayOrders$.pipe(first()).toPromise(); 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) { async updateDisplayOrderItem(item: DisplayOrderItemDTO) {
@@ -322,9 +401,16 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
if (takeNowOrders.length != 1) return; if (takeNowOrders.length != 1) return;
try { try {
await this.router.navigate(this._shelfOutNavigationService.listRoute({ processId: Date.now() }).path, { await this.router.navigate(
queryParams: { main_qs: takeNowOrders[0].orderNumber, filter_supplier_id: '16' }, this._shelfOutNavigationService.listRoute({ processId: Date.now() })
}); .path,
{
queryParams: {
main_qs: takeNowOrders[0].orderNumber,
filter_supplier_id: '16',
},
},
);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
@@ -344,7 +430,8 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
.pipe( .pipe(
first(), first(),
map((printers) => { 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(); .toPromise();
@@ -362,10 +449,16 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
const result = await this.domainPrinterService const result = await this.domainPrinterService
.printOrder({ orderIds: orders.map((o) => o.id), printer }) .printOrder({ orderIds: orders.map((o) => o.id), printer })
.toPromise(); .toPromise();
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' }); this._toaster.open({
type: 'success',
message: 'Bestellbestätigung wurde gedruckt',
});
return result; return result;
} catch (error) { } 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 { } finally {
this.isPrinting$.next(false); this.isPrinting$.next(false);
} }
@@ -381,12 +474,21 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
} else { } else {
try { try {
const result = await this.domainPrinterService 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(); .toPromise();
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' }); this._toaster.open({
type: 'success',
message: 'Bestellbestätigung wurde gedruckt',
});
return result; return result;
} catch (error) { } 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 { } finally {
this.isPrinting$.next(false); 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"> <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" /> <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"> <ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #prebookedTooltip [closeable]="true">
Artikel wird für Sie vorgemerkt. Artikel wird für Sie vorgemerkt.
</ui-tooltip> </ui-tooltip>
</ng-container> }
<ng-container *ngIf="notificationsSent$ | async; let notificationsSent"> @if (notificationsSent$ | async; as notificationsSent) {
<ng-container *ngIf="notificationsSent?.NOTIFICATION_EMAIL"> @if (notificationsSent?.NOTIFICATION_EMAIL) {
<img [uiOverlayTrigger]="emailTooltip" src="/assets/images/email_bookmark.svg" /> <img [uiOverlayTrigger]="emailTooltip" src="/assets/images/email_bookmark.svg" />
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #emailTooltip [closeable]="true"> <ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #emailTooltip [closeable]="true">
Per E-Mail benachrichtigt Per E-Mail benachrichtigt
<br /> <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 {{ notification | date: 'dd.MM.yyyy | HH:mm' }} Uhr
<br /> <br />
</ng-container> }
</ui-tooltip> </ui-tooltip>
</ng-container> }
<ng-container *ngIf="notificationsSent?.NOTIFICATION_SMS"> @if (notificationsSent?.NOTIFICATION_SMS) {
<img [uiOverlayTrigger]="smsTooltip" src="/assets/images/sms_bookmark.svg" /> <img [uiOverlayTrigger]="smsTooltip" src="/assets/images/sms_bookmark.svg" />
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #smsTooltip [closeable]="true"> <ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #smsTooltip [closeable]="true">
Per SMS benachrichtigt Per SMS benachrichtigt
<br /> <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 {{ notification | date: 'dd.MM.yyyy | HH:mm' }} Uhr
<br /> <br />
</ng-container> }
</ui-tooltip> </ui-tooltip>
</ng-container> }
</ng-container> }
</div> </div>
<div class="page-customer-order-details-item__item-container"> <div class="page-customer-order-details-item__item-container">
<div class="page-customer-order-details-item__thumbnail"> <div class="page-customer-order-details-item__thumbnail">
@@ -42,169 +42,190 @@
#elementDistance="uiElementDistance" #elementDistance="uiElementDistance"
[style.max-width.px]="elementDistance.distanceChange | async" [style.max-width.px]="elementDistance.distanceChange | async"
class="flex flex-col" class="flex flex-col"
> >
<div class="font-normal mb-[0.375rem]">{{ orderItem.product?.contributors }}</div> <div class="font-normal mb-[0.375rem]">{{ orderItem.product?.contributors }}</div>
<div>{{ orderItem.product?.name }}</div> <div>{{ orderItem.product?.name }}</div>
</h3> </h3>
<div class="history-wrapper flex flex-col items-end justify-center"> <div class="history-wrapper flex flex-col items-end justify-center">
<button class="cta-history text-p1" (click)="historyClick.emit(orderItem)">Historie</button> <button class="cta-history text-p1" (click)="historyClick.emit(orderItem)">Historie</button>
@if (selectable$ | async) {
<input <input
*ngIf="selectable$ | async" [ngModel]="selected$ | async"
[ngModel]="selected$ | async" (ngModelChange)="setSelected($event)"
(ngModelChange)="setSelected($event)" class="isa-select-bullet mt-4"
class="isa-select-bullet mt-4" type="checkbox"
type="checkbox" />
/> }
</div> </div>
</div> </div>
<div class="detail"> <div class="detail">
<div class="label">Menge</div> <div class="label">Menge</div>
<div class="value"> <div class="value">
<ng-container *ngIf="!(canChangeQuantity$ | async)">{{ orderItem?.quantity }}x</ng-container> @if (!(canChangeQuantity$ | async)) {
<ui-quantity-dropdown {{ orderItem?.quantity }}x
*ngIf="canChangeQuantity$ | async" }
[showTrash]="false" @if (canChangeQuantity$ | async) {
[range]="orderItem?.quantity" <ui-quantity-dropdown
[(ngModel)]="quantity" [showTrash]="false"
[showSpinner]="false" [range]="orderItem?.quantity"
></ui-quantity-dropdown> [(ngModel)]="quantity"
[showSpinner]="false"
></ui-quantity-dropdown>
}
<span class="overall-quantity">(von {{ orderItem?.overallQuantity }})</span> <span class="overall-quantity">(von {{ orderItem?.overallQuantity }})</span>
</div> </div>
</div> </div>
<div class="detail" *ngIf="!!orderItem.product?.formatDetail"> @if (!!orderItem.product?.formatDetail) {
<div class="label">Format</div> <div class="detail">
<div class="value"> <div class="label">Format</div>
<img <div class="value">
*ngIf="orderItem?.product?.format && orderItem?.product?.format !== 'UNKNOWN'" @if (orderItem?.product?.format && orderItem?.product?.format !== 'UNKNOWN') {
class="format-icon" <img
[src]="'/assets/images/Icon_' + orderItem.product?.format + '.svg'" class="format-icon"
alt="format icon" [src]="'/assets/images/Icon_' + orderItem.product?.format + '.svg'"
/> alt="format icon"
<span>{{ orderItem.product?.formatDetail }}</span> />
}
<span>{{ orderItem.product?.formatDetail }}</span>
</div>
</div> </div>
</div> }
<div class="detail" *ngIf="!!orderItem.product?.ean"> @if (!!orderItem.product?.ean) {
<div class="label">ISBN/EAN</div> <div class="detail">
<div class="value">{{ orderItem.product?.ean }}</div> <div class="label">ISBN/EAN</div>
</div> <div class="value">{{ orderItem.product?.ean }}</div>
<div class="detail" *ngIf="orderItem.price !== undefined"> </div>
<div class="label">Preis</div> }
<div class="value">{{ orderItem.price | currency: 'EUR' }}</div> @if (orderItem.price !== undefined) {
</div> <div class="detail">
<div class="detail" *ngIf="!!orderItem.retailPrice?.vat?.inPercent"> <div class="label">Preis</div>
<div class="label">MwSt</div> <div class="value">{{ orderItem.price | currency: 'EUR' }}</div>
<div class="value">{{ orderItem.retailPrice?.vat?.inPercent }}%</div> </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" /> <hr class="border-[#EDEFF0] border-t-2 my-4" />
@if (orderItem.supplier) {
<div class="detail" *ngIf="orderItem.supplier"> <div class="detail">
<div class="label">Lieferant</div> <div class="label">Lieferant</div>
<div class="value">{{ orderItem.supplier }}</div> <div class="value">{{ orderItem.supplier }}</div>
</div> </div>
<div class="detail" *ngIf="!!orderItem.ssc || !!orderItem.sscText"> }
<div class="label">Meldenummer</div> @if (!!orderItem.ssc || !!orderItem.sscText) {
<div class="value">{{ orderItem.ssc }} - {{ orderItem.sscText }}</div> <div class="detail">
</div> <div class="label">Meldenummer</div>
<div class="detail" *ngIf="!!orderItem.targetBranch"> <div class="value">{{ orderItem.ssc }} - {{ orderItem.sscText }}</div>
<div class="label">Zielfiliale</div> </div>
<div class="value">{{ orderItem.targetBranch }}</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="detail">
<div class="label"> <div class="label">
<ng-container @if (
*ngIf=" orderItemFeature(orderItem) === 'Versand' ||
orderItemFeature(orderItem) === 'Versand' || orderItemFeature(orderItem) === 'B2B-Versand' ||
orderItemFeature(orderItem) === 'B2B-Versand' || orderItemFeature(orderItem) === 'DIG-Versand'
orderItemFeature(orderItem) === 'DIG-Versand' ) {
"
>
{{ orderItem?.estimatedDelivery ? 'Lieferung zwischen' : 'Lieferung ab' }} {{ 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 Abholung ab
</ng-container> }
</div> </div>
@if (!!orderItem?.estimatedDelivery || !!orderItem?.estimatedShippingDate) {
<ng-container *ngIf="!!orderItem?.estimatedDelivery || !!orderItem?.estimatedShippingDate">
<div class="value bg-[#D8DFE5] rounded w-max px-2"> <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?.start | date: 'dd.MM.yy' }} und
{{ orderItem?.estimatedDelivery?.stop | date: 'dd.MM.yy' }} {{ orderItem?.estimatedDelivery?.stop | date: 'dd.MM.yy' }}
</ng-container> } @else {
@if (!!orderItem?.estimatedShippingDate) {
{{ orderItem?.estimatedShippingDate | date: 'dd.MM.yy' }}
}
}
</div> </div>
</ng-container> }
<ng-template #estimatedShippingDate>
<ng-container *ngIf="!!orderItem?.estimatedShippingDate">
{{ orderItem?.estimatedShippingDate | date: 'dd.MM.yy' }}
</ng-container>
</ng-template>
</div> </div>
<div class="page-customer-order-details-item__tracking-details" *ngIf="getOrderItemTrackingData(orderItem); let trackingData"> @if (getOrderItemTrackingData(orderItem); as trackingData) {
<div class="label">{{ trackingData.length > 1 ? 'Sendungsnummern' : 'Sendungsnummer' }}</div> <div class="page-customer-order-details-item__tracking-details">
<ng-container *ngFor="let tracking of trackingData"> <div class="label">{{ trackingData.length > 1 ? 'Sendungsnummern' : 'Sendungsnummer' }}</div>
<ng-container *ngIf="tracking.trackingProvider === 'DHL' && !isNative; else noTrackingLink"> @for (tracking of trackingData; track tracking) {
<a class="value text-[#0556B4]" [href]="getTrackingNumberLink(tracking.trackingNumber)" target="_blank"> @if (tracking.trackingProvider === 'DHL' && !isNative) {
{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }} <a class="value text-[#0556B4]" [href]="getTrackingNumberLink(tracking.trackingNumber)" target="_blank">
</a> {{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}
</ng-container> </a>
<ng-template #noTrackingLink> } @else {
<p class="value">{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}</p> <p class="value">{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}</p>
</ng-template> }
</ng-container> }
</div> </div>
}
<hr class="border-[#EDEFF0] border-t-2 my-4" /> <hr class="border-[#EDEFF0] border-t-2 my-4" />
@if (!!orderItem?.compartmentCode) {
<div class="detail" *ngIf="!!orderItem?.compartmentCode"> <div class="detail">
<div class="label">Abholfachnr.</div> <div class="label">Abholfachnr.</div>
<div class="value">{{ orderItem?.compartmentCode }}</div> <div class="value">{{ orderItem?.compartmentCode }}</div>
</div> </div>
}
<div class="detail"> <div class="detail">
<div class="label">Vormerker</div> <div class="label">Vormerker</div>
<div class="value">{{ orderItem.isPrebooked ? 'Ja' : 'Nein' }}</div> <div class="value">{{ orderItem.isPrebooked ? 'Ja' : 'Nein' }}</div>
</div> </div>
<hr class="border-[#EDEFF0] border-t-2 my-4" /> <hr class="border-[#EDEFF0] border-t-2 my-4" />
@if (!!orderItem.paymentProcessing) {
<div class="detail" *ngIf="!!orderItem.paymentProcessing"> <div class="detail">
<div class="label">Zahlungsweg</div> <div class="label">Zahlungsweg</div>
<div class="value">{{ orderItem.paymentProcessing || '-' }}</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>
</div> </div>
<div class="detail" *ngIf="!!receipt?.printedDate"> }
<div class="label">Erstellt am</div> @if (!!orderItem.paymentType) {
<div class="value">{{ receipt?.printedDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div> <div class="detail">
<div class="label">Zahlungsart</div>
<div class="value">{{ orderItem.paymentType | paymentType }}</div>
</div> </div>
<div class="detail" *ngIf="!!receipt?.receiptText"> }
<div class="label">Rechnungstext</div> @if (receiptCount$ | async; as count) {
<div class="value">{{ receipt?.receiptText || '-' }}</div> <h4 class="receipt-header">
</div> {{ count > 1 ? 'Belege' : 'Beleg' }}
<div class="detail" *ngIf="!!receipt?.receiptType"> </h4>
<div class="label">Belegart</div> }
<div class="value"> @for (receipt of receipts$ | async; track receipt) {
{{ receipt?.receiptType === 1 ? 'Lieferschein' : receipt?.receiptType === 64 ? 'Zahlungsbeleg' : '-' }} @if (!!receipt?.receiptNumber) {
<div class="detail">
<div class="label">Belegnummer</div>
<div class="value">{{ receipt?.receiptNumber }}</div>
</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="page-customer-order-details-item__comment flex flex-col items-start mt-[1.625rem]">
<div class="label mb-[0.375rem]">Anmerkung</div> <div class="label mb-[0.375rem]">Anmerkung</div>
<div class="flex flex-row w-full"> <div class="flex flex-row w-full">
<textarea <textarea
matInput matInput
@@ -222,27 +243,28 @@
[formControl]="specialCommentControl" [formControl]="specialCommentControl"
[class.inactive]="!specialCommentControl.dirty" [class.inactive]="!specialCommentControl.dirty"
></textarea> ></textarea>
<div class="comment-actions"> <div class="comment-actions">
<button @if (!!specialCommentControl.value?.length) {
type="reset" <button
class="clear" type="reset"
*ngIf="!!specialCommentControl.value?.length" class="clear"
(click)="specialCommentControl.setValue(''); saveSpecialComment(); triggerResize()" (click)="specialCommentControl.setValue(''); saveSpecialComment(); triggerResize()"
> >
<shared-icon icon="close" [size]="24"></shared-icon> <shared-icon icon="close" [size]="24"></shared-icon>
</button> </button>
<button }
class="cta-save" @if (specialCommentControl?.enabled && specialCommentControl.dirty) {
type="submit" <button
*ngIf="specialCommentControl?.enabled && specialCommentControl.dirty" class="cta-save"
(click)="saveSpecialComment()" type="submit"
> (click)="saveSpecialComment()"
Speichern >
</button> Speichern
</button>
}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</ng-container> }

View File

@@ -1,19 +1,20 @@
<div class="page-customer-order-details-tags__wrapper"> <div class="page-customer-order-details-tags__wrapper">
<button @for (tag of defaultTags; track tag) {
class="page-customer-order-details-tags__tag" <button
type="button" class="page-customer-order-details-tags__tag"
[class.selected]="tag === (selected$ | async) && !inputFocus.focused" type="button"
*ngFor="let tag of defaultTags" [class.selected]="tag === (selected$ | async) && !inputFocus.focused"
(click)="setCompartmentInfo(tag)" (click)="setCompartmentInfo(tag)"
> >
{{ tag }} {{ tag }}
</button> </button>
}
<button <button
(click)="inputFocus.focus()" (click)="inputFocus.focus()"
type="button" type="button"
class="page-customer-order-details-tags__tag" class="page-customer-order-details-tags__tag"
[class.selected]="(inputValue$ | async) === (selected$ | async) && (inputValue$ | async)" [class.selected]="(inputValue$ | async) === (selected$ | async) && (inputValue$ | async)"
> >
<input <input
#inputFocus="uiFocus" #inputFocus="uiFocus"
uiFocus uiFocus
@@ -23,6 +24,6 @@
placeholder="..." placeholder="..."
[size]="controlSize$ | async" [size]="controlSize$ | async"
maxlength="15" maxlength="15"
/> />
</button> </button>
</div> </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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, forwardRef } from '@angular/core';
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { UiCommonModule } from '@ui/common'; import { UiCommonModule } from '@ui/common';
@@ -14,7 +14,7 @@ import { PickUpShelfDetailsTagsComponent } from '../../../pickup-shelf/shared/pi
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-pickup-shelf-details-tags' }, host: { class: 'page-pickup-shelf-details-tags' },
standalone: true, standalone: true,
imports: [NgFor, UiCommonModule, FormsModule, AsyncPipe, MatomoModule], imports: [UiCommonModule, FormsModule, AsyncPipe, MatomoModule],
providers: [ providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => PickUpShelfDetailsTagsComponent), multi: true }, { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => PickUpShelfDetailsTagsComponent), multi: true },
], ],

View File

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

View File

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

View File

@@ -11,53 +11,57 @@
<br /> <br />
oder scannen Sie die Kundenkarte. oder scannen Sie die Kundenkarte.
</p> </p>
<ng-container *ngIf="filter$ | async; let filter"> @if (filter$ | async; as filter) {
<shared-filter-filter-group-main @if (!(isDesktop$ | async)) {
class="mb-8 w-full" <shared-filter-filter-group-main
*ngIf="!(isDesktop$ | async)" class="mb-8 w-full"
[inputGroup]="filter?.filter | group: 'main'" [inputGroup]="filter?.filter | group: 'main'"
></shared-filter-filter-group-main> ></shared-filter-filter-group-main>
}
<div class="flex flex-row px-12 justify-center desktop-large:px-0"> <div class="flex flex-row px-12 justify-center desktop-large:px-0">
<shared-filter-input-group-main @if (filter?.input | group: 'main'; as inputGroup) {
class="block w-full mr-3 desktop-large:mx-auto" <shared-filter-input-group-main
*ngIf="filter?.input | group: 'main'; let inputGroup" class="block w-full mr-3 desktop-large:mx-auto"
[inputGroup]="inputGroup" [inputGroup]="inputGroup"
[loading]="loading$ | async" [loading]="loading$ | async"
(search)="search(filter)" (search)="search(filter)"
[hint]="message$ | async" [hint]="message$ | async"
[scanner]="true" [scanner]="true"
></shared-filter-input-group-main> ></shared-filter-input-group-main>
<button }
*ngIf="!(isDesktop$ | async)" @if (!(isDesktop$ | async)) {
(click)="showFilter.emit()" <button
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" (click)="showFilter.emit()"
[class.active]="hasFilter$ | async" 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"
type="button" [class.active]="hasFilter$ | async"
> type="button"
<shared-icon class="mr-2" icon="filter-variant"></shared-icon> >
Filter <shared-icon class="mr-2" icon="filter-variant"></shared-icon>
</button> Filter
</button>
}
</div> </div>
<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)]" 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> <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"> <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"> @for (query of history$ | async; track query) {
<button <li class="list-none pb-3">
class="flex flex-row items-center outline-none border-none bg-white text-black text-p2 m-0 p-0" <button
(click)="setQueryHistory(filter, query)" 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]" <shared-icon
icon="magnify" class="flex w-8 h-8 justify-center items-center mr-3 rounded-full text-black bg-[#edeff0]"
[size]="20" icon="magnify"
></shared-icon> [size]="20"
<p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ query }}</p> ></shared-icon>
</button> <p class="m-0 p-0 whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[25rem]">{{ query }}</p>
</li> </button>
</li>
}
</ul> </ul>
</div> </div>
</ng-container> }
</div> </div>

View File

@@ -5,19 +5,20 @@
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''" [routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
[queryParams]="queryParams" [queryParams]="queryParams"
(click)="isDesktopLarge ? scrollIntoView() : ''" (click)="isDesktopLarge ? scrollIntoView() : ''"
> >
<div <div
class="page-customer-order-item__item-grid-container" class="page-customer-order-item__item-grid-container"
[class.page-customer-order-item__item-grid-container-main]="primaryOutletActive" [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]"> <div class="page-customer-order-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]">
<img @if (item?.product?.ean | productImage; as productImage) {
class="page-customer-order-item__item-image w-[3.125rem] max-h-[4.9375rem]" <img
loading="lazy" class="page-customer-order-item__item-image w-[3.125rem] max-h-[4.9375rem]"
*ngIf="item?.product?.ean | productImage; let productImage" loading="lazy"
[src]="productImage" [src]="productImage"
[alt]="item?.product?.name" [alt]="item?.product?.name"
/> />
}
</div> </div>
<div <div
@@ -27,7 +28,7 @@
[class.text-p2]="item?.product?.name?.length >= 50 && isTablet" [class.text-p2]="item?.product?.name?.length >= 50 && isTablet"
[class.text-p3]="item?.product?.name?.length >= 60 || !isTablet" [class.text-p3]="item?.product?.name?.length >= 60 || !isTablet"
[class.text-p4]="item?.product?.name?.length >= 100" [class.text-p4]="item?.product?.name?.length >= 100"
> >
{{ item?.product?.name }} {{ item?.product?.name }}
</div> </div>
@@ -35,88 +36,111 @@
{{ item?.specialComment }} {{ item?.specialComment }}
</div> </div>
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-format desktop-small:text-p2"> @if (primaryOutletActive) {
<div *ngIf="item?.product?.format && item?.product?.formatDetail" class="font-bold flex flex-row"> <div class="page-customer-order-item__item-format desktop-small:text-p2">
<img @if (item?.product?.format && item?.product?.formatDetail) {
class="mr-3" <div class="font-bold flex flex-row">
*ngIf="item?.product?.format !== '--'" @if (item?.product?.format !== '--') {
loading="lazy" <img
src="assets/images/Icon_{{ item?.product?.format }}.svg" class="mr-3"
[alt]="item?.product?.formatDetail" loading="lazy"
/> src="assets/images/Icon_{{ item?.product?.format }}.svg"
{{ item?.product?.formatDetail | substr: 30 }} [alt]="item?.product?.formatDetail"
/>
}
{{ item?.product?.formatDetail | substr: 30 }}
</div>
}
</div> </div>
</div> }
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-ean desktop-small:text-p2"> @if (primaryOutletActive) {
{{ item?.product?.ean }} <div class="page-customer-order-item__item-ean desktop-small:text-p2">
</div> {{ item?.product?.ean }}
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-price desktop-small:text-p2 font-bold"> @if (primaryOutletActive) {
{{ item.price | currency: 'EUR' : 'code' }} <div class="page-customer-order-item__item-price desktop-small:text-p2 font-bold">
</div> {{ item.price | currency: 'EUR' : 'code' }}
</div>
}
<div *ngIf="primaryOutletActive" class="page-customer-order-item__item-changed desktop-small:text-p2"> @if (primaryOutletActive) {
<ng-container [ngSwitch]="showChangeDate$ | async"> <div class="page-customer-order-item__item-changed desktop-small:text-p2">
<div class="flex flex-row" *ngSwitchCase="true"> @switch (showChangeDate$ | async) {
<div class="min-w-[7.5rem]">Geändert</div> @case (true) {
<div class="font-bold">{{ item?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div> <div class="flex flex-row">
</div> <div class="min-w-[7.5rem]">Geändert</div>
<div class="flex flex-row" *ngSwitchCase="false"> <div class="font-bold">{{ item?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
<div class="min-w-[7.5rem]">Bestelldatum</div> </div>
<div class="font-bold">{{ item?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div> }
</div> @case (false) {
</ng-container> <div class="flex flex-row">
</div> <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"> @if (primaryOutletActive) {
<div class="min-w-[7.5rem]">Menge</div> <div class="page-customer-order-item__item-quantity flex flex-row desktop-small:text-p2">
<div class="font-bold">{{ item.quantity }} x</div> <div class="min-w-[7.5rem]">Menge</div>
</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"> @if (primaryOutletActive) {
<ng-container *ngIf="item.orderType === 1; else showDelivery"> <div class="page-customer-order-item__item-target-branch flex flex-row desktop-small:text-p2">
<div class="min-w-[7.5rem]">Zielfiliale</div> @if (item.orderType === 1) {
<div class="font-bold">{{ item.targetBranch }}</div> <div class="min-w-[7.5rem]">Zielfiliale</div>
</ng-container> <div class="font-bold">{{ item.targetBranch }}</div>
<ng-template #showDelivery> } @else {
<div class="min-w-[7.5rem]">Versanddatum</div> <div class="min-w-[7.5rem]">Versanddatum</div>
<div class="font-bold">{{ item?.estimatedShippingDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div> <div class="font-bold">{{ item?.estimatedShippingDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</ng-template> }
</div> </div>
}
<hr @if (!primaryOutletActive) {
*ngIf="!primaryOutletActive" <hr
class="page-customer-order-item__separator border-[#EDEFF0] border-solid border-[1px] -mx-[0.875rem]" class="page-customer-order-item__separator border-[#EDEFF0] border-solid border-[1px] -mx-[0.875rem]"
/> />
}
<div <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 desktop-small:text-xl justify-self-end font-bold"
[class.page-customer-order-item__item-order-number-main]="!primaryOutletActive" [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 }} {{ item?.compartmentCode }}{{ item?.compartmentInfo && '_' + item?.compartmentInfo }}
</ng-container> } @else {
<ng-template #orderNumber>{{ item?.orderNumber }}</ng-template> {{ item?.orderNumber }}
}
</div> </div>
<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" 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]"> <div class="page-customer-order-item__item-processing-status flex flex-row mb-[0.375rem]">
<shared-icon @if (item.processingStatus | processingStatus: 'icon'; as icon) {
class="flex items-center justify-center mr-1" <shared-icon
[size]="16" class="flex items-center justify-center mr-1"
*ngIf="item.processingStatus | processingStatus: 'icon'; let icon" [size]="16"
[icon]="icon" [icon]="icon"
></shared-icon> ></shared-icon>
}
{{ item.processingStatus | processingStatus }} {{ item.processingStatus | processingStatus }}
</div> </div>
<div class="page-customer-order-item__item-paid flex flex-row self-end"> <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"> @if (item.features?.paid) {
{{ item.features?.paid }} <div class="font-bold w-fit desktop-small:text-p2 px-3 py-[0.125rem] rounded text-white bg-[#26830C]">
</div> {{ item.features?.paid }}
</div>
}
</div> </div>
</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="page-customer-order-search-results__header bg-background-liste flex items-end justify-between"
[class.pb-4]="!(primaryOutletActive$ | async)" [class.pb-4]="!(primaryOutletActive$ | async)"
[class.flex-col]="!(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)"> <div class="flex flex-row w-full desktop-small:w-min" [class.desktop-large:w-full]="!(primaryOutletActive$ | async)">
<shared-filter-input-group-main @if (filter$ | async; as filter) {
*ngIf="filter$ | async; let filter" <shared-filter-input-group-main
class="block mr-3 w-full desktop-small:w-[23.5rem]" class="block mr-3 w-full desktop-small:w-[23.5rem]"
[class.desktop-large:w-full]="!(primaryOutletActive$ | async)" [class.desktop-large:w-full]="!(primaryOutletActive$ | async)"
[hint]="message$ | async" [hint]="message$ | async"
[loading]="loading$ | async" [loading]="loading$ | async"
[inputGroup]="filter?.input | group: 'main'" [inputGroup]="filter?.input | group: 'main'"
(search)="search({ filter, clear: true })" (search)="search({ filter, clear: true })"
[showDescription]="false" [showDescription]="false"
[scanner]="true" [scanner]="true"
></shared-filter-input-group-main> ></shared-filter-input-group-main>
}
<a <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="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" [class.active]="hasFilter$ | async"
[routerLink]="filterRoute" [routerLink]="filterRoute"
queryParamsHandling="preserve" queryParamsHandling="preserve"
> >
<shared-icon class="mr-2" icon="filter-variant"></shared-icon> <shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter Filter
</a> </a>
</div> </div>
<div @if (hits$ | async; as hits) {
*ngIf="hits$ | async; let hits" <div
class="page-customer-order-search-results__items-count inline-flex flex-row items-center pr-5 text-p3" class="page-customer-order-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
[class.mb-4]="primaryOutletActive$ | async" [class.mb-4]="primaryOutletActive$ | async"
> >
{{ hits ?? 0 }} {{ hits ?? 0 }}
Titel Titel
</div> </div>
}
</div> </div>
<ui-scroll-container @if (!(listEmpty$ | async)) {
*ngIf="!(listEmpty$ | async); else emptyMessage" <ui-scroll-container
class="page-customer-order-results__scroll-container m-0 p-0" class="page-customer-order-results__scroll-container m-0 p-0"
[showScrollbar]="false" [showScrollbar]="false"
[showScrollArrow]="false" [showScrollArrow]="false"
(reachEnd)="loadMore()" (reachEnd)="loadMore()"
[deltaEnd]="150" [deltaEnd]="150"
[itemLength]="itemLength$ | async" [itemLength]="itemLength$ | async"
[containerHeight]="25" [containerHeight]="25"
[showSpacer]="(primaryOutletActive$ | async) || (isTablet$ | async)" [showSpacer]="(primaryOutletActive$ | async) || (isTablet$ | async)"
> >
<ng-container *ngIf="processId$ | async; let processId"> @if (processId$ | async; as processId) {
<div class="page-customer-order-results__items-list w-full" *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn"> @for (bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn; track bueryNumberGroup) {
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem"> <div class="page-customer-order-results__items-list w-full">
<div @if (bueryNumberGroup.items[0]; as firstItem) {
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" <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 }} <h3 class="m-0 break-words" [class.w-72]="!(primaryOutletActive$ | async)">
<ng-container *ngIf="!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)">-</ng-container> {{ firstItem?.organisation }}
{{ firstItem?.lastName }} @if (!!firstItem?.organisation && (!!firstItem?.firstName || !!firstItem?.lastName)) {
{{ firstItem?.firstName }} -
</h3> }
<h3 class="m-0 break-words text-right" [class.w-40]="!(primaryOutletActive$ | async)">{{ firstItem?.buyerNumber }}</h3> {{ 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> </div>
</ng-container> }
}
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn"> </ui-scroll-container>
<ng-container *ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn"> } @else {
<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>
<div class="empty-message"> <div class="empty-message">
Es sind im Moment keine Bestellposten vorhanden, Es sind im Moment keine Bestellposten vorhanden,
<br /> <br />
die bearbeitet werden können. die bearbeitet werden können.
</div> </div>
</ng-template> }
<div class="actions z-fixed" *ngIf="actions$ | async; let actions">
<button @if (actions$ | async; as actions) {
[disabled]="(loadingFetchedActionButton$ | async) || (loading$ | async)" <div class="actions z-fixed">
class="cta-action" @for (action of actions; track action) {
*ngFor="let action of actions" <button
[class.cta-action-primary]="action.selected" [disabled]="(loadingFetchedActionButton$ | async) || (loading$ | async)"
[class.cta-action-secondary]="!action.selected" class="cta-action"
(click)="handleAction(action)" [class.cta-action-primary]="action.selected"
> [class.cta-action-secondary]="!action.selected"
<ui-spinner [show]="(loadingFetchedActionButton$ | async) || (loading$ | async)">{{ action.label }}</ui-spinner> (click)="handleAction(action)"
</button> >
</div> <ui-spinner [show]="(loadingFetchedActionButton$ | async) || (loading$ | async)">{{ action.label }}</ui-spinner>
</button>
}
</div>
}

View File

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

View File

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

View File

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

View File

@@ -1,21 +1,23 @@
<ng-container *ifRole="'Store'"> <ng-container *ifRole="'Store'">
<shared-checkbox @if (customerType !== 'b2b') {
*ngIf="customerType !== 'b2b'" <shared-checkbox
[ngModel]="p4mUser" [ngModel]="p4mUser"
(ngModelChange)="setValue({ p4mUser: !p4mUser })" (ngModelChange)="setValue({ p4mUser: !p4mUser })"
[disabled]="p4mReadonly || readonly" [disabled]="p4mReadonly || readonly"
> >
Kundenkarte Kundenkarte
</shared-checkbox> </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>
</ng-container> </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" type="text"
formControlName="street" formControlName="street"
[tabindex]="tabIndexStart" [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" [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-form-control class="col-span-2" label="Adresszusatz">
<shared-select placeholder="Land" formControlName="country" [tabindex]="tabIndexStart + 5" [readonly]="readonly"> <input
<shared-select-option *ngFor="let country of countries || (countries$ | async)" [value]="country.isO3166_A_3"> placeholder="Adresszusatz"
{{ country.name }} class="input-control"
</shared-select-option> type="text"
</shared-select> formControlName="info"
</shared-form-control> [tabindex]="tabIndexStart + 4"
</ng-container> [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" [tabindex]="tabIndexStart"
[autofocus]="focusAfterInit" [autofocus]="focusAfterInit"
[readonly]="readonly" [readonly]="readonly"
> >
<ng-content></ng-content> <ng-content></ng-content>
</shared-checkbox> </shared-checkbox>
<div class="address-block" *ngIf="control.value.deviatingAddress"> @if (control.value.deviatingAddress) {
<div class="wrapper"> <div class="address-block">
<app-organisation-form-block <div class="wrapper">
*ngIf="organisation" @if (organisation) {
[tabIndexStart]="tabIndexStart + 1" <app-organisation-form-block
#orgaBlock [tabIndexStart]="tabIndexStart + 1"
(onInit)="addOrganisationGroup($event)" #orgaBlock
(onDestroy)="removeOrganisationGroup()" (onInit)="addOrganisationGroup($event)"
[data]="data?.organisation" (onDestroy)="removeOrganisationGroup()"
#nameFormBlock [data]="data?.organisation"
[tabIndexStart]="tabIndexStart + 1" #nameFormBlock
[requiredMarks]="organisationRequiredMarks" [tabIndexStart]="tabIndexStart + 1"
[validatorFns]="organisationValidatorFns" [requiredMarks]="organisationRequiredMarks"
[readonly]="readonly" [validatorFns]="organisationValidatorFns"
></app-organisation-form-block> [readonly]="readonly"
<app-name-form-block ></app-organisation-form-block>
(onInit)="addNameGroup($event)" }
(onDestroy)="removeNameGroup()" <app-name-form-block
[data]="data?.name" (onInit)="addNameGroup($event)"
#nameFormBlock (onDestroy)="removeNameGroup()"
[requiredMarks]="nameRequiredMarks" [data]="data?.name"
[validatorFns]="nameValidatorFns" #nameFormBlock
[readonly]="readonly" [requiredMarks]="nameRequiredMarks"
></app-name-form-block> [validatorFns]="nameValidatorFns"
<app-address-form-block [readonly]="readonly"
#addressFormBlock ></app-name-form-block>
(onInit)="addAddressGroup($event)" <app-address-form-block
(onDestroy)="removeAddressGroup()" #addressFormBlock
[data]="data?.address" (onInit)="addAddressGroup($event)"
[requiredMarks]="addressRequiredMarks" (onDestroy)="removeAddressGroup()"
[validatorFns]="addressValidatorFns" [data]="data?.address"
[readonly]="readonly" [requiredMarks]="addressRequiredMarks"
></app-address-form-block> [validatorFns]="addressValidatorFns"
<app-email-form-block [readonly]="readonly"
*ngIf="email" ></app-address-form-block>
#emailFormBlock @if (email) {
(onInit)="addEmailGroup($event)" <app-email-form-block
(onDestroy)="removeEmailGroup()" #emailFormBlock
[data]="data?.email" (onInit)="addEmailGroup($event)"
[requiredMark]="emailRequiredMark" (onDestroy)="removeEmailGroup()"
[validatorFns]="emailValidationFns" [data]="data?.email"
[readonly]="readonly" [requiredMark]="emailRequiredMark"
></app-email-form-block> [validatorFns]="emailValidationFns"
<app-phone-numbers-form-block [readonly]="readonly"
*ngIf="phoneNumbers" ></app-email-form-block>
(onInit)="addPhoneNumbersGroup($event)" }
(onDestroy)="removePhoneNumbersGroup()" @if (phoneNumbers) {
[readonly]="readonly" <app-phone-numbers-form-block
> (onInit)="addPhoneNumbersGroup($event)"
[tabIndexStart]="emailFormBlock?.tabIndexEnd+1" [requiredMarks]="phoneNumbersRequiredMarks" [validatorFns]="phoneNumbersValidatorFns"> (onDestroy)="removePhoneNumbersGroup()"
</app-phone-numbers-form-block> [readonly]="readonly"
>
[tabIndexStart]="emailFormBlock?.tabIndexEnd+1" [requiredMarks]="phoneNumbersRequiredMarks" [validatorFns]="phoneNumbersValidatorFns">
</app-phone-numbers-form-block>
}
</div>
</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-description">Geben Sie Interessen an, um Ihre persönlichen Kontoangaben zu verfeinern.</div>
<div class="interests-wrapper" [formGroup]="control"> <div class="interests-wrapper" [formGroup]="control">
<shared-checkbox @for (pair of interests | keyvalue; track pair; let idx = $index) {
*ngFor="let pair of interests | keyvalue; let idx = index" <shared-checkbox
[formControlName]="pair.key" [formControlName]="pair.key"
[tabindex]="tabIndexStart + idx" [tabindex]="tabIndexStart + idx"
[autofocus]="focusAfterInit" [autofocus]="focusAfterInit"
[readonly]="readonly" [readonly]="readonly"
> >
{{ pair.value }} {{ pair.value }}
</shared-checkbox> </shared-checkbox>
}
</div> </div>

View File

@@ -6,8 +6,10 @@
[readonly]="readonly" [readonly]="readonly"
[tabindex]="tabIndexStart" [tabindex]="tabIndexStart"
[autofocus]="focusAfterInit" [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-select>
</shared-form-control> </shared-form-control>
@@ -30,7 +32,7 @@
formControlName="lastName" formControlName="lastName"
[tabindex]="tabIndexStart + 2" [tabindex]="tabIndexStart + 2"
[readonly]="readonly" [readonly]="readonly"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control label="Vorname"> <shared-form-control label="Vorname">
@@ -41,6 +43,6 @@
formControlName="firstName" formControlName="firstName"
[tabindex]="tabIndexStart + 3" [tabindex]="tabIndexStart + 3"
[readonly]="readonly" [readonly]="readonly"
/> />
</shared-form-control> </shared-form-control>
</ng-container> </ng-container>

View File

@@ -6,30 +6,30 @@
type="text" type="text"
formControlName="name" formControlName="name"
[tabindex]="tabIndexStart" [tabindex]="tabIndexStart"
[readonly]="readonly" [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>
<shared-form-control label="USt-ID"> @if (appearence === 'default') {
<input <shared-form-control label="Abteilung">
placeholder="USt-ID" <input
class="input-control" placeholder="Abteilung"
type="text" class="input-control"
formControlName="vatId" type="text"
[tabindex]="tabIndexStart + 2" formControlName="department"
[readonly]="readonly" [tabindex]="tabIndexStart + 1"
/> [readonly]="readonly"
</shared-form-control> />
</ng-container> </shared-form-control>
</ng-container> <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" [formControl]="control"
[tabindex]="tabIndexStart" [tabindex]="tabIndexStart"
[readonly]="readonly" [readonly]="readonly"
/> />
</shared-form-control> </shared-form-control>
<button type="button" *ngIf="!readonly && canScan()" (click)="scan()"> @if (!readonly && canScan()) {
<shared-icon icon="barcode-scan" [size]="32"></shared-icon> <button type="button" (click)="scan()">
</button> <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 class="wrapper text-center" [@cardFlip]="state" (@cardFlip.done)="flipAnimationDone($event)">
<div *ngIf="cardDetails" class="card-main"> @if (cardDetails) {
<div class="icons text-brand"> <div class="card-main">
<button *ngIf="isCustomerCard && frontside" class="icon-barcode" (click)="flipCard()"> <div class="icons text-brand">
<shared-icon [size]="35" icon="barcode-scanner"></shared-icon> @if (isCustomerCard && frontside) {
</button> <button class="icon-barcode" (click)="flipCard()">
<button *ngIf="isCustomerCard && !frontside" class="icon-back" (click)="flipCard()"> <shared-icon [size]="35" icon="barcode-scanner"></shared-icon>
<shared-icon [size]="35" icon="refresh"></shared-icon> </button>
</button> }
<!-- <div *ngIf="!isCustomerCard" class="icon-delete"><ui-icon (click)="onDeletePartnerCard()" size="25px" icon="trash"></ui-icon></div> --> @if (isCustomerCard && !frontside) {
</div> <button class="icon-back" (click)="flipCard()">
<div class="headline"> <shared-icon [size]="35" icon="refresh"></shared-icon>
<p *ngIf="isCustomerCard && frontside">Ihre Lesepunkte</p> </button>
<p *ngIf="isCustomerCard && !frontside">Kartennummer</p> }
<p *ngIf="!isCustomerCard">Partnerkartennummer</p> <!-- <div *ngIf="!isCustomerCard" class="icon-delete"><ui-icon (click)="onDeletePartnerCard()" size="25px" icon="trash"></ui-icon></div> -->
</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" />
</div> </div>
<div *ngIf="isCustomerCard && frontside"> <div class="headline">
<button class="button" (click)="onRewardShop()">Zum Prämienshop</button> @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>
</div> }
<div class="card-bottom"> <div class="card-bottom">
<div *ngIf="!isCustomerCard || (isCustomerCard && !frontside)" class="customer-name"> @if (!isCustomerCard || (isCustomerCard && !frontside)) {
<p>{{ cardDetails.firstName }} {{ cardDetails.lastName }}</p> <div class="customer-name">
</div> <p>{{ cardDetails.firstName }} {{ cardDetails.lastName }}</p>
<div *ngIf="isCustomerCard && frontside" class="logo ml-2"> </div>
<img class="logo-picture" src="/assets/images/Hugendubel_Logo.png" alt="Hugendubel Logo" /> }
</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>
</div> </div>

View File

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

View File

@@ -1,89 +1,83 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()"> @if (formData$ | async; as data) {
<h1 class="title">Kundendaten erfassen</h1> <form (keydown.enter)="$event.preventDefault()">
<p class="description"> <h1 class="title">Kundendaten erfassen</h1>
Um Ihnen den ausgewählten Service zu <p class="description">
<br /> Um Ihnen den ausgewählten Service zu
ermöglichen, legen wir Ihnen gerne <br />
<br /> ermöglichen, legen wir Ihnen gerne
ein Kundenkonto an. <br />
</p> ein Kundenkonto an.
</p>
<app-customer-type-selector <app-customer-type-selector
[processId]="processId$ | async" [processId]="processId$ | async"
[p4mUser]="false" [p4mUser]="false"
customerType="b2b" customerType="b2b"
(valueChanges)="customerTypeChanged($event)" (valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector> ></app-customer-type-selector>
<app-organisation-form-block
<app-organisation-form-block #orga
#orga [tabIndexStart]="1"
[tabIndexStart]="1" [data]="data.organisation"
[data]="data.organisation" (dataChanges)="patchFormData('organisation', $event)"
(dataChanges)="patchFormData('organisation', $event)" (onInit)="addFormBlock('organisation', $event)"
(onInit)="addFormBlock('organisation', $event)" [requiredMarks]="organisationFormBlockRequiredMarks"
[requiredMarks]="organisationFormBlockRequiredMarks" [validatorFns]="organisationFormBlockValidators"
[validatorFns]="organisationFormBlockValidators" ></app-organisation-form-block>
></app-organisation-form-block> <app-name-form-block
#name
<app-name-form-block [tabIndexStart]="orga.tabIndexEnd + 1"
#name [data]="data.name"
[tabIndexStart]="orga.tabIndexEnd + 1" (dataChanges)="patchFormData('name', $event)"
[data]="data.name" (onInit)="addFormBlock('name', $event)"
(dataChanges)="patchFormData('name', $event)" ></app-name-form-block>
(onInit)="addFormBlock('name', $event)" <app-address-form-block
></app-name-form-block> #address
[tabIndexStart]="name.tabIndexEnd + 1"
<app-address-form-block [data]="data.address"
#address (dataChanges)="patchFormData('address', $event)"
[tabIndexStart]="name.tabIndexEnd + 1" (onInit)="addFormBlock('address', $event)"
[data]="data.address" [requiredMarks]="addressRequiredMarks"
(dataChanges)="patchFormData('address', $event)" [validatorFns]="addressValidators"
(onInit)="addFormBlock('address', $event)" [defaults]="{ country: 'DEU' }"
[requiredMarks]="addressRequiredMarks" ></app-address-form-block>
[validatorFns]="addressValidators" <app-email-form-block
[defaults]="{ country: 'DEU' }" #email
></app-address-form-block> [tabIndexStart]="address.tabIndexEnd + 1"
[data]="data.email"
<app-email-form-block (dataChanges)="patchFormData('email', $event)"
#email [validatorFns]="emailFormBlockValidators"
[tabIndexStart]="address.tabIndexEnd + 1" (onInit)="addFormBlock('email', $event)"
[data]="data.email" ></app-email-form-block>
(dataChanges)="patchFormData('email', $event)" <app-phone-numbers-form-block
[validatorFns]="emailFormBlockValidators" #phoneNumbers
(onInit)="addFormBlock('email', $event)" [tabIndexStart]="email.tabIndexEnd + 1"
></app-email-form-block> [data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)"
<app-phone-numbers-form-block (onInit)="addFormBlock('phoneNumbers', $event)"
#phoneNumbers ></app-phone-numbers-form-block>
[tabIndexStart]="email.tabIndexEnd + 1" <app-deviating-address-form-block
[data]="data.phoneNumbers" [tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(dataChanges)="patchFormData('phoneNumbers', $event)" [data]="data.deviatingDeliveryAddress"
(onInit)="addFormBlock('phoneNumbers', $event)" (dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
></app-phone-numbers-form-block> (onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="deviatingNameRequiredMarks"
<app-deviating-address-form-block [nameValidatorFns]="deviatingNameValidationFns"
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1" [addressRequiredMarks]="addressRequiredMarks"
[data]="data.deviatingDeliveryAddress" [addressValidatorFns]="addressValidators"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)" [organisationRequiredMarks]="organisationFormBlockRequiredMarks"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)" [organisationValidatorFns]="organisationFormBlockValidators"
[nameRequiredMarks]="deviatingNameRequiredMarks" [defaults]="{ address: { country: 'DEU' } }"
[nameValidatorFns]="deviatingNameValidationFns" [organisation]="true"
[addressRequiredMarks]="addressRequiredMarks" [email]="true"
[addressValidatorFns]="addressValidators" [phoneNumbers]="true"
[organisationRequiredMarks]="organisationFormBlockRequiredMarks" >
[organisationValidatorFns]="organisationFormBlockValidators" Die Lieferadresse weicht von der Rechnungsadresse ab
[defaults]="{ address: { country: 'DEU' } }" </app-deviating-address-form-block>
[organisation]="true" <div class="spacer"></div>
[email]="true" <div class="sticky w-full flex items-center justify-center">
[phoneNumbers]="true" <button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
> <ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
Die Lieferadresse weicht von der Rechnungsadresse ab </button>
</app-deviating-address-form-block> </div>
</form>
<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 { Component, ChangeDetectionStrategy } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router'; import { ActivatedRoute, RouterModule } from '@angular/router';
import { CustomerCreateSideViewModule } from './customer-create-side-view'; import { CustomerCreateSideViewModule } from './customer-create-side-view';
@@ -10,7 +10,7 @@ import { SharedSplitscreenComponent } from '@shared/components/splitscreen';
templateUrl: 'create-customer.component.html', templateUrl: 'create-customer.component.html',
styleUrls: ['create-customer.component.css'], styleUrls: ['create-customer.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, RouterModule, SharedSplitscreenComponent, CustomerCreateSideViewModule], imports: [RouterModule, SharedSplitscreenComponent, CustomerCreateSideViewModule],
}) })
export class CreateCustomerComponent { export class CreateCustomerComponent {
processId$ = this._activatedRoute.parent.data.pipe(map((data) => data.processId)); 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()"> @if (formData$ | async; as data) {
<h1 class="title">Kundendaten erfassen</h1> <form (keydown.enter)="$event.preventDefault()">
<p class="description"> <h1 class="title">Kundendaten erfassen</h1>
Um Ihnen den ausgewählten Service <p class="description">
<br /> Um Ihnen den ausgewählten Service
zu ermöglichen, legen wir Ihnen <br />
<br /> zu ermöglichen, legen wir Ihnen
gerne ein Kundenkonto an. <br />
<br /> gerne ein Kundenkonto an.
</p> <br />
</p>
<app-customer-type-selector <app-customer-type-selector
[processId]="processId$ | async" [processId]="processId$ | async"
[p4mUser]="false" [p4mUser]="false"
customerType="guest" customerType="guest"
(valueChanges)="customerTypeChanged($event)" (valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector> ></app-customer-type-selector>
<app-name-form-block
<app-name-form-block #name
#name [tabIndexStart]="1"
[tabIndexStart]="1" [data]="data.name"
[data]="data.name" (dataChanges)="patchFormData('name', $event)"
(dataChanges)="patchFormData('name', $event)" (onInit)="addFormBlock('name', $event)"
(onInit)="addFormBlock('name', $event)" [requiredMarks]="nameRequiredMarks"
[requiredMarks]="nameRequiredMarks" [validatorFns]="nameValidationFns"
[validatorFns]="nameValidationFns" ></app-name-form-block>
></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
<p class="info"> Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der die Übermittlungskosten nach den Basistarifen entstehen.
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als </p>
die Übermittlungskosten nach den Basistarifen entstehen. <app-email-form-block
</p> #email
[tabIndexStart]="name.tabIndexEnd + 1"
<app-email-form-block [data]="data.email"
#email [requiredMark]="true"
[tabIndexStart]="name.tabIndexEnd + 1" (dataChanges)="patchFormData('email', $event)"
[data]="data.email" [validatorFns]="emailFormBlockValidators"
[requiredMark]="true" (onInit)="addFormBlock('email', $event)"
(dataChanges)="patchFormData('email', $event)" ></app-email-form-block>
[validatorFns]="emailFormBlockValidators" <app-organisation-form-block
(onInit)="addFormBlock('email', $event)" #orga
></app-email-form-block> [tabIndexStart]="email.tabIndexStart + 1"
[data]="data.organisation"
<app-organisation-form-block (dataChanges)="patchFormData('organisation', $event)"
#orga (onInit)="addFormBlock('organisation', $event)"
[tabIndexStart]="email.tabIndexStart + 1" appearence="compact"
[data]="data.organisation" ></app-organisation-form-block>
(dataChanges)="patchFormData('organisation', $event)" <app-address-form-block
(onInit)="addFormBlock('organisation', $event)" #address
appearence="compact" [tabIndexStart]="orga.tabIndexEnd + 1"
></app-organisation-form-block> [data]="data.address"
(dataChanges)="patchFormData('address', $event)"
<app-address-form-block (onInit)="addFormBlock('address', $event)"
#address [requiredMarks]="addressRequiredMarks"
[tabIndexStart]="orga.tabIndexEnd + 1" [validatorFns]="addressValidators"
[data]="data.address" [defaults]="{ country: 'DEU' }"
(dataChanges)="patchFormData('address', $event)" ></app-address-form-block>
(onInit)="addFormBlock('address', $event)" <app-phone-numbers-form-block
[requiredMarks]="addressRequiredMarks" #phoneNumbers
[validatorFns]="addressValidators" [tabIndexStart]="address.tabIndexEnd + 1"
[defaults]="{ country: 'DEU' }" [data]="data.phoneNumbers"
></app-address-form-block> (dataChanges)="patchFormData('phoneNumbers', $event)"
(onInit)="addFormBlock('phoneNumbers', $event)"
<app-phone-numbers-form-block ></app-phone-numbers-form-block>
#phoneNumbers <app-birth-date-form-block
[tabIndexStart]="address.tabIndexEnd + 1" #birthDate
[data]="data.phoneNumbers" [tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(dataChanges)="patchFormData('phoneNumbers', $event)" (onInit)="addFormBlock('birthDate', $event)"
(onInit)="addFormBlock('phoneNumbers', $event)" [data]="data.birthDate"
></app-phone-numbers-form-block> (dataChanges)="patchFormData('birthDate', $event)"
></app-birth-date-form-block>
<app-birth-date-form-block <app-deviating-address-form-block
#birthDate [tabIndexStart]="birthDate.tabIndexEnd + 1"
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1" [data]="data.deviatingDeliveryAddress"
(onInit)="addFormBlock('birthDate', $event)" (dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
[data]="data.birthDate" (onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
(dataChanges)="patchFormData('birthDate', $event)" [nameRequiredMarks]="deviatingNameRequiredMarks"
></app-birth-date-form-block> [nameValidatorFns]="deviatingNameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
<app-deviating-address-form-block [addressValidatorFns]="addressValidators"
[tabIndexStart]="birthDate.tabIndexEnd + 1" [defaults]="{ address: { country: 'DEU' } }"
[data]="data.deviatingDeliveryAddress" [organisation]="true"
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)" >
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)" Die Lieferadresse weicht von der Rechnungsadresse ab
[nameRequiredMarks]="deviatingNameRequiredMarks" </app-deviating-address-form-block>
[nameValidatorFns]="deviatingNameValidationFns" <div class="spacer"></div>
[addressRequiredMarks]="addressRequiredMarks" <div class="sticky w-full flex items-center justify-center">
[addressValidatorFns]="addressValidators" <button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
[defaults]="{ address: { country: 'DEU' } }" <ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
[organisation]="true" </button>
> </div>
Die Lieferadresse weicht von der Rechnungsadresse ab </form>
</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()"> @if (formData$ | async; as data) {
<h1 class="title flex flex-row items-center justify-center"> <form (keydown.enter)="$event.preventDefault()">
Kundendaten erfassen <h1 class="title flex flex-row items-center justify-center">
<!-- <span Kundendaten erfassen
class="rounded-full ml-4 h-8 w-8 text-xl text-center border-2 border-solid border-brand text-brand">i</span> --> <!-- <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> </h1>
<p class="description"> <p class="description">
Um Sie als Kunde beim nächsten Um Sie als Kunde beim nächsten
<br /> <br />
@@ -12,7 +12,6 @@
<br /> <br />
wir Ihnen gerne eine Kundenkarte an. wir Ihnen gerne eine Kundenkarte an.
</p> </p>
<app-customer-type-selector <app-customer-type-selector
[processId]="processId$ | async" [processId]="processId$ | async"
[p4mUser]="true" [p4mUser]="true"
@@ -20,7 +19,6 @@
(valueChanges)="customerTypeChanged($event)" (valueChanges)="customerTypeChanged($event)"
[p4mReadonly]="data?._meta?.p4mRequired" [p4mReadonly]="data?._meta?.p4mRequired"
></app-customer-type-selector> ></app-customer-type-selector>
<app-p4m-number-form-block <app-p4m-number-form-block
#p4mBlock #p4mBlock
[tabIndexStart]="1" [tabIndexStart]="1"
@@ -31,7 +29,6 @@
[focusAfterInit]="!data?._meta?.p4mRequired" [focusAfterInit]="!data?._meta?.p4mRequired"
[asyncValidatorFns]="asyncLoyaltyCardValidatorFn" [asyncValidatorFns]="asyncLoyaltyCardValidatorFn"
></app-p4m-number-form-block> ></app-p4m-number-form-block>
<app-accept-agb-form-block <app-accept-agb-form-block
[tabIndexStart]="inBlock.tabIndexEnd + 1" [tabIndexStart]="inBlock.tabIndexEnd + 1"
(onInit)="addFormBlock('agb', $event)" (onInit)="addFormBlock('agb', $event)"
@@ -40,7 +37,6 @@
[requiredMark]="true" [requiredMark]="true"
[validatorFns]="agbValidatorFns" [validatorFns]="agbValidatorFns"
></app-accept-agb-form-block> ></app-accept-agb-form-block>
<app-newsletter-form-block <app-newsletter-form-block
class="mb-4" class="mb-4"
#newsletterBlock #newsletterBlock
@@ -50,7 +46,6 @@
(dataChanges)="patchFormData('newsletter', $event)" (dataChanges)="patchFormData('newsletter', $event)"
[focusAfterInit]="data?._meta?.p4mRequired" [focusAfterInit]="data?._meta?.p4mRequired"
></app-newsletter-form-block> ></app-newsletter-form-block>
<app-name-form-block <app-name-form-block
#nameBlock #nameBlock
[tabIndexStart]="newsletterBlock.tabIndexEnd + 1" [tabIndexStart]="newsletterBlock.tabIndexEnd + 1"
@@ -60,13 +55,13 @@
[validatorFns]="nameValidationFns" [validatorFns]="nameValidationFns"
(dataChanges)="patchFormData('name', $event)" (dataChanges)="patchFormData('name', $event)"
></app-name-form-block> ></app-name-form-block>
@if (customerType === 'webshop-p4m') {
<p class="info" *ngIf="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 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 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. die Übermittlungskosten nach den Basistarifen entstehen.
</p> </p>
}
<app-email-form-block <app-email-form-block
class="flex-grow" class="flex-grow"
#email #email
@@ -78,7 +73,6 @@
[validatorFns]="emailValidatorFn" [validatorFns]="emailValidatorFn"
[asyncValidatorFns]="asyncEmailVlaidtorFn" [asyncValidatorFns]="asyncEmailVlaidtorFn"
></app-email-form-block> ></app-email-form-block>
<app-organisation-form-block <app-organisation-form-block
#orgBlock #orgBlock
[tabIndexStart]="email.tabIndexEnd + 1" [tabIndexStart]="email.tabIndexEnd + 1"
@@ -87,7 +81,6 @@
[data]="data.organisation" [data]="data.organisation"
(dataChanges)="patchFormData('organisation', $event)" (dataChanges)="patchFormData('organisation', $event)"
></app-organisation-form-block> ></app-organisation-form-block>
<app-address-form-block <app-address-form-block
[defaults]="{ country: 'DEU' }" [defaults]="{ country: 'DEU' }"
#addressBlock #addressBlock
@@ -98,7 +91,6 @@
[requiredMarks]="addressRequiredMarks" [requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidatorFns" [validatorFns]="addressValidatorFns"
></app-address-form-block> ></app-address-form-block>
<app-deviating-address-form-block <app-deviating-address-form-block
#ddaBlock #ddaBlock
[defaults]="{ address: { country: 'DEU' } }" [defaults]="{ address: { country: 'DEU' } }"
@@ -110,10 +102,9 @@
[nameValidatorFns]="nameValidationFns" [nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="shippingAddressRequiredMarks" [addressRequiredMarks]="shippingAddressRequiredMarks"
[addressValidatorFns]="shippingAddressValidators" [addressValidatorFns]="shippingAddressValidators"
> >
Die Lieferadresse weicht von der Rechnungsadresse ab Die Lieferadresse weicht von der Rechnungsadresse ab
</app-deviating-address-form-block> </app-deviating-address-form-block>
<app-phone-numbers-form-block <app-phone-numbers-form-block
#phoneNumbers #phoneNumbers
[tabIndexStart]="ddaBlock.tabIndexEnd + 1" [tabIndexStart]="ddaBlock.tabIndexEnd + 1"
@@ -121,7 +112,6 @@
[data]="data.phoneNumbers" [data]="data.phoneNumbers"
(dataChanges)="patchFormData('phoneNumbers', $event)" (dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block> ></app-phone-numbers-form-block>
<app-birth-date-form-block <app-birth-date-form-block
#bdBlock #bdBlock
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1" [tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
@@ -131,7 +121,6 @@
[requiredMark]="true" [requiredMark]="true"
[validatorFns]="birthDateValidatorFns" [validatorFns]="birthDateValidatorFns"
></app-birth-date-form-block> ></app-birth-date-form-block>
<app-interests-form-block <app-interests-form-block
#inBlock #inBlock
[tabIndexStart]="bdBlock.tabIndexEnd + 1" [tabIndexStart]="bdBlock.tabIndexEnd + 1"
@@ -139,12 +128,11 @@
[data]="data.interests" [data]="data.interests"
(dataChanges)="patchFormData('interests', $event)" (dataChanges)="patchFormData('interests', $event)"
></app-interests-form-block> ></app-interests-form-block>
<div class="spacer"></div> <div class="spacer"></div>
<div class="sticky w-full flex items-center justify-center"> <div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()"> <button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner> <ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button> </button>
</div> </div>
</form> </form>
}

View File

@@ -1,86 +1,78 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()"> @if (formData$ | async; as data) {
<h1 class="title">Kundendaten erfassen</h1> <form (keydown.enter)="$event.preventDefault()">
<p class="description">Wir legen Ihnen gerne ein Kundenkonto an</p> <h1 class="title">Kundendaten erfassen</h1>
<p class="description">Wir legen Ihnen gerne ein Kundenkonto an</p>
<app-customer-type-selector <app-customer-type-selector
[processId]="processId$ | async" [processId]="processId$ | async"
[p4mUser]="false" [p4mUser]="false"
customerType="store" customerType="store"
(valueChanges)="customerTypeChanged($event)" (valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector> ></app-customer-type-selector>
<app-name-form-block
<app-name-form-block #name
#name [tabIndexStart]="1"
[tabIndexStart]="1" (onInit)="addFormBlock('name', $event)"
(onInit)="addFormBlock('name', $event)" [requiredMarks]="nameRequiredMarks"
[requiredMarks]="nameRequiredMarks" [validatorFns]="nameValidationFns"
[validatorFns]="nameValidationFns" [data]="data.name"
[data]="data.name" (dataChanges)="patchFormData('name', $event)"
(dataChanges)="patchFormData('name', $event)" ></app-name-form-block>
></app-name-form-block> <app-email-form-block
#email
<app-email-form-block [tabIndexStart]="name.tabIndexEnd + 1"
#email [validatorFns]="emailFormBlockValidators"
[tabIndexStart]="name.tabIndexEnd + 1" (onInit)="addFormBlock('email', $event)"
[validatorFns]="emailFormBlockValidators" [data]="data.email"
(onInit)="addFormBlock('email', $event)" (dataChanges)="patchFormData('email', $event)"
[data]="data.email" ></app-email-form-block>
(dataChanges)="patchFormData('email', $event)" <app-organisation-form-block
></app-email-form-block> #orga
[tabIndexStart]="email.tabIndexEnd + 1"
<app-organisation-form-block appearence="compact"
#orga (onInit)="addFormBlock('organisation', $event)"
[tabIndexStart]="email.tabIndexEnd + 1" [data]="data.organisation"
appearence="compact" (dataChanges)="patchFormData('organisation', $event)"
(onInit)="addFormBlock('organisation', $event)" ></app-organisation-form-block>
[data]="data.organisation" <app-address-form-block
(dataChanges)="patchFormData('organisation', $event)" #address
></app-organisation-form-block> [tabIndexStart]="orga.tabIndexEnd + 1"
(onInit)="addFormBlock('address', $event)"
<app-address-form-block [data]="data.address"
#address (dataChanges)="patchFormData('address', $event)"
[tabIndexStart]="orga.tabIndexEnd + 1" ></app-address-form-block>
(onInit)="addFormBlock('address', $event)" <app-phone-numbers-form-block
[data]="data.address" #phoneNumbers
(dataChanges)="patchFormData('address', $event)" [tabIndexStart]="address.tabIndexEnd + 1"
></app-address-form-block> (onInit)="addFormBlock('phoneNumbers', $event)"
[data]="data.phoneNumbers"
<app-phone-numbers-form-block (dataChanges)="patchFormData('phoneNumbers', $event)"
#phoneNumbers ></app-phone-numbers-form-block>
[tabIndexStart]="address.tabIndexEnd + 1" <app-birth-date-form-block
(onInit)="addFormBlock('phoneNumbers', $event)" #birthDate
[data]="data.phoneNumbers" [tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(dataChanges)="patchFormData('phoneNumbers', $event)" (onInit)="addFormBlock('birthDate', $event)"
></app-phone-numbers-form-block> [data]="data.birthDate"
(dataChanges)="patchFormData('birthDate', $event)"
<app-birth-date-form-block ></app-birth-date-form-block>
#birthDate <app-deviating-address-form-block
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1" [tabIndexStart]="birthDate.tabIndexEnd + 1"
(onInit)="addFormBlock('birthDate', $event)" (onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[data]="data.birthDate" [organisation]="true"
(dataChanges)="patchFormData('birthDate', $event)" [nameRequiredMarks]="nameRequiredMarks"
></app-birth-date-form-block> [nameValidatorFns]="nameValidationFns"
[addressRequiredMarks]="addressRequiredMarks"
<app-deviating-address-form-block [addressValidatorFns]="deviatingAddressValidators"
[tabIndexStart]="birthDate.tabIndexEnd + 1" [defaults]="{ address: { country: 'DEU' } }"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)" [data]="data.deviatingDeliveryAddress"
[organisation]="true" (dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
[nameRequiredMarks]="nameRequiredMarks" >
[nameValidatorFns]="nameValidationFns" Die Lieferadresse weicht von der Rechnungsadresse ab
[addressRequiredMarks]="addressRequiredMarks" </app-deviating-address-form-block>
[addressValidatorFns]="deviatingAddressValidators" <div class="spacer"></div>
[defaults]="{ address: { country: 'DEU' } }" <div class="sticky w-full flex items-center justify-center">
[data]="data.deviatingDeliveryAddress" <button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)" <ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
> </button>
Die Lieferadresse weicht von der Rechnungsadresse ab </div>
</app-deviating-address-form-block> </form>
}
<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()"> @if (formData$ | async; as data) {
<h1 class="title">Kundendaten erfassen</h1> <form (keydown.enter)="$event.preventDefault()">
<p class="description"> <h1 class="title">Kundendaten erfassen</h1>
Wenn Sie möchten legen wir Ihnen <p class="description">
<br /> Wenn Sie möchten legen wir Ihnen
gerne ein Onlinekonto an. Dort können <br />
<br /> gerne ein Onlinekonto an. Dort können
Sie Ihre Bestellungen einsehen. <br />
</p> Sie Ihre Bestellungen einsehen.
</p>
<app-customer-type-selector <app-customer-type-selector
[processId]="processId$ | async" [processId]="processId$ | async"
[p4mUser]="false" [p4mUser]="false"
customerType="webshop" customerType="webshop"
(valueChanges)="customerTypeChanged($event)" (valueChanges)="customerTypeChanged($event)"
></app-customer-type-selector> ></app-customer-type-selector>
<app-name-form-block
<app-name-form-block #name
#name [tabIndexStart]="1"
[tabIndexStart]="1" (onInit)="addFormBlock('name', $event)"
(onInit)="addFormBlock('name', $event)" [requiredMarks]="nameRequiredMarks"
[requiredMarks]="nameRequiredMarks" [validatorFns]="nameValidationFns"
[validatorFns]="nameValidationFns" [data]="data.name"
[data]="data.name" (dataChanges)="patchFormData('name', $event)"
(dataChanges)="patchFormData('name', $event)" ></app-name-form-block>
></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
<p class="info"> Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der die Übermittlungskosten nach den Basistarifen entstehen.
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als </p>
die Übermittlungskosten nach den Basistarifen entstehen. <app-email-form-block
</p> #email
[tabIndexStart]="name.tabIndexEnd + 1"
<app-email-form-block (onInit)="addFormBlock('email', $event)"
#email [requiredMark]="true"
[tabIndexStart]="name.tabIndexEnd + 1" [asyncValidatorFns]="asyncEmailValidatorFns"
(onInit)="addFormBlock('email', $event)" [validatorFns]="emailValidatorFns"
[requiredMark]="true" [data]="data.email"
[asyncValidatorFns]="asyncEmailValidatorFns" (dataChanges)="patchFormData('email', $event)"
[validatorFns]="emailValidatorFns" ></app-email-form-block>
[data]="data.email" <app-organisation-form-block
(dataChanges)="patchFormData('email', $event)" #org
></app-email-form-block> [tabIndexStart]="email.tabIndexEnd + 1"
appearence="compact"
<app-organisation-form-block (onInit)="addFormBlock('organisation', $event)"
#org [data]="data.organisation"
[tabIndexStart]="email.tabIndexEnd + 1" (dataChanges)="patchFormData('organisation', $event)"
appearence="compact" ></app-organisation-form-block>
(onInit)="addFormBlock('organisation', $event)" <app-address-form-block
[data]="data.organisation" #address
(dataChanges)="patchFormData('organisation', $event)" [tabIndexStart]="org.tabIndexEnd + 1"
></app-organisation-form-block> [requiredMarks]="addressRequiredMarks"
[validatorFns]="addressValidators"
<app-address-form-block (onInit)="addFormBlock('address', $event)"
#address [defaults]="{ country: 'DEU' }"
[tabIndexStart]="org.tabIndexEnd + 1" [data]="data.address"
[requiredMarks]="addressRequiredMarks" (dataChanges)="patchFormData('address', $event)"
[validatorFns]="addressValidators" ></app-address-form-block>
(onInit)="addFormBlock('address', $event)" <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>
[defaults]="{ country: 'DEU' }" <app-phone-numbers-form-block
[data]="data.address" #phoneNumbers
(dataChanges)="patchFormData('address', $event)" [tabIndexStart]="address.tabIndexEnd + 1"
></app-address-form-block> (onInit)="addFormBlock('phoneNumbers', $event)"
[data]="data.phoneNumbers"
<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> (dataChanges)="patchFormData('phoneNumbers', $event)"
></app-phone-numbers-form-block>
<app-phone-numbers-form-block <app-birth-date-form-block
#phoneNumbers #birthDate
[tabIndexStart]="address.tabIndexEnd + 1" [tabIndexStart]="phoneNumbers.tabIndexEnd + 1"
(onInit)="addFormBlock('phoneNumbers', $event)" (onInit)="addFormBlock('birthDate', $event)"
[data]="data.phoneNumbers" [data]="data.birthDate"
(dataChanges)="patchFormData('phoneNumbers', $event)" (dataChanges)="patchFormData('birthDate', $event)"
></app-phone-numbers-form-block> ></app-birth-date-form-block>
<app-deviating-address-form-block
<app-birth-date-form-block [tabIndexStart]="birthDate.tabIndexEnd + 1"
#birthDate (onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
[tabIndexStart]="phoneNumbers.tabIndexEnd + 1" appearence="b2b"
(onInit)="addFormBlock('birthDate', $event)" [nameRequiredMarks]="nameRequiredMarks"
[data]="data.birthDate" [nameValidatorFns]="nameValidationFns"
(dataChanges)="patchFormData('birthDate', $event)" [addressRequiredMarks]="addressRequiredMarks"
></app-birth-date-form-block> [addressValidatorFns]="addressValidators"
[defaults]="{ address: { country: 'DEU' } }"
<app-deviating-address-form-block [data]="data.deviatingDeliveryAddress"
[tabIndexStart]="birthDate.tabIndexEnd + 1" (dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)" >
appearence="b2b" Die Lieferadresse weicht von der Rechnungsadresse ab
[nameRequiredMarks]="nameRequiredMarks" </app-deviating-address-form-block>
[nameValidatorFns]="nameValidationFns" <div class="spacer"></div>
[addressRequiredMarks]="addressRequiredMarks" <div class="sticky w-full flex items-center justify-center">
[addressValidatorFns]="addressValidators" <button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
[defaults]="{ address: { country: 'DEU' } }" <ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
[data]="data.deviatingDeliveryAddress" </button>
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)" </div>
> </form>
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 { Component, ChangeDetectionStrategy } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
@@ -7,7 +7,7 @@ import { RouterModule } from '@angular/router';
templateUrl: 'customer-create-side-view.component.html', templateUrl: 'customer-create-side-view.component.html',
styleUrls: ['customer-create-side-view.component.css'], styleUrls: ['customer-create-side-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, RouterModule], imports: [RouterModule],
}) })
export class CustomerCreateSideViewComponent { export class CustomerCreateSideViewComponent {
constructor() {} constructor() {}

View File

@@ -1,121 +1,109 @@
<form *ngIf="formData$ | async; let data" (keydown.enter)="$event.preventDefault()"> @if (formData$ | async; as data) {
<h1 class="title flex flex-row items-center justify-center">Kundenkartendaten erfasen</h1> <form (keydown.enter)="$event.preventDefault()">
<p class="description">Bitte erfassen Sie die Kundenkarte</p> <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 <app-customer-type-selector
[processId]="processId$ | async" [processId]="processId$ | async"
[p4mUser]="true" [p4mUser]="true"
customerType="webshop" customerType="webshop"
[readonly]="true" [readonly]="true"
></app-customer-type-selector> ></app-customer-type-selector>
<app-p4m-number-form-block
<app-p4m-number-form-block #p4mBlock
#p4mBlock [tabIndexStart]="1"
[tabIndexStart]="1" (onInit)="addFormBlock('p4m', $event)"
(onInit)="addFormBlock('p4m', $event)" [data]="data.p4m"
[data]="data.p4m" (dataChanges)="patchFormData('p4m', $event)"
(dataChanges)="patchFormData('p4m', $event)" [focusAfterInit]="!data?._meta?.p4mRequired"
[focusAfterInit]="!data?._meta?.p4mRequired" [asyncValidatorFns]="asyncLoyaltyCardValidatorFn"
[asyncValidatorFns]="asyncLoyaltyCardValidatorFn" ></app-p4m-number-form-block>
></app-p4m-number-form-block> <app-accept-agb-form-block
[tabIndexStart]="inBlock.tabIndexEnd + 1"
<app-accept-agb-form-block (onInit)="addFormBlock('agb', $event)"
[tabIndexStart]="inBlock.tabIndexEnd + 1" [data]="data.agb"
(onInit)="addFormBlock('agb', $event)" (dataChanges)="patchFormData('agb', $event)"
[data]="data.agb" [requiredMark]="true"
(dataChanges)="patchFormData('agb', $event)" [validatorFns]="agbValidatorFns"
[requiredMark]="true" ></app-accept-agb-form-block>
[validatorFns]="agbValidatorFns" <app-newsletter-form-block
></app-accept-agb-form-block> class="mb-4"
#newsletterBlock
<app-newsletter-form-block [tabIndexStart]="p4mBlock.tabIndexEnd + 1"
class="mb-4" (onInit)="addFormBlock('newsletter', $event)"
#newsletterBlock [data]="data.newsletter"
[tabIndexStart]="p4mBlock.tabIndexEnd + 1" (dataChanges)="patchFormData('newsletter', $event)"
(onInit)="addFormBlock('newsletter', $event)" [focusAfterInit]="data?._meta?.p4mRequired"
[data]="data.newsletter" ></app-newsletter-form-block>
(dataChanges)="patchFormData('newsletter', $event)" <app-name-form-block (onInit)="addFormBlock('name', $event)" [data]="data.name" readonly></app-name-form-block>
[focusAfterInit]="data?._meta?.p4mRequired" <app-email-form-block (onInit)="addFormBlock('email', $event)" [data]="data.email" readonly></app-email-form-block>
></app-newsletter-form-block> <app-organisation-form-block
(onInit)="addFormBlock('organisation', $event)"
<app-name-form-block (onInit)="addFormBlock('name', $event)" [data]="data.name" readonly></app-name-form-block> appearence="compact"
[data]="data.organisation"
<app-email-form-block (onInit)="addFormBlock('email', $event)" [data]="data.email" readonly></app-email-form-block> readonly
></app-organisation-form-block>
<app-organisation-form-block <app-address-form-block [data]="data.address" readonly></app-address-form-block>
(onInit)="addFormBlock('organisation', $event)" <div class="mt-8">
appearence="compact" <h4 class="-mb-6">Rechnungsadresse</h4>
[data]="data.organisation" <ui-form-control class="-mb-5" [showHint]="false">
readonly <input type="text" [value]="(billingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" />
></app-organisation-form-block> </ui-form-control>
<app-deviating-address-form-block
<app-address-form-block [data]="data.address" readonly></app-address-form-block> #dbaBlock
[defaults]="{ address: { country: 'DEU' } }"
<div class="mt-8"> [tabIndexStart]="newsletterBlock.tabIndexEnd + 1"
<h4 class="-mb-6">Rechnungsadresse</h4> (onInit)="addFormBlock('billingAddress', $event)"
<ui-form-control class="-mb-5" [showHint]="false"> [data]="data.billingAddress"
<input type="text" [value]="(billingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" /> (dataChanges)="patchFormData('billingAddress', $event)"
</ui-form-control> [nameRequiredMarks]="nameRequiredMarks"
<app-deviating-address-form-block [nameValidatorFns]="nameValidationFns"
#dbaBlock [addressRequiredMarks]="addressRequiredMarks"
[defaults]="{ address: { country: 'DEU' } }" [addressValidatorFns]="addressValidatorFns"
[tabIndexStart]="newsletterBlock.tabIndexEnd + 1" >
(onInit)="addFormBlock('billingAddress', $event)" Abweichende Rechnungsadresse anlegen
[data]="data.billingAddress" </app-deviating-address-form-block>
(dataChanges)="patchFormData('billingAddress', $event)" </div>
[nameRequiredMarks]="nameRequiredMarks" <div class="mt-8">
[nameValidatorFns]="nameValidationFns" <h4 class="-mb-6">Lieferadresse</h4>
[addressRequiredMarks]="addressRequiredMarks" <ui-form-control class="-mb-5" [showHint]="false">
[addressValidatorFns]="addressValidatorFns" <input type="text" [value]="(shippingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" />
> </ui-form-control>
Abweichende Rechnungsadresse anlegen <app-deviating-address-form-block
</app-deviating-address-form-block> #ddaBlock
</div> [defaults]="{ address: { country: 'DEU' } }"
[tabIndexStart]="dbaBlock.tabIndexEnd + 1"
<div class="mt-8"> (onInit)="addFormBlock('deviatingDeliveryAddress', $event)"
<h4 class="-mb-6">Lieferadresse</h4> [data]="data.deviatingDeliveryAddress"
<ui-form-control class="-mb-5" [showHint]="false"> (dataChanges)="patchFormData('deviatingDeliveryAddress', $event)"
<input type="text" [value]="(shippingAddress | address: true) ?? 'Keine Adresse vorhanden'" [readonly]="true" /> [nameRequiredMarks]="nameRequiredMarks"
</ui-form-control> [nameValidatorFns]="nameValidationFns"
<app-deviating-address-form-block [addressRequiredMarks]="addressRequiredMarks"
#ddaBlock [addressValidatorFns]="addressValidatorFns"
[defaults]="{ address: { country: 'DEU' } }" >
[tabIndexStart]="dbaBlock.tabIndexEnd + 1" Abweichende Lieferadresse anlegen
(onInit)="addFormBlock('deviatingDeliveryAddress', $event)" </app-deviating-address-form-block>
[data]="data.deviatingDeliveryAddress" </div>
(dataChanges)="patchFormData('deviatingDeliveryAddress', $event)" <app-birth-date-form-block
[nameRequiredMarks]="nameRequiredMarks" #bdBlock
[nameValidatorFns]="nameValidationFns" [tabIndexStart]="ddaBlock.tabIndexEnd + 1"
[addressRequiredMarks]="addressRequiredMarks" (onInit)="addFormBlock('birthDate', $event)"
[addressValidatorFns]="addressValidatorFns" [data]="data.birthDate"
> (dataChanges)="patchFormData('birthDate', $event)"
Abweichende Lieferadresse anlegen [requiredMark]="true"
</app-deviating-address-form-block> [validatorFns]="birthDateValidatorFns"
</div> ></app-birth-date-form-block>
<app-interests-form-block
<app-birth-date-form-block #inBlock
#bdBlock [tabIndexStart]="bdBlock.tabIndexEnd + 1"
[tabIndexStart]="ddaBlock.tabIndexEnd + 1" (onInit)="addFormBlock('interests', $event)"
(onInit)="addFormBlock('birthDate', $event)" [data]="data.interests"
[data]="data.birthDate" (dataChanges)="patchFormData('interests', $event)"
(dataChanges)="patchFormData('birthDate', $event)" ></app-interests-form-block>
[requiredMark]="true" <div class="spacer"></div>
[validatorFns]="birthDateValidatorFns" <div class="sticky w-full flex items-center justify-center">
></app-birth-date-form-block> <button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
<app-interests-form-block </button>
#inBlock </div>
[tabIndexStart]="bdBlock.tabIndexEnd + 1" </form>
(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"> <div class="flex flex-row justify-end -mt-4 -mr-2">
<a @if (detailsRoute$ | async; as detailsRoute) {
*ngIf="detailsRoute$ | async; let detailsRoute" <a
[routerLink]="detailsRoute.path" [routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams" [queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
> >
<shared-icon icon="close" [size]="32"></shared-icon> <shared-icon icon="close" [size]="32"></shared-icon>
</a> </a>
}
</div> </div>
<h1 class="text-2xl text-center font-bold mb-6">Rechnungsadresse hinzufügen</h1> <h1 class="text-2xl text-center font-bold mb-6">Rechnungsadresse hinzufügen</h1>
<form [formGroup]="formGroup" (ngSubmit)="save()"> <form [formGroup]="formGroup" (ngSubmit)="save()">
<shared-form-control label="Anrede"> <shared-form-control label="Anrede">
<shared-select formControlName="gender" placeholder="Anrede" tabindex="1" [autofocus]="true"> <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-select>
</shared-form-control> </shared-form-control>
@@ -62,9 +65,11 @@
<shared-form-control class="col-span-2" label="Land"> <shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="11"> <shared-select placeholder="Land" formControlName="country" tabindex="11">
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3"> @for (country of countries$ | async; track country) {
{{ country.name }} <shared-select-option [value]="country.isO3166_A_3">
</shared-select-option> {{ country.name }}
</shared-select-option>
}
</shared-select> </shared-select>
</shared-form-control> </shared-form-control>
@@ -76,7 +81,7 @@
[disabled]="formGroup.invalid || formGroup.disabled" [disabled]="formGroup.invalid || formGroup.disabled"
type="submit" type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white" class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
> >
Speichern Speichern
</button> </button>
</div> </div>

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ import { FormControlComponent } from '@shared/components/form-control';
import { CrmCustomerService } from '@domain/crm'; import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, Gender, ShippingAddressDTO } from '@generated/swagger/crm-api'; import { AddressDTO, Gender, ShippingAddressDTO } from '@generated/swagger/crm-api';
import { map, takeUntil } from 'rxjs/operators'; 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 { AddressSelectionModalService } from '@modal/address-selection';
import { CustomerSearchStore } from '../store'; import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation'; import { CustomerSearchNavigation } from '@shared/services/navigation';
@@ -27,13 +27,11 @@ import { validateCompanyOrPersonalInfoRequired } from '../../validators/gender-b
RouterLink, RouterLink,
IconComponent, IconComponent,
AsyncPipe, AsyncPipe,
NgIf,
NgForOf,
ReactiveFormsModule, ReactiveFormsModule,
SelectModule, SelectModule,
FormControlComponent, FormControlComponent,
CheckboxComponent, CheckboxComponent
], ],
}) })
export class AddShippingAddressMainViewComponent implements OnInit, OnDestroy { export class AddShippingAddressMainViewComponent implements OnInit, OnDestroy {
private _customerService = inject(CrmCustomerService); 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"> <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> <h3 class="font-bold text-xl">Rechnungsadresse</h3>
<a @if (addBillingAddressRoute$ | async; as addRoute) {
*ngIf="addBillingAddressRoute$ | async; let addRoute" <a
type="button" type="button"
class="text-brand font-bold" class="text-brand font-bold"
[routerLink]="addRoute.path" [routerLink]="addRoute.path"
[queryParams]="addRoute.queryParams" [queryParams]="addRoute.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
> >
Hinzufügen Hinzufügen
</a> </a>
}
</div> </div>
<div class="grid grid-flow-row"> <div class="grid grid-flow-row">
<label @if (showCustomerAddress$ | async) {
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 flex flex-row justify-between items-center" <label
*ngIf="showCustomerAddress$ | async" class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 flex flex-row justify-between items-center"
>
<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"
> >
Bearbeiten @if (isNotBusinessKonto$ | async) {
</a> <input
</div> name="assigned-payer"
</label> type="radio"
<label [checked]="!(selectedPayer$ | async)"
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row items-center justify-start" (change)="selectCustomerAddress()"
*ngFor="let assignedPayer of assignedPayers$ | async" />
> }
<input <div class="ml-2 flex flex-row justify-between items-start grow">
name="assigned-payer" <span class="mr-4">
type="radio" {{ customer$ | async | address }}
[value]="assignedPayer" </span>
[checked]="(selectedPayer$ | async)?.payer.id === assignedPayer.payer.id" @if (editRoute$ | async; as editRoute) {
(change)="selectPayer(assignedPayer)" <a
/> [routerLink]="editRoute.path"
<div class="ml-2 flex flex-row justify-between items-start grow"> [queryParams]="editRoute.queryParams"
<span class="mr-4"> [queryParamsHandling]="'merge'"
{{ assignedPayer.payer.data | address }} class="text-brand font-bold"
</span> type="button"
<ng-container *ngIf="canEditAddress$ | async"> >
<a Bearbeiten
*ngIf="editRoute(assignedPayer.payer.id); let editRoute" </a>
class="text-brand font-bold" }
[routerLink]="editRoute.path" </div>
[queryParams]="editRoute.queryParams" </label>
[queryParamsHandling]="'merge'" }
> @for (assignedPayer of assignedPayers$ | async; track assignedPayer) {
Bearbeiten <label
</a> class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row items-center justify-start"
</ng-container> >
</div> <input
</label> 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> </div>

View File

@@ -4,7 +4,7 @@ import { CrmCustomerService } from '@domain/crm';
import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators'; import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators';
import { Observable, Subject, combineLatest } from 'rxjs'; import { Observable, Subject, combineLatest } from 'rxjs';
import { AssignedPayerDTO, CustomerDTO, ListResponseArgsOfAssignedPayerDTO } from '@generated/swagger/crm-api'; 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 { CustomerPipesModule } from '@shared/pipes/customer';
import { ComponentStore } from '@ngrx/component-store'; import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators'; import { tapResponse } from '@ngrx/operators';
@@ -26,7 +26,7 @@ interface DetailsMainViewBillingAddressesComponentState {
styleUrls: ['details-main-view-billing-addresses.component.css'], styleUrls: ['details-main-view-billing-addresses.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-details-main-view-billing-addresses' }, host: { class: 'page-details-main-view-billing-addresses' },
imports: [NgIf, NgFor, AsyncPipe, CustomerPipesModule, RouterLink], imports: [AsyncPipe, CustomerPipesModule, RouterLink],
}) })
export class DetailsMainViewBillingAddressesComponent export class DetailsMainViewBillingAddressesComponent
extends ComponentStore<DetailsMainViewBillingAddressesComponentState> 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"> <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> <h3 class="font-bold text-xl">Lieferadresse</h3>
<a @if (addShippingAddressRoute$ | async; as addRoute) {
*ngIf="addShippingAddressRoute$ | async; let addRoute" <a
type="button" type="button"
class="text-brand font-bold" class="text-brand font-bold"
[routerLink]="addRoute.path" [routerLink]="addRoute.path"
[queryParams]="addRoute.queryParams" [queryParams]="addRoute.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
> >
Hinzufügen Hinzufügen
</a> </a>
}
</div> </div>
<div class="grid grid-flow-row"> <div class="grid grid-flow-row">
<label @if (showCustomerAddress$ | async) {
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center" <label
*ngIf="showCustomerAddress$ | async" class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
>
<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"
> >
Bearbeiten <input name="shipping-address" type="radio" [checked]="!(selectedShippingAddress$ | async)" (change)="selectCustomerAddress()" />
</a> <div class="ml-2 flex flex-row justify-between items-start grow">
</div> <span class="mr-4">
</label> {{ customer$ | async | address }}
<label </span>
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center" @if (editRoute$ | async; as editRoute) {
*ngFor="let shippingAddress of shippingAddresses$ | async" <a
> [routerLink]="editRoute.path"
<input [queryParams]="editRoute.queryParams"
name="shipping-address" [queryParamsHandling]="'merge'"
type="radio" class="text-brand font-bold"
[value]="shippingAddress" type="button"
[checked]="(selectedShippingAddress$ | async)?.id === shippingAddress.id" >
(change)="selectShippingAddress(shippingAddress)" Bearbeiten
/> </a>
<div class="ml-2 flex flex-row justify-between items-start grow"> }
<span class="mr-4"> </div>
{{ shippingAddress | address }} </label>
</span> }
<a @for (shippingAddress of shippingAddresses$ | async; track shippingAddress) {
*ngIf="editShippingAddressRoute$(shippingAddress.id) | async; let route" <label
class="text-brand font-bold" class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
type="button"
[routerLink]="route?.path"
[queryParams]="route?.queryParams"
[queryParamsHandling]="'merge'"
> >
Bearbeiten <input
</a> name="shipping-address"
</div> type="radio"
</label> [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> </div>

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,98 +1,105 @@
<div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1"> <div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1">
<a @if (detailsRoute$ | async; as route) {
*ngIf="detailsRoute$ | async; let route" <a
[routerLink]="route.path" [routerLink]="route.path"
[queryParams]="route.queryParams" [queryParams]="route.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
class="btn btn-label" class="btn btn-label"
> >
<ui-icon [icon]="'close'"></ui-icon> <ui-icon [icon]="'close'"></ui-icon>
</a> </a>
}
</div> </div>
<div class="header"> <div class="header">
<h1>Firmendetails</h1> <h1>Firmendetails</h1>
</div> </div>
<form *ngIf="control" [formGroup]="control" (ngSubmit)="submit()"> @if (control) {
<ng-container formGroupName="organisation"> <form [formGroup]="control" (ngSubmit)="submit()">
<ui-form-control label="Firmenname" variant="inline"> <ng-container formGroupName="organisation">
<input uiInput type="text" formControlName="name" tabindex="1" /> <ui-form-control label="Firmenname" variant="inline">
</ui-form-control> <input uiInput type="text" formControlName="name" tabindex="1" />
<ui-form-control label="Abteilung" variant="inline"> </ui-form-control>
<input uiInput type="text" formControlName="department" tabindex="2" /> <ui-form-control label="Abteilung" variant="inline">
</ui-form-control> <input uiInput type="text" formControlName="department" tabindex="2" />
<ui-form-control label="USt ID" variant="inline"> </ui-form-control>
<input uiInput type="text" formControlName="vatId" tabindex="3" /> <ui-form-control label="USt ID" variant="inline">
</ui-form-control> <input uiInput type="text" formControlName="vatId" tabindex="3" />
</ng-container> </ui-form-control>
</ng-container>
<ui-form-control [clearable]="true" label="Anrede" variant="inline"> <ui-form-control [clearable]="true" label="Anrede" variant="inline">
<ui-select formControlName="gender" tabindex="4"> <ui-select formControlName="gender" tabindex="4">
<ui-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value" [label]="gender.label"></ui-select-option> @for (gender of genderSettings.genders; track gender) {
</ui-select> <ui-select-option [value]="gender.value" [label]="gender.label"></ui-select-option>
</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>
</ui-select> </ui-select>
</ui-form-control> </ui-form-control>
</ng-container> <ui-form-control [clearable]="true" label="Titel" variant="inline">
<ui-select formControlName="title" tabindex="5">
<div class="actions"> <ui-select-option value="Dipl.-Ing." label="Dipl.-Ing."></ui-select-option>
<button class="btn-cancel" type="button" (click)="cancel()">Abbrechen</button> <ui-select-option value="Dr." label="Dr."></ui-select-option>
<button class="btn-save" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled"> <ui-select-option value="Dr. med." label="Dr. med."></ui-select-option>
<ng-container *ngSwitchCase="true">Speichern</ng-container> <ui-select-option value="Prof." label="Prof."></ui-select-option>
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon> <ui-select-option value="Prof. Dr." label="Prof. Dr."></ui-select-option>
</button> <ui-select-option value="RA" label="RA"></ui-select-option>
</div> </ui-select>
</form> </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"> <div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1">
<a @if (detailsRoute$ | async; as route) {
*ngIf="detailsRoute$ | async; let route" <a
[routerLink]="route.path" [routerLink]="route.path"
[queryParams]="route.queryParams" [queryParams]="route.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
class="btn btn-label" class="btn btn-label"
> >
<ui-icon [icon]="'close'"></ui-icon> <ui-icon [icon]="'close'"></ui-icon>
</a> </a>
}
</div> </div>
<div class="header"> <div class="header">
<h1>Kundendetails</h1> <h1>Kundendetails</h1>
</div> </div>
<form *ngIf="control" [formGroup]="control" (ngSubmit)="submit()"> @if (control) {
<ui-form-control [clearable]="true" label="Anrede" variant="inline"> <form [formGroup]="control" (ngSubmit)="submit()">
<ui-select formControlName="gender" tabindex="1"> <ui-form-control [clearable]="true" label="Anrede" variant="inline">
<ui-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value" [label]="gender.label"></ui-select-option> <ui-select formControlName="gender" tabindex="1">
</ui-select> @for (gender of genderSettings.genders; track gender) {
</ui-form-control> <ui-select-option [value]="gender.value" [label]="gender.label"></ui-select-option>
<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>
</ui-select> </ui-select>
</ui-form-control> </ui-form-control>
</ng-container> <ui-form-control [clearable]="true" label="Titel" variant="inline">
<ui-select formControlName="title" tabindex="2">
<ng-container formGroupName="communicationDetails"> <ui-select-option value="Dipl.-Ing." label="Dipl.-Ing."></ui-select-option>
<ui-form-control label="Festnetznummer" variant="inline"> <ui-select-option value="Dr." label="Dr."></ui-select-option>
<input uiInput type="tel" formControlName="phone" tabindex="12" /> <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>
<ui-form-control label="Mobilnummer" variant="inline"> <ui-form-control label="Nachname" variant="inline">
<input uiInput type="tel" formControlName="mobile" tabindex="13" /> <input uiInput type="text" formControlName="lastName" tabindex="3" />
</ui-form-control> </ui-form-control>
</ng-container> <ui-form-control label="Vorname" variant="inline">
<ui-form-control label="Geburtsdatum" variant="inline"> <input uiInput type="text" formControlName="firstName" tabindex="4" />
<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> </ui-form-control>
<ng-container *ngIf="!(isOnlineOrCustomerCardUser$ | async)"> <ui-form-control label="E-Mail" formGroupName="communicationDetails" variant="inline">
<ui-form-control label="Abteilung" variant="inline"> <input uiInput type="mail" formControlName="email" tabindex="5" />
<input uiInput type="text" formControlName="department" tabindex="16" /> </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>
<ui-form-control label="USt ID" variant="inline"> <ui-form-control label="Hausnummer" variant="inline">
<input uiInput type="text" formControlName="vatId" tabindex="17" /> <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> </ui-form-control>
</ng-container> </ng-container>
</ng-container> <ng-container formGroupName="communicationDetails">
<ui-form-control label="Festnetznummer" variant="inline">
<div class="actions"> <input uiInput type="tel" formControlName="phone" tabindex="12" />
<button class="btn-cancel" type="button" (click)="cancel()">Abbrechen</button> </ui-form-control>
<button class="btn-save" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled"> <ui-form-control label="Mobilnummer" variant="inline">
<ng-container *ngSwitchCase="true">Speichern</ng-container> <input uiInput type="tel" formControlName="mobile" tabindex="13" />
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon> </ui-form-control>
</button> </ng-container>
</div> <ui-form-control label="Geburtsdatum" variant="inline">
</form> <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"> <div class="flex flex-row justify-end -mt-4 -mr-2">
<a @if (detailsRoute$ | async; as detailsRoute) {
*ngIf="detailsRoute$ | async; let detailsRoute" <a
[routerLink]="detailsRoute.path" [routerLink]="detailsRoute.path"
[queryParams]="detailsRoute.urlTree.queryParams" [queryParams]="detailsRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
> >
<shared-icon icon="close" [size]="32"></shared-icon> <shared-icon icon="close" [size]="32"></shared-icon>
</a> </a>
}
</div> </div>
<h1 class="text-2xl text-center font-bold mb-6">Lieferadresse bearbeiten</h1> <h1 class="text-2xl text-center font-bold mb-6">Lieferadresse bearbeiten</h1>
<form [formGroup]="formGroup" (ngSubmit)="save()"> <form [formGroup]="formGroup" (ngSubmit)="save()">
<ng-container *ngIf="isBusinessKonto$ | async"> @if (isBusinessKonto$ | async) {
<shared-form-control <shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Firma *' : 'Firma'" [label]="formGroup.controls.organisation.errors?.required ? 'Firma *' : 'Firma'"
class="col-span-2" class="col-span-2"
@@ -19,175 +20,176 @@
formGroup.controls.organisation.errors?.required || formGroup.controls.organisation.errors?.required ||
formGroup.errors?.eitherCompanyOrPersonalRequired formGroup.errors?.eitherCompanyOrPersonalRequired
" "
> >
<input <input
class="input-control" class="input-control"
placeholder="Firma" placeholder="Firma"
type="text" type="text"
formControlName="organisation" formControlName="organisation"
tabindex="1" 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"> <shared-form-control label="Anrede">
<input <shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
class="input-control" @for (gender of genderSettings.genders; track gender) {
placeholder="Abteilung" <shared-select-option [value]="gender.value">{{
type="text" gender.label
formControlName="department" }}</shared-select-option>
tabindex="2" }
/> </shared-select>
</shared-form-control> </shared-form-control>
<shared-form-control label="USt-ID"> <shared-form-control label="Titel">
<input <shared-select formControlName="title" placeholder="Titel" tabindex="5">
class="input-control" <shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
placeholder="Abteilung" <shared-select-option value="Dr.">Dr.</shared-select-option>
type="text" <shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
formControlName="vatId" <shared-select-option value="Prof.">Prof.</shared-select-option>
tabindex="3" <shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
/> <shared-select-option value="RA">RA</shared-select-option>
</shared-form-control> </shared-select>
</ng-container> </shared-form-control>
<shared-form-control label="Anrede"> <shared-form-control
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true"> [label]="formGroup.controls.organisation.errors?.required ? 'Nachname *' : 'Nachname'"
<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'"
[hasRequiredMark]=" [hasRequiredMark]="
formGroup.controls.lastName.errors?.required || formGroup.controls.lastName.errors?.required ||
formGroup.errors?.eitherCompanyOrPersonalRequired formGroup.errors?.eitherCompanyOrPersonalRequired
" "
> >
<input <input
class="input-control" class="input-control"
placeholder="Nachname" placeholder="Nachname"
type="text" type="text"
formControlName="lastName" formControlName="lastName"
tabindex="6" tabindex="6"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control <shared-form-control
[label]="formGroup.controls.organisation.errors?.required ? 'Vorname *' : 'Vorname'" [label]="formGroup.controls.organisation.errors?.required ? 'Vorname *' : 'Vorname'"
[hasRequiredMark]=" [hasRequiredMark]="
formGroup.controls.firstName.errors?.required || formGroup.controls.firstName.errors?.required ||
formGroup.errors?.eitherCompanyOrPersonalRequired formGroup.errors?.eitherCompanyOrPersonalRequired
" "
> >
<input <input
class="input-control" class="input-control"
placeholder="Vorname" placeholder="Vorname"
type="text" type="text"
formControlName="firstName" formControlName="firstName"
tabindex="7" tabindex="7"
/> />
</shared-form-control> </shared-form-control>
<ng-container *ngIf="!(isBusinessKonto$ | async)"> @if (!(isBusinessKonto$ | async)) {
<shared-form-control label="Firma" class="col-span-2"> <shared-form-control label="Firma" class="col-span-2">
<input <input
class="input-control" class="input-control"
placeholder="Firma" placeholder="Firma"
type="text" type="text"
formControlName="organisation" formControlName="organisation"
tabindex="8" tabindex="8"
/> />
</shared-form-control> </shared-form-control>
</ng-container> }
<shared-form-control label="Straße"> <shared-form-control label="Straße">
<input <input
class="input-control" class="input-control"
placeholder="Straße" placeholder="Straße"
type="text" type="text"
formControlName="street" formControlName="street"
tabindex="9" tabindex="9"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control label="Hausnummer"> <shared-form-control label="Hausnummer">
<input <input
class="input-control" class="input-control"
placeholder="Hausnummer" placeholder="Hausnummer"
type="text" type="text"
formControlName="streetNumber" formControlName="streetNumber"
tabindex="10" tabindex="10"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control label="PLZ"> <shared-form-control label="PLZ">
<input <input
class="input-control" class="input-control"
placeholder="PLZ" placeholder="PLZ"
type="text" type="text"
formControlName="zipCode" formControlName="zipCode"
tabindex="11" tabindex="11"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control label="Ort"> <shared-form-control label="Ort">
<input <input
class="input-control" class="input-control"
placeholder="Ort" placeholder="Ort"
type="text" type="text"
formControlName="city" formControlName="city"
tabindex="12" tabindex="12"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control label="Adresszusatz" class="col-span-2"> <shared-form-control label="Adresszusatz" class="col-span-2">
<input <input
class="input-control" class="input-control"
placeholder="Adresszusatz" placeholder="Adresszusatz"
type="text" type="text"
formControlName="info" formControlName="info"
tabindex="13" tabindex="13"
/> />
</shared-form-control> </shared-form-control>
<shared-form-control class="col-span-2" label="Land"> <shared-form-control class="col-span-2" label="Land">
<shared-select placeholder="Land" formControlName="country" tabindex="14"> <shared-select placeholder="Land" formControlName="country" tabindex="14">
<shared-select-option @for (country of countries$ | async; track country) {
*ngFor="let country of countries$ | async" <shared-select-option
[value]="country.isO3166_A_3" [value]="country.isO3166_A_3"
> >
{{ country.name }} {{ country.name }}
</shared-select-option> </shared-select-option>
</shared-select> }
</shared-form-control> </shared-select>
</shared-form-control>
<div class="text-center col-span-2"> <div class="text-center col-span-2">
<shared-checkbox formControlName="isDefault" <shared-checkbox formControlName="isDefault"
>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox >Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox
> >
</div> </div>
<div class="mt-6 text-center col-span-2"> <div class="mt-6 text-center col-span-2">
<button <button
[disabled]="formGroup.invalid || formGroup.disabled" [disabled]="formGroup.invalid || formGroup.disabled"
type="submit" 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" 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" tabindex="15"
> >
Speichern Speichern
</button> </button>
</div> </div>
</form> </form>

View File

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

View File

@@ -1,46 +1,48 @@
<ng-container *ngIf="fetchingFilterSettings$ | async; else filterTemplate"></ng-container> @if (fetchingFilterSettings$ | async) {
} @else {
<ng-template #filterTemplate> @if (filter$ | async; as filter) {
<div *ngIf="filter$ | async; let filter"> <div>
<div class="customer-filter-header"> <div class="customer-filter-header">
<div class="customer-filter-header-actions flex flex-row justify-end pt-1 px-1"> <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)="clearFilter(filter)" class="text-[#0556B4] mr-2 h-12">Alle Filter entfernen</button>
<button (click)="close()" class="btn btn-label" *ngIf="!isOnMainRoute"> @if (!isOnMainRoute) {
<ui-icon [icon]="'close'"></ui-icon> <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> </button>
</div> </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>
}
}
<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> <page-customer-menu [customerId]="customerId$ | async" [processId]="processId$ | async" [showCustomerCard]="false"></page-customer-menu>
</div> </div>
<h1 class="text-center text-2xl font-bold">Kundenkarte</h1> <h1 class="text-center text-2xl font-bold">Kundenkarte</h1>
<p class="text-center text-xl" *ngIf="!(noDataFound$ | async)"> @if (!(noDataFound$ | async)) {
Alle Infos zu Ihrer Kundenkarte <p class="text-center text-xl">
<br /> Alle Infos zu Ihrer Kundenkarte
und allen Partnerkarten. <br />
</p> und allen Partnerkarten.
<p class="text-center text-xl" *ngIf="noDataFound$ | async">Keine Kundenkarte gefunden.</p> </p>
<page-customer-kundenkarte }
class="justify-self-center" @if (noDataFound$ | async) {
*ngFor="let karte of primaryKundenkarte$ | async" <p class="text-center text-xl">Keine Kundenkarte gefunden.</p>
[cardDetails]="karte" }
[isCustomerCard]="true" @for (karte of primaryKundenkarte$ | async; track karte) {
></page-customer-kundenkarte> <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 @for (karte of partnerKundenkarte$ | async; track karte) {
class="justify-self-center" <page-customer-kundenkarte
*ngFor="let karte of partnerKundenkarte$ | async" class="justify-self-center"
[cardDetails]="karte" [cardDetails]="karte"
[isCustomerCard]="false" [isCustomerCard]="false"
></page-customer-kundenkarte> ></page-customer-kundenkarte>
}

View File

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

View File

@@ -1,17 +1,20 @@
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow"> <div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1> <h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
<p class="text-lg mt-2 mb-6">Haben Sie ein Konto bei uns?</p> <p class="text-lg mt-2 mb-6">Haben Sie ein Konto bei uns?</p>
<shared-filter-input-group-main @if (filter$ | async; as filter) {
*ngIf="filter$ | async; let filter" <shared-filter-input-group-main
[inputGroup]="filter?.input | group: 'main'" [inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)" (search)="search(filter)"
[loading]="fetching$ | async" [loading]="fetching$ | async"
[hint]="message$ | async" [hint]="message$ | async"
></shared-filter-input-group-main> ></shared-filter-input-group-main>
}
<p class="mt-6"> <p class="mt-6">
Kunde nicht gefunden? Kunde nicht gefunden?
<a class="text-brand" *ngIf="createRoute$ | async; let route" [routerLink]="route.path" [queryParams]="route.queryParams"> @if (createRoute$ | async; as route) {
Neue Kundendaten erfassen <a class="text-brand" [routerLink]="route.path" [queryParams]="route.queryParams">
</a> Neue Kundendaten erfassen
</a>
}
</p> </p>
</div> </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 { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { Filter, FilterModule } from '@shared/components/filter'; import { Filter, FilterModule } from '@shared/components/filter';
@@ -13,7 +13,7 @@ import { CustomerInfoDTO } from '@generated/swagger/crm-api';
templateUrl: 'main-side-view.component.html', templateUrl: 'main-side-view.component.html',
styleUrls: ['main-side-view.component.css'], styleUrls: ['main-side-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, RouterModule, FilterModule, AsyncPipe, NgIf], imports: [CommonModule, RouterModule, FilterModule, AsyncPipe],
}) })
export class MainSideViewComponent { export class MainSideViewComponent {
private _store = inject(CustomerSearchStore); private _store = inject(CustomerSearchStore);

View File

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

View File

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

View File

@@ -1,12 +1,13 @@
<ng-container *ngIf="fetching$ | async; else historyTemplate"></ng-container> @if (fetching$ | async) {
} @else {
<ng-template #historyTemplate>
<div> <div>
<div class="customer-history-header"> <div class="customer-history-header">
<div class="customer-history-header-actions flex flex-row justify-end pt-1 px-1"> <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"> @if (detailsRoute$ | async; as route) {
<shared-icon [icon]="'close'" [size]="32"></shared-icon> <a [routerLink]="route.path" [queryParams]="route.queryParams" class="btn btn-label">
</a> <shared-icon [icon]="'close'" [size]="32"></shared-icon>
</a>
}
</div> </div>
<div class="customer-history-header-body text-center -mt-3"> <div class="customer-history-header-body text-center -mt-3">
<h1 class="text-[1.625rem] font-bold">Historie</h1> <h1 class="text-[1.625rem] font-bold">Historie</h1>
@@ -26,4 +27,5 @@
<shared-history-list [history]="history$ | async"></shared-history-list> <shared-history-list [history]="history$ | async"></shared-history-list>
</div> </div>
</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 { map, switchMap, takeUntil, tap } from 'rxjs/operators';
import { CustomerSearchStore } from '../store'; import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services/navigation'; import { CustomerSearchNavigation } from '@shared/services/navigation';
import { AsyncPipe, NgIf } from '@angular/common'; import { AsyncPipe } from '@angular/common';
import { IconModule } from '@shared/components/icon'; import { IconModule } from '@shared/components/icon';
import { SharedHistoryListModule } from '@shared/components/history'; import { SharedHistoryListModule } from '@shared/components/history';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { ActivatedRoute, RouterLink } from '@angular/router';
@@ -23,7 +23,7 @@ export interface CustomerHistoryViewMainState {
templateUrl: 'order-details-history-main-view.component.html', templateUrl: 'order-details-history-main-view.component.html',
styleUrls: ['order-details-history-main-view.component.css'], styleUrls: ['order-details-history-main-view.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [AsyncPipe, RouterLink, NgIf, IconModule, SharedHistoryListModule], imports: [AsyncPipe, RouterLink, IconModule, SharedHistoryListModule],
}) })
export class CustomerOrderDetailsHistoryMainViewComponent export class CustomerOrderDetailsHistoryMainViewComponent
extends ComponentStore<CustomerHistoryViewMainState> extends ComponentStore<CustomerHistoryViewMainState>

View File

@@ -5,15 +5,16 @@
<div class="grid grid-flow-row gap-2"> <div class="grid grid-flow-row gap-2">
<div class="grid grid-flow-col justify-between items-end"> <div class="grid grid-flow-col justify-between items-end">
<span>{{ orderItem.product?.contributors }}</span> <span>{{ orderItem.product?.contributors }}</span>
<a @if (orderDetailsHistoryRoute$ | async; as orderDetailsHistoryRoute) {
*ngIf="orderDetailsHistoryRoute$ | async; let orderDetailsHistoryRoute" <a
[routerLink]="orderDetailsHistoryRoute.path" [routerLink]="orderDetailsHistoryRoute.path"
[queryParams]="orderDetailsHistoryRoute.urlTree.queryParams" [queryParams]="orderDetailsHistoryRoute.urlTree.queryParams"
[queryParamsHandling]="'merge'" [queryParamsHandling]="'merge'"
class="text-brand font-bold text-xl" class="text-brand font-bold text-xl"
> >
Historie Historie
</a> </a>
}
</div> </div>
<div class="font-bold text-lg"> <div class="font-bold text-lg">
{{ orderItem?.product?.name }} {{ orderItem?.product?.name }}
@@ -23,82 +24,90 @@
{{ processingStatus$ | async | orderItemProcessingStatus }} {{ processingStatus$ | async | orderItemProcessingStatus }}
</span> </span>
</div> </div>
<div class="grid grid-flow-row gap-2" *ngIf="orderItemSubsetItem$ | async; let orderItemSubsetItem"> @if (orderItemSubsetItem$ | async; as orderItemSubsetItem) {
<div class="col-data"> <div class="grid grid-flow-row gap-2">
<div class="col-label">Menge</div> <div class="col-data">
<div class="col-value">{{ orderItem?.quantity?.quantity }}x</div> <div class="col-label">Menge</div>
</div> <div class="col-value">{{ orderItem?.quantity?.quantity }}x</div>
<div class="col-data"> </div>
<div class="col-label">Format</div> <div class="col-data">
<div class="col-value grid-flow-col grid gap-3 items-center justify-start"> <div class="col-label">Format</div>
<shared-icon [icon]="orderItem?.product?.format"></shared-icon> <div class="col-value grid-flow-col grid gap-3 items-center justify-start">
<span>{{ orderItem?.product?.formatDetail }}</span> <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> </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>
</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 { Component, ChangeDetectionStrategy, Input, OnDestroy, OnInit, inject } from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { ActivatedRoute, RouterLink } from '@angular/router';
import { ProductImagePipe } from '@cdn/product-image'; import { ProductImagePipe } from '@cdn/product-image';
@@ -19,7 +19,6 @@ import { PaymentTypePipe } from '@shared/pipes/customer';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page-customer-order-item-list-item' }, host: { class: 'page-customer-order-item-list-item' },
imports: [ imports: [
NgIf,
AsyncPipe, AsyncPipe,
DatePipe, DatePipe,
OrderProcessingStatusPipe, OrderProcessingStatusPipe,
@@ -30,8 +29,8 @@ import { PaymentTypePipe } from '@shared/pipes/customer';
IconComponent, IconComponent,
RouterLink, RouterLink,
PaymentTypePipe, PaymentTypePipe,
OrderItemProcessingStatusPipe, OrderItemProcessingStatusPipe
], ],
}) })
export class CustomerOrderItemListItemComponent implements OnInit, OnDestroy { export class CustomerOrderItemListItemComponent implements OnInit, OnDestroy {
private _activatedRoute = inject(ActivatedRoute); private _activatedRoute = inject(ActivatedRoute);

View File

@@ -2,23 +2,25 @@
{{ customer$ | async | customerName }} {{ customer$ | async | customerName }}
</div> </div>
<div class="bg-surface-2 text-surface-2-content p-4 text-right">{{ (orderItems$ | async)?.length }} Artikel</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"> @if (selectedOrderItemId$ | async; as selectedOrderItemId) {
<ng-container *ngFor="let orderItem of orderItems$ | async"> <div class="grid grid-flow-row gap-1">
<div @for (orderItem of orderItems$ | async; track orderItem) {
[class.order-item-active]="selectedOrderItemId === orderItem?.id" <div
class="grid grid-cols-[auto_1fr] gap-4 p-4 border border-solid bg-surface text-surface-content rounded first:rounded-t-none" [class.order-item-active]="selectedOrderItemId === orderItem?.id"
(click)="selectOrderItem(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>
<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>
<div class="grid grid-flow-row gap-1"> }
<span>{{ orderItem?.product?.contributors }}</span> </div>
<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>

View File

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

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