Merged PR 2060: feature(checkout-reward, core-tabs): Added back button and configured it so i...

feature(checkout-reward, core-tabs): Added back button and configured it so it can accept optional route to navigate. Added orderNumber and orderDate to reward order confirmation

Ref: #5456
This commit is contained in:
Nino Righi
2025-11-28 12:38:08 +00:00
committed by Lorenz Hilpert
parent 41630d5d7c
commit c0cc0e1bbc
9 changed files with 147 additions and 12 deletions

View File

@@ -1,3 +1,7 @@
:host {
@apply w-full flex flex-row items-center justify-between;
}
ui-item-row-data-label {
width: 12.4rem;
}

View File

@@ -1,8 +1,21 @@
<h1 class="text-isa-neutral-900 isa-text-subtitle-1-regular">
Prämienausgabe abgeschlossen
</h1>
<div class="flex flex-col gap-4">
<h1 class="text-isa-neutral-900 isa-text-subtitle-1-regular">
Prämienausgabe abgeschlossen
</h1>
<ui-item-row-data>
<ui-item-row-data-row>
<ui-item-row-data-label>Vorgangs-ID</ui-item-row-data-label>
<ui-item-row-data-value>{{ orderNumbers() }}</ui-item-row-data-value>
</ui-item-row-data-row>
<ui-item-row-data-row>
<ui-item-row-data-label>Bestelldatum</ui-item-row-data-label>
<ui-item-row-data-value>{{ orderDates() }}</ui-item-row-data-value>
</ui-item-row-data-row>
</ui-item-row-data>
</div>
<common-print-button
class="self-start"
*ifNotRole="Role.CallCenter"
printerType="label"
[printFn]="printFn"

View File

@@ -1,20 +1,28 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
inject,
computed,
} from '@angular/core';
import { DatePipe } from '@angular/common';
import { CheckoutPrintFacade } from '@isa/checkout/data-access';
import { PrintButtonComponent, Printer } from '@isa/common/print';
import { OrderConfiramtionStore } from '../reward-order-confirmation.store';
import { IfRoleDirective, Role } from '@isa/core/auth';
import { ItemRowDataImports } from '@isa/ui/item-rows';
@Component({
selector: 'checkout-order-confirmation-header',
templateUrl: './order-confirmation-header.component.html',
styleUrls: ['./order-confirmation-header.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [PrintButtonComponent, IfRoleDirective],
imports: [PrintButtonComponent, IfRoleDirective, ItemRowDataImports],
})
export class OrderConfirmationHeaderComponent {
protected readonly Role = Role;
#checkoutPrintFacade = inject(CheckoutPrintFacade);
#store = inject(OrderConfiramtionStore);
#datePipe = new DatePipe('de-DE');
orderIds = this.#store.orderIds;
@@ -24,4 +32,35 @@ export class OrderConfirmationHeaderComponent {
data: this.orderIds() ?? [],
});
};
orderNumbers = computed(() => {
const orders = this.#store.orders();
if (!orders || orders.length === 0) {
return '';
}
return orders
.map((order) => order.orderNumber)
.filter(Boolean)
.join('; ');
});
orderDates = computed(() => {
const orders = this.#store.orders();
if (!orders || orders.length === 0) {
return '';
}
return orders
.map((order) => {
if (!order.orderDate) {
return null;
}
const formatted = this.#datePipe.transform(
order.orderDate,
'dd.MM.yyyy | HH:mm',
);
return formatted ? `${formatted} Uhr` : null;
})
.filter(Boolean)
.join('; ');
});
}

View File

@@ -19,6 +19,7 @@ import {
HandleCommandService,
HandleCommand,
getMainActions,
DisplayOrdersResource,
} from '@isa/oms/data-access';
import { ButtonComponent } from '@isa/ui/buttons';
import { NgIcon } from '@ng-icons/core';
@@ -61,6 +62,7 @@ export class ConfirmationListItemActionCardComponent {
#orderRewardCollectFacade = inject(OrderRewardCollectFacade);
#store = inject(OrderConfiramtionStore);
#orderItemSubsetResource = inject(OrderItemSubsetResource);
#displayOrdersResource = inject(DisplayOrdersResource);
#handleCommandFacade = inject(HandleCommandFacade);
item = input.required<DisplayOrderItem>();
@@ -165,7 +167,7 @@ export class ConfirmationListItemActionCardComponent {
}
}
}
this.#orderItemSubsetResource.refresh();
this.reloadResources();
}
} finally {
this.isLoading.set(false);
@@ -175,4 +177,9 @@ export class ConfirmationListItemActionCardComponent {
async handleCommand(params: HandleCommand) {
await this.#handleCommandFacade.handle(params);
}
reloadResources() {
this.#orderItemSubsetResource.refresh();
this.#displayOrdersResource.refresh();
}
}

View File

@@ -1,3 +1,3 @@
:host {
@apply block w-full text-isa-neutral-900 mt-[1.42rem];
@apply flex flex-col w-full text-isa-neutral-900 mt-[1.42rem] gap-4;
}

View File

@@ -1,3 +1,6 @@
@if (!hasPendingActions()) {
<tabs-navigate-back-button [navigateTo]="rewardCatalogRoute()" />
}
<div
class="bg-isa-white p-6 rounded-2xl flex flex-col gap-6 items-start self-stretch"
>

View File

@@ -12,9 +12,21 @@ import { OrderConfirmationAddressesComponent } from './order-confirmation-addres
import { OrderConfirmationHeaderComponent } from './order-confirmation-header/order-confirmation-header.component';
import { OrderConfirmationItemListComponent } from './order-confirmation-item-list/order-confirmation-item-list.component';
import { ActivatedRoute } from '@angular/router';
import { TabService } from '@isa/core/tabs';
import {
NavigateBackButtonComponent,
TabService,
injectTabId,
} from '@isa/core/tabs';
import { OrderConfiramtionStore } from './reward-order-confirmation.store';
import { DisplayOrdersResource } from '@isa/oms/data-access';
import {
DisplayOrdersResource,
getProcessingStatusState,
ProcessingStatusState,
} from '@isa/oms/data-access';
import {
hasOrderTypeFeature,
hasLoyaltyCollectCommand,
} from '@isa/checkout/data-access';
@Component({
selector: 'checkout-reward-order-confirmation',
@@ -25,13 +37,14 @@ import { DisplayOrdersResource } from '@isa/oms/data-access';
OrderConfirmationHeaderComponent,
OrderConfirmationAddressesComponent,
OrderConfirmationItemListComponent,
NavigateBackButtonComponent,
],
providers: [OrderConfiramtionStore, DisplayOrdersResource],
})
export class RewardOrderConfirmationComponent {
#store = inject(OrderConfiramtionStore);
#displayOrdersResource = inject(DisplayOrdersResource);
#tabId = inject(TabService).activatedTabId;
#tabId = injectTabId();
#activatedRoute = inject(ActivatedRoute);
params = toSignal(this.#activatedRoute.paramMap);
@@ -49,6 +62,43 @@ export class RewardOrderConfirmationComponent {
orderIds = this.displayOrderIds;
orders = this.#store.orders;
/**
* Checks if there are any items with pending actions (Rücklage items that still need to be collected).
* Returns true if at least one item requires action.
*/
hasPendingActions = computed(() => {
const orders = this.#store.orders();
if (!orders) {
return false;
}
const allItems = orders.flatMap((order) => order.items ?? []);
return allItems.some((item) => {
const isRuecklage = hasOrderTypeFeature(item.features, ['Rücklage']);
if (!isRuecklage) {
return false;
}
const hasCollectCommand = hasLoyaltyCollectCommand(item.subsetItems);
const statuses = item.subsetItems?.map(
(subset) => subset.processingStatus,
);
const processingStatus = getProcessingStatusState(statuses);
const isComplete =
processingStatus !== undefined &&
processingStatus !== ProcessingStatusState.Ordered;
// Item has pending action if it has collect command and is not complete
return hasCollectCommand && !isComplete;
});
});
/**
* Route to the reward catalog for the current tab.
*/
rewardCatalogRoute = computed(() => `/${this.#tabId()}/reward`);
constructor() {
// Update store state
effect(() => {

View File

@@ -1,4 +1,4 @@
import { Component, inject, computed } from '@angular/core';
import { Component, inject, computed, input } from '@angular/core';
import { Router } from '@angular/router';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { isaActionChevronLeft } from '@isa/icons';
@@ -33,7 +33,18 @@ export class NavigateBackButtonComponent {
#tabService = inject(TabService);
#router = inject(Router);
/**
* Optional URL to navigate to instead of using browser history.
* Pass a complete URL string (e.g. '/123/reward').
*/
navigateTo = input<string>();
canNavigateBack = computed(() => {
// If navigateTo is set, always allow navigation
if (this.navigateTo()) {
return true;
}
const tabId = this.#tabService.activatedTabId();
if (tabId === null) {
return false;
@@ -49,10 +60,18 @@ export class NavigateBackButtonComponent {
});
back() {
const navigateTo = this.navigateTo();
if (navigateTo) {
this.#router.navigateByUrl(navigateTo);
return;
}
// Default behavior: use browser history
const tabId = this.#tabService.activatedTabId();
if (tabId === null) {
return;
}
const location = this.#tabService.navigateBack(tabId);
if (!location) {

View File

@@ -15,7 +15,7 @@
</ui-item-row-data-value>
</ui-item-row-data-row>
<ui-item-row-data-row>
<ui-item-row-data-label>Vorgang-ID:</ui-item-row-data-label>
<ui-item-row-data-label>Vorgangs-ID:</ui-item-row-data-label>
<ui-item-row-data-value>
{{ r.order?.data?.orderNumber }}
</ui-item-row-data-value>