Files
ISA-Frontend/libs/checkout/shared/reward-selection-dialog/README.md
Nino 215cceb1c4 feature(purchase-options, reward-dialog, reward-popup, checkout-data-access): replace useRedemptionPoints flag with p4mAccountId
Replace the boolean useRedemptionPoints flag with explicit p4mAccountId
string parameter throughout the reward selection and purchase options flow.
This provides better traceability and explicit account identification for
P4M loyalty point redemptions.

Changes:
- Update PurchaseOptionsModalData to use p4mAccountId instead of useRedemptionPoints
- Pass p4mAccountId through purchase options store and selectors
- Set loyalty.code with p4mAccountId when creating/updating cart items
- Update RewardSelectionService to compute p4mAccountId from customer attributes
- Add getCustomerP4mAccountId helper function with unit tests
- Update getPrimaryBonusCard to sort alphabetically by code when multiple primary cards exist
- Add SelectedCustomerResource provider to required modules
- Update all component templates and service calls to use p4mAccountId
- Enhance reward selection dialog to require and use p4mAccountId
- Update README documentation with new parameter usage

The p4mAccountId is now extracted from customer attributes using the key
'p4mAccountId' and passed explicitly through the entire redemption flow,
replacing the implicit boolean flag approach.

Ref: #5407
2025-10-27 17:56:48 +01:00

5.5 KiB

Reward Selection Dialog

Angular library for managing reward selection in shopping cart context. Allows users to toggle between regular purchase and reward redemption using bonus points.

Features

  • 🎯 Pre-built trigger component or direct service integration
  • 🔄 Automatic resource management (carts, bonus cards)
  • 📊 Smart grouping by order type and branch
  • 💾 NgRx Signals state management
  • Full TypeScript support

Installation

import {
  RewardSelectionService,
  RewardSelectionPopUpService,
  RewardSelectionTriggerComponent,
} from '@isa/checkout/shared/reward-selection-dialog';

Quick Start

Simplest integration - includes all providers automatically:

import { Component } from '@angular/core';
import { RewardSelectionTriggerComponent } from '@isa/checkout/shared/reward-selection-dialog';

@Component({
  selector: 'app-checkout',
  template: `<lib-reward-selection-trigger />`,
  imports: [RewardSelectionTriggerComponent],
})
export class CheckoutComponent {}

Using the Pop-Up Service

More control over navigation flow:

import { Component, inject } from '@angular/core';
import {
  RewardSelectionPopUpService,
  NavigateAfterRewardSelection,
  RewardSelectionService,
} from '@isa/checkout/shared/reward-selection-dialog';
import {
  SelectedShoppingCartResource,
  SelectedRewardShoppingCartResource,
} from '@isa/checkout/data-access';

@Component({
  selector: 'app-custom-checkout',
  template: `<button (click)="openRewardSelection()">Select Rewards</button>`,
  providers: [
    // Required providers
    SelectedShoppingCartResource,
    SelectedRewardShoppingCartResource,
    SelectedCustomerResource,
    RewardSelectionService,
    RewardSelectionPopUpService,
  ],
})
export class CustomCheckoutComponent {
  #popUpService = inject(RewardSelectionPopUpService);

  async openRewardSelection() {
    const result = await this.#popUpService.popUp();
    
    // Handle navigation: 'cart' | 'reward' | 'catalog' | undefined
    if (result === NavigateAfterRewardSelection.CART) {
      // Navigate to cart
    }
  }
}

Using the Service Directly

For custom UI or advanced use cases:

import { Component, inject } from '@angular/core';
import { RewardSelectionService } from '@isa/checkout/shared/reward-selection-dialog';
import {
  SelectedShoppingCartResource,
  SelectedRewardShoppingCartResource,
} from '@isa/checkout/data-access';

@Component({
  selector: 'app-advanced',
  template: `
    @if (canOpen()) {
      <button (click)="openDialog()" [disabled]="isLoading()">
        {{ eligibleItemsCount() }} items as rewards ({{ availablePoints() }} points)
      </button>
    }
  `,
  providers: [
    SelectedShoppingCartResource,
    SelectedRewardShoppingCartResource,
    RewardSelectionService,
  ],
})
export class AdvancedComponent {
  #service = inject(RewardSelectionService);

  canOpen = this.#service.canOpen;
  isLoading = this.#service.isLoading;
  eligibleItemsCount = computed(() => this.#service.eligibleItems().length);
  availablePoints = this.#service.primaryBonusCardPoints;

  async openDialog() {
    const result = await this.#service.open({ closeText: 'Cancel' });
    if (result) {
      // Handle result.rewardSelectionItems
      await this.#service.reloadResources();
    }
  }
}

API Reference

RewardSelectionService

Key Signals:

  • canOpen(): boolean - Can dialog be opened
  • isLoading(): boolean - Loading state
  • eligibleItems(): RewardSelectionItem[] - Items available as rewards
  • primaryBonusCardPoints(): number - Available points

Methods:

  • open({ closeText }): Promise<RewardSelectionDialogResult> - Opens dialog
  • reloadResources(): Promise<void> - Reloads all data

RewardSelectionPopUpService

Methods:

  • popUp(): Promise<NavigateAfterRewardSelection | undefined> - Opens dialog with navigation flow

Return values:

  • 'cart' - Navigate to shopping cart
  • 'reward' - Navigate to reward checkout
  • 'catalog' - Navigate to catalog
  • undefined - No navigation needed

Types

interface RewardSelectionItem {
  item: ShoppingCartItem;
  catalogPrice: Price | undefined;
  availabilityPrice: Price | undefined;
  catalogRewardPoints: number | undefined;
  cartQuantity: number;
  rewardCartQuantity: number;
}

type RewardSelectionDialogResult = {
  rewardSelectionItems: RewardSelectionItem[];
} | undefined;

type NavigateAfterRewardSelection = 'cart' | 'reward' | 'catalog';

Required Providers

When using RewardSelectionService or RewardSelectionPopUpService directly, provide:

providers: [
  SelectedShoppingCartResource,      // Regular cart data
  SelectedRewardShoppingCartResource, // Reward cart data
  RewardSelectionService,             // Core service
  RewardSelectionPopUpService,        // Optional: only if using pop-up
]

Note: RewardSelectionTriggerComponent includes all required providers automatically.

Testing

nx test reward-selection-dialog

Architecture

reward-selection-dialog/
├── helper/           # Pure utility functions
├── resource/         # Data resources
├── service/          # Business logic
├── store/           # NgRx Signals state
└── trigger/         # Trigger component

Dependencies

  • @isa/checkout/data-access - Cart resources
  • @isa/crm/data-access - Customer data
  • @isa/catalogue/data-access - Product catalog
  • @isa/ui/dialog - Dialog infrastructure
  • @ngrx/signals - State management