diff --git a/libs/checkout/data-access/src/lib/helpers/group-display-order-items-by-branch.helper.ts b/libs/checkout/data-access/src/lib/helpers/group-display-order-items-by-branch.helper.ts new file mode 100644 index 000000000..fc4a9269a --- /dev/null +++ b/libs/checkout/data-access/src/lib/helpers/group-display-order-items-by-branch.helper.ts @@ -0,0 +1,110 @@ +import { DisplayOrderItem } from '@isa/oms/data-access'; +import { OrderType } from '../models'; + +/** + * Represents a group of order items sharing the same branch (for pickup/in-store) + * or all items for delivery types that don't have branch-specific grouping. + */ +export type OrderItemBranchGroup = { + /** Branch ID (undefined for delivery types without branch grouping) */ + branchId?: number; + /** Branch name (undefined for delivery types without branch grouping) */ + branchName?: string; + /** Array of items in this branch group */ + items: DisplayOrderItem[]; +}; + +/** + * Order types that require grouping by branch/filiale. + * Other order types (Versand, DIG-Versand, etc.) are grouped together without branch subdivision. + */ +const ORDER_TYPES_WITH_BRANCH_GROUPING = [ + OrderType.Pickup, + OrderType.InStore, +] as const; + +/** + * Sorts branch groups by branch ID (ascending). + */ +const sortByBranchId = ( + entries: [number, DisplayOrderItem[]][], +): [number, DisplayOrderItem[]][] => { + return [...entries].sort(([a], [b]) => a - b); +}; + +/** + * Groups display order items by their target branch. + * Only applies branch-level grouping for Abholung (Pickup) and Rücklage (InStore) order types. + * For other delivery types (Versand, DIG-Versand, etc.), returns a single group with all items. + * + * Uses item.order.targetBranch for grouping since items inherit their parent order's branch information. + * + * @param orderType - The order type to determine if branch grouping is needed + * @param items - Array of DisplayOrderItem objects to group + * @returns Array of OrderItemBranchGroup objects, each containing items for a specific branch + * + * @example + * ```typescript + * // For Abholung (pickup) items from different branches + * const pickupItems = [ + * { id: 1, order: { targetBranch: { id: 1, name: 'München' } } }, + * { id: 2, order: { targetBranch: { id: 2, name: 'Berlin' } } } + * ]; + * const groups = groupDisplayOrderItemsByBranch('Abholung', pickupItems); + * // [ + * // { branchId: 1, branchName: 'München', items: [item1] }, + * // { branchId: 2, branchName: 'Berlin', items: [item2] } + * // ] + * + * // For Versand (delivery) items + * const deliveryItems = [ + * { id: 1, ... }, + * { id: 2, ... } + * ]; + * const groups = groupDisplayOrderItemsByBranch('Versand', deliveryItems); + * // [ + * // { branchId: undefined, branchName: undefined, items: [item1, item2] } + * // ] + * ``` + */ +export function groupDisplayOrderItemsByBranch( + orderType: OrderType | string, + items: DisplayOrderItem[], +): OrderItemBranchGroup[] { + const needsBranchGrouping = + orderType === OrderType.Pickup || orderType === OrderType.InStore; + + if (!needsBranchGrouping) { + // For delivery types without branch grouping, return single group with all items + return [ + { + branchId: undefined, + branchName: undefined, + items, + }, + ]; + } + + // For Abholung/Rücklage, group by item.order.targetBranch.id + const branchGroups = items.reduce((map, item) => { + const branchId = item.order?.targetBranch?.id ?? 0; + if (!map.has(branchId)) { + map.set(branchId, []); + } + map.get(branchId)!.push(item); + return map; + }, new Map()); + + // Convert Map to array of OrderItemBranchGroup, sorted by branch ID + return sortByBranchId(Array.from(branchGroups.entries())).map( + ([branchId, branchItems]) => { + const branch = branchItems[0]?.order?.targetBranch; + + return { + branchId: branchId || undefined, + branchName: branch?.name, + items: branchItems, + }; + }, + ); +} diff --git a/libs/checkout/data-access/src/lib/helpers/group-display-order-items-by-delivery-type.helper.ts b/libs/checkout/data-access/src/lib/helpers/group-display-order-items-by-delivery-type.helper.ts new file mode 100644 index 000000000..9a50d9463 --- /dev/null +++ b/libs/checkout/data-access/src/lib/helpers/group-display-order-items-by-delivery-type.helper.ts @@ -0,0 +1,48 @@ +import { DisplayOrder, DisplayOrderItem } from '@isa/oms/data-access'; +import { getOrderTypeFeature } from './get-order-type-feature.helper'; +import { OrderType } from '../models'; + +/** + * Groups display order items by their delivery type (item.features.orderType). + * + * Unlike groupDisplayOrdersByDeliveryType which groups entire orders, + * this groups individual items since items within one order can have different delivery types. + * + * @param orders - Array of DisplayOrder objects containing items to group + * @returns Map where keys are order types (Abholung, Rücklage, Versand, etc.) + * and values are arrays of items with that type + * + * @example + * ```typescript + * const orders = [ + * { + * id: 1, + * features: { orderType: 'Abholung' }, + * items: [ + * { id: 1, features: { orderType: 'Abholung' }, ... }, + * { id: 2, features: { orderType: 'Rücklage' }, ... } + * ] + * } + * ]; + * + * const grouped = groupDisplayOrderItemsByDeliveryType(orders); + * // Map { + * // 'Abholung' => [item1], + * // 'Rücklage' => [item2] + * // } + * ``` + */ +export function groupDisplayOrderItemsByDeliveryType( + orders: DisplayOrder[], +): Map { + const allItems = orders.flatMap((order) => order.items ?? []); + + return allItems.reduce((map, item) => { + const orderType = getOrderTypeFeature(item.features) ?? 'Unbekannt'; + if (!map.has(orderType)) { + map.set(orderType, []); + } + map.get(orderType)!.push(item); + return map; + }, new Map()); +} diff --git a/libs/checkout/data-access/src/lib/helpers/index.ts b/libs/checkout/data-access/src/lib/helpers/index.ts index bb26cd288..27aab7fbe 100644 --- a/libs/checkout/data-access/src/lib/helpers/index.ts +++ b/libs/checkout/data-access/src/lib/helpers/index.ts @@ -12,6 +12,8 @@ export * from './group-by-branch.helper'; export * from './group-by-order-type.helper'; export * from './group-display-orders-by-branch.helper'; export * from './group-display-orders-by-delivery-type.helper'; +export * from './group-display-order-items-by-branch.helper'; +export * from './group-display-order-items-by-delivery-type.helper'; export * from './item-selection-changed.helper'; export * from './merge-reward-selection-items.helper'; export * from './should-show-grouping.helper'; diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.html b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.html index 48160ee5e..6f77f6466 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.html +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.html @@ -1,14 +1,39 @@ -
- -
- {{ orderType() }} -
-
+@for (group of groupedOrders(); track group.orderType) { + +
+ @for (branchGroup of group.branchGroups; track branchGroup.branchId ?? 0) { + + @if (branchGroup.branchName && group.branchGroups.length > 1) { +
+ +
{{ group.orderType }} - {{ branchGroup.branchName }}
+
+ } @else { + +
+ +
+ {{ group.orderType }} +
+
+ } -@for (item of items(); track item.id) { - + + @for (item of branchGroup.items; track item.id) { + + } + } +
} diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.ts b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.ts index a517d664b..c07d5b825 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.ts +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list.component.ts @@ -2,19 +2,24 @@ import { ChangeDetectionStrategy, Component, computed, - input, + inject, } from '@angular/core'; import { OrderConfirmationItemListItemComponent } from './order-confirmation-item-list-item/order-confirmation-item-list-item.component'; -import { getOrderTypeFeature, OrderType } from '@isa/checkout/data-access'; +import { + groupDisplayOrderItemsByDeliveryType, + groupDisplayOrderItemsByBranch, + getOrderTypeIcon, +} from '@isa/checkout/data-access'; import { NgIcon, provideIcons } from '@ng-icons/core'; import { isaDeliveryVersand, isaDeliveryRuecklage2, isaDeliveryRuecklage1, + isaDeliveryB2BVersand1, } from '@isa/icons'; -import { DisplayOrder } from '@isa/oms/data-access'; +import { OrderConfiramtionStore } from '../reward-order-confirmation.store'; @Component({ selector: 'checkout-order-confirmation-item-list', @@ -27,33 +32,40 @@ import { DisplayOrder } from '@isa/oms/data-access'; isaDeliveryVersand, isaDeliveryRuecklage2, isaDeliveryRuecklage1, + isaDeliveryB2BVersand1, }), ], }) export class OrderConfirmationItemListComponent { - order = input.required(); + #store = inject(OrderConfiramtionStore); - orderType = computed(() => { - return getOrderTypeFeature(this.order().features); + orders = this.#store.orders; + + /** + * Groups order items hierarchically by delivery type and branch. + * - Primary grouping: By delivery type from item.features.orderType (Abholung, Rücklage, Versand, etc.) + * - Secondary grouping: By branch (only for Abholung and Rücklage) + * + * Note: Groups by item-level orderType, not order-level, since items within + * a single order can have different delivery types. + */ + groupedOrders = computed(() => { + const orders = this.orders(); + if (!orders || orders.length === 0) { + return []; + } + + const byDeliveryType = groupDisplayOrderItemsByDeliveryType(orders); + + const result = Array.from(byDeliveryType.entries()).map( + ([orderType, items]) => ({ + orderType, + icon: getOrderTypeIcon(orderType), + branchGroups: groupDisplayOrderItemsByBranch(orderType, items), + }), + ); + + console.log('Grouped orders:', result); + return result; }); - - orderTypeIcon = computed(() => { - const orderType = this.orderType(); - - if (OrderType.Delivery === orderType) { - return 'isaDeliveryVersand'; - } - - if (OrderType.Pickup === orderType) { - return 'isaDeliveryRuecklage2'; - } - - if (OrderType.InStore === orderType) { - return 'isaDeliveryRuecklage1'; - } - - return 'isaDeliveryVersand'; - }); - - items = computed(() => this.order().items ?? []); } diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.html b/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.html index 591f3362e..2084ad2ea 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.html +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.html @@ -1,47 +1,8 @@
- +
- - - @for (group of groupedOrders(); track group.orderType) { - -
- @for (branchGroup of group.branchGroups; track branchGroup.branchId ?? 0) { - - @if (branchGroup.branchName && group.branchGroups.length > 1) { -
- -
- {{ group.orderType }} - {{ branchGroup.branchName }} -
-
- } @else { - -
- -
- {{ group.orderType }} -
-
- } - - - @for (item of branchGroup.allItems; track item.id) { - - } - } -
- } + +
diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.ts b/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.ts index 09daf8604..b9b209f85 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.ts +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/reward-order-confirmation.component.ts @@ -11,22 +11,9 @@ import { toSignal } from '@angular/core/rxjs-interop'; import { OrderConfirmationAddressesComponent } from './order-confirmation-addresses/order-confirmation-addresses.component'; import { OrderConfirmationHeaderComponent } from './order-confirmation-header/order-confirmation-header.component'; import { OrderConfirmationItemListComponent } from './order-confirmation-item-list/order-confirmation-item-list.component'; -import { OrderConfirmationItemListItemComponent } from './order-confirmation-item-list/order-confirmation-item-list-item/order-confirmation-item-list-item.component'; import { ActivatedRoute } from '@angular/router'; import { TabService } from '@isa/core/tabs'; import { OrderConfiramtionStore } from './reward-order-confirmation.store'; -import { - groupDisplayOrdersByDeliveryType, - groupDisplayOrdersByBranch, - getOrderTypeIcon, -} from '@isa/checkout/data-access'; -import { NgIcon, provideIcons } from '@ng-icons/core'; -import { - isaDeliveryVersand, - isaDeliveryRuecklage2, - isaDeliveryRuecklage1, - isaDeliveryB2BVersand1, -} from '@isa/icons'; @Component({ selector: 'checkout-reward-order-confirmation', @@ -37,18 +24,8 @@ import { OrderConfirmationHeaderComponent, OrderConfirmationAddressesComponent, OrderConfirmationItemListComponent, - OrderConfirmationItemListItemComponent, - NgIcon, - ], - providers: [ - OrderConfiramtionStore, - provideIcons({ - isaDeliveryVersand, - isaDeliveryRuecklage2, - isaDeliveryRuecklage1, - isaDeliveryB2BVersand1, - }), ], + providers: [OrderConfiramtionStore], }) export class RewardOrderConfirmationComponent { #store = inject(OrderConfiramtionStore); @@ -66,28 +43,6 @@ export class RewardOrderConfirmationComponent { return param ? param.split('+').map((strId) => parseInt(strId, 10)) : []; }); - orders = this.#store.orders; - - /** - * Groups orders hierarchically by delivery type and branch. - * - Primary grouping: By delivery type (Abholung, Rücklage, Versand, etc.) - * - Secondary grouping: By branch (only for Abholung and Rücklage) - */ - groupedOrders = computed(() => { - const orders = this.orders(); - if (!orders || orders.length === 0) { - return []; - } - - const byDeliveryType = groupDisplayOrdersByDeliveryType(orders); - - return Array.from(byDeliveryType.entries()).map(([orderType, typeOrders]) => ({ - orderType, - icon: getOrderTypeIcon(orderType), - branchGroups: groupDisplayOrdersByBranch(orderType, typeOrders), - })); - }); - constructor() { effect(() => { const tabId = this.#tabId() || undefined; @@ -97,9 +52,5 @@ export class RewardOrderConfirmationComponent { this.#store.patch({ tabId, orderIds }); }); }); - - effect(() => { - console.log('Orders to display:', this.orders()); - }); } }