📝 docs: update README documentation for 13 libraries

This commit is contained in:
Lorenz Hilpert
2025-11-25 14:13:44 +01:00
parent b93e39068c
commit bc1f6a42e6
14 changed files with 3591 additions and 2317 deletions

View File

@@ -1,205 +1,310 @@
# Reward Selection Dialog
# @isa/checkout/shared/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.
A comprehensive Angular dialog library for managing reward selection in the checkout process, allowing customers to allocate cart items between regular purchases (paid with money) and reward redemptions (paid with loyalty points).
## Features
## Overview
- 🎯 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
This library provides a sophisticated dialog system that enables customers to decide how they want to purchase items that are eligible for both regular checkout and reward redemption. The dialog presents items from both the regular shopping cart and reward shopping cart, allowing customers to allocate quantities between payment methods.
The library includes:
- A main dialog component with quantity allocation interface
- A trigger component for opening the dialog from various contexts
- State management using NgRx Signal Store
- Services for managing dialog lifecycle and popup behavior
- Automatic resource loading and validation
## Installation
```typescript
```ts
import {
RewardSelectionDialogComponent,
RewardSelectionService,
RewardSelectionPopUpService,
RewardSelectionTriggerComponent,
RewardSelectionTriggerComponent
} from '@isa/checkout/shared/reward-selection-dialog';
```
## Quick Start
## Components
### Using the Trigger Component (Recommended)
### RewardSelectionDialogComponent
Simplest integration - includes all providers automatically:
The main dialog component that displays eligible items and allows customers to allocate quantities between regular cart and reward cart.
```typescript
**Features:**
- Displays customer's available loyalty points
- Shows item grouping by order type (delivery, pickup, etc.) and branch
- Real-time calculation of total price and loyalty points needed
- Validates sufficient loyalty points before allowing save
- Integrates with shopping cart resources
### RewardSelectionTriggerComponent
A button component that can be embedded in the UI to trigger the reward selection dialog.
**Features:**
- Automatically shows/hides based on eligibility
- Skeleton loader during resource loading
- Handles dialog result and navigation
- Provides feedback after selection
## API Reference
### Dialog Data Interface
```ts
export type RewardSelectionDialogData = {
rewardSelectionItems: RewardSelectionItem[];
customerRewardPoints: number;
closeText: string;
};
export type RewardSelectionDialogResult =
| {
rewardSelectionItems: RewardSelectionItem[];
}
| undefined;
```
**RewardSelectionDialogData:**
- `rewardSelectionItems`: Array of items eligible for reward selection with current cart/reward quantities
- `customerRewardPoints`: Total loyalty points available to the customer
- `closeText`: Text for the cancel/close button
**RewardSelectionDialogResult:**
- Returns updated `rewardSelectionItems` array if customer saves changes
- Returns `undefined` if dialog is cancelled or no changes made
### Opening the Dialog
#### Using RewardSelectionService
```ts
import { inject } from '@angular/core';
import { RewardSelectionService } from '@isa/checkout/shared/reward-selection-dialog';
export class MyComponent {
#rewardSelectionService = inject(RewardSelectionService);
async openDialog() {
// Check if dialog can be opened (has eligible items and customer has points)
if (this.#rewardSelectionService.canOpen()) {
const result = await this.#rewardSelectionService.open({
closeText: 'Abbrechen'
});
if (result) {
// Handle the result
console.log('Updated items:', result.rewardSelectionItems);
}
}
}
}
```
#### Using RewardSelectionPopUpService
For automatic popup behavior (e.g., showing dialog once per session):
```ts
import { inject } from '@angular/core';
import {
RewardSelectionPopUpService,
NavigateAfterRewardSelection
} from '@isa/checkout/shared/reward-selection-dialog';
export class CheckoutComponent {
#popUpService = inject(RewardSelectionPopUpService);
async showPopupIfNeeded() {
const navigation = await this.#popUpService.popUp();
switch (navigation) {
case NavigateAfterRewardSelection.CART:
// Navigate to regular shopping cart
break;
case NavigateAfterRewardSelection.REWARD:
// Navigate to reward checkout
break;
case NavigateAfterRewardSelection.CATALOG:
// Navigate back to catalog
break;
case undefined:
// Stay on current page
break;
}
}
}
```
#### Using RewardSelectionTriggerComponent
Add the trigger component directly to your template:
```html
<lib-reward-selection-trigger />
```
The trigger component:
- Automatically determines eligibility
- Shows loading skeleton during resource fetching
- Opens dialog on click
- Handles navigation after selection
## Usage Examples
### Basic Dialog Integration
```ts
import { Component, inject } from '@angular/core';
import { RewardSelectionService } from '@isa/checkout/shared/reward-selection-dialog';
@Component({
selector: 'app-checkout',
template: `
<button (click)="openRewardSelection()">
Select Reward Items
</button>
`,
providers: [RewardSelectionService]
})
export class CheckoutComponent {
#rewardSelectionService = inject(RewardSelectionService);
async openRewardSelection() {
await this.#rewardSelectionService.reloadResources();
if (this.#rewardSelectionService.canOpen()) {
const result = await this.#rewardSelectionService.open({
closeText: 'Cancel'
});
if (result?.rewardSelectionItems.length) {
// Process updated selections
}
}
}
}
```
### Using Trigger Component
```ts
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],
selector: 'app-cart-summary',
template: `
<div class="cart-actions">
<lib-reward-selection-trigger />
<button>Proceed to Checkout</button>
</div>
`,
imports: [RewardSelectionTriggerComponent]
})
export class CheckoutComponent {}
export class CartSummaryComponent {}
```
### Using the Pop-Up Service
### One-Time Popup on Checkout Entry
More control over navigation flow:
```typescript
import { Component, inject } from '@angular/core';
```ts
import { Component, inject, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import {
RewardSelectionPopUpService,
NavigateAfterRewardSelection,
RewardSelectionService,
NavigateAfterRewardSelection
} 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,
RewardSelectionService,
RewardSelectionPopUpService,
],
selector: 'app-checkout-entry',
template: `<p>Loading checkout...</p>`,
providers: [RewardSelectionPopUpService]
})
export class CustomCheckoutComponent {
export class CheckoutEntryComponent implements OnInit {
#router = inject(Router);
#popUpService = inject(RewardSelectionPopUpService);
async openRewardSelection() {
async ngOnInit() {
const result = await this.#popUpService.popUp();
// Handle navigation: 'cart' | 'reward' | 'catalog' | undefined
if (result === NavigateAfterRewardSelection.CART) {
// Navigate to cart
await this.#router.navigate(['/cart']);
} else if (result === NavigateAfterRewardSelection.REWARD) {
await this.#router.navigate(['/reward-checkout']);
}
}
}
```
### Using the Service Directly
### Checking Eligibility
For custom UI or advanced use cases:
```typescript
import { Component, inject } from '@angular/core';
```ts
import { Component, inject, computed } from '@angular/core';
import { RewardSelectionService } from '@isa/checkout/shared/reward-selection-dialog';
import {
SelectedShoppingCartResource,
} from '@isa/checkout/data-access';
@Component({
selector: 'app-advanced',
selector: 'app-cart',
template: `
@if (canOpen()) {
<button (click)="openDialog()" [disabled]="isLoading()">
{{ eligibleItemsCount() }} items as rewards ({{ availablePoints() }} points)
</button>
@if (hasRewardEligibleItems()) {
<div class="reward-banner">
You have items eligible for reward redemption!
<button (click)="openDialog()">Choose Payment Method</button>
</div>
}
`,
providers: [
SelectedShoppingCartResource,
RewardSelectionService,
],
providers: [RewardSelectionService]
})
export class AdvancedComponent {
#service = inject(RewardSelectionService);
export class CartComponent {
#rewardSelectionService = inject(RewardSelectionService);
canOpen = this.#service.canOpen;
isLoading = this.#service.isLoading;
eligibleItemsCount = computed(() => this.#service.eligibleItems().length);
availablePoints = this.#service.primaryBonusCardPoints;
hasRewardEligibleItems = this.#rewardSelectionService.canOpen;
async openDialog() {
const result = await this.#service.open({ closeText: 'Cancel' });
if (result) {
// Handle result.rewardSelectionItems
await this.#service.reloadResources();
}
const result = await this.#rewardSelectionService.open({
closeText: 'Cancel'
});
// Handle result...
}
}
```
## API Reference
## State Management
### RewardSelectionService
The library uses `RewardSelectionStore` (NgRx Signal Store) internally to manage:
**Key Signals:**
- `canOpen()`: `boolean` - Can dialog be opened
- `isLoading()`: `boolean` - Loading state
- `eligibleItems()`: `RewardSelectionItem[]` - Items available as rewards
- `primaryBonusCardPoints()`: `number` - Available points
- **State:** Item allocations, customer loyalty points
- **Computed Values:** Total price, total loyalty points needed
- **Methods:** Update cart quantities, update reward cart quantities
**Methods:**
- `open({ closeText }): Promise<RewardSelectionDialogResult>` - Opens dialog
- `reloadResources(): Promise<void>` - Reloads all data
The store is scoped to each dialog instance and automatically initialized with dialog data.
### RewardSelectionPopUpService
## Validation
**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
```typescript
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:
```typescript
providers: [
SelectedShoppingCartResource, // Regular cart data
RewardSelectionService, // Core service
RewardSelectionPopUpService, // Optional: only if using pop-up
]
```
**Note:** `RewardSelectionTriggerComponent` includes all required providers automatically.
## Testing
```bash
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
```
The dialog automatically validates:
- Customer has sufficient loyalty points for selected reward items
- Items are eligible for reward redemption (have loyalty points configured)
- Changes were made before saving (prevents unnecessary API calls)
## 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
Key dependencies on other @isa libraries:
- **@isa/checkout/data-access**: Shopping cart resources, reward selection models and facades
- **@isa/ui/dialog**: Dialog infrastructure and directives
- **@isa/ui/buttons**: Button components
- **@isa/core/tabs**: Tab ID management for multi-tab support
- **@isa/crm/data-access**: Customer card resource for loyalty points
- **@isa/icons**: Order type icons for grouping display
- **@ngrx/signals**: Signal Store for state management
## Architecture
The library follows a layered architecture:
1. **Presentation Layer**: Dialog and trigger components
2. **State Layer**: Signal Store for reactive state management
3. **Service Layer**: Dialog lifecycle and popup behavior services
4. **Resource Layer**: Price and redemption points loading
5. **Integration Layer**: Shopping cart and customer card resources
This separation ensures the dialog can be used in various contexts (manual trigger, automatic popup, embedded component) while maintaining consistent behavior and state management.