# @isa/checkout/feature/select-branch-dropdown

Branch selection dropdown components for the checkout domain, enabling users to select a branch for their checkout session.

## Overview

The Select Branch Dropdown feature library provides two UI components for branch selection in the checkout flow:

- **SelectedBranchDropdownComponent** - High-level component that integrates with `CheckoutMetadataService` for automatic persistence
- **BranchDropdownComponent** - Low-level component with `ControlValueAccessor` support for custom form integration

## Table of Contents

- [Features](#features)
- [Quick Start](#quick-start)
- [Component API Reference](#component-api-reference)
- [Usage Examples](#usage-examples)
- [State Management](#state-management)
- [Dependencies](#dependencies)
- [Testing](#testing)
- [Best Practices](#best-practices)

## Features

- **Branch Selection** - Dropdown interface for selecting a branch
- **Metadata Integration** - Persists selected branch in checkout metadata via `CheckoutMetadataService.setSelectedBranch()`
- **Standalone Component** - Modern Angular standalone architecture
- **Responsive Design** - Works across tablet and desktop layouts
- **E2E Testing Support** - Includes data-what and data-which attributes

## Quick Start

### 1. Import the Component

```typescript
import { SelectedBranchDropdownComponent } from '@isa/checkout/feature/select-branch-dropdown';

@Component({
  selector: 'app-checkout',
  imports: [SelectedBranchDropdownComponent],
  template: `
    <checkout-selected-branch-dropdown [tabId]="tabId()" />
  `
})
export class CheckoutComponent {
  tabId = injectTabId();
}
```

### 2. Using the Low-Level Component with Forms

```typescript
import { BranchDropdownComponent } from '@isa/checkout/feature/select-branch-dropdown';

@Component({
  selector: 'app-branch-form',
  imports: [BranchDropdownComponent, ReactiveFormsModule],
  template: `
    <checkout-branch-dropdown formControlName="branch" />
  `
})
export class BranchFormComponent {}
```

## Component API Reference

### SelectedBranchDropdownComponent

High-level branch selection component with automatic `CheckoutMetadataService` integration.

**Selector:** `checkout-selected-branch-dropdown`

**Inputs:**
| Input | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `tabId` | `number` | Yes | - | The tab ID for metadata storage |
| `appearance` | `DropdownAppearance` | No | `AccentOutline` | Visual style of the dropdown |

**Example:**
```html
<checkout-selected-branch-dropdown
  [tabId]="tabId()"
  [appearance]="DropdownAppearance.AccentOutline"
/>
```

---

### BranchDropdownComponent

Low-level branch dropdown with `ControlValueAccessor` support for reactive forms.

**Selector:** `checkout-branch-dropdown`

**Inputs:**
| Input | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `appearance` | `DropdownAppearance` | No | `AccentOutline` | Visual style of the dropdown |

**Outputs:**
| Output | Type | Description |
|--------|------|-------------|
| `selected` | `Branch \| null` | Two-way bindable selected branch (model) |

**Example:**
```html
<!-- With ngModel -->
<checkout-branch-dropdown [(selected)]="selectedBranch" />

<!-- With reactive forms -->
<checkout-branch-dropdown formControlName="branch" />
```

## Usage Examples

### Basic Usage in Checkout Flow

```typescript
import { Component } from '@angular/core';
import { SelectedBranchDropdownComponent } from '@isa/checkout/feature/select-branch-dropdown';
import { injectTabId } from '@isa/core/tabs';

@Component({
  selector: 'app-checkout-header',
  imports: [SelectedBranchDropdownComponent],
  template: `
    <div class="checkout-header">
      <h1>Checkout</h1>
      <checkout-selected-branch-dropdown [tabId]="tabId()" />
    </div>
  `
})
export class CheckoutHeaderComponent {
  tabId = injectTabId();
}
```

### Using BranchDropdownComponent with Reactive Forms

```typescript
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { BranchDropdownComponent } from '@isa/checkout/feature/select-branch-dropdown';

@Component({
  selector: 'app-branch-form-example',
  imports: [BranchDropdownComponent, ReactiveFormsModule],
  template: `
    <form [formGroup]="form">
      <checkout-branch-dropdown formControlName="branch" />
    </form>
  `
})
export class BranchFormExampleComponent {
  #fb = inject(FormBuilder);
  form = this.#fb.group({
    branch: [null]
  });
}
```

### Reading Selected Branch from Metadata

```typescript
import { Component, inject, computed } from '@angular/core';
import { CheckoutMetadataService } from '@isa/checkout/data-access';
import { injectTabId } from '@isa/core/tabs';

@Component({
  selector: 'app-branch-reader-example',
  template: `
    @if (selectedBranch(); as branch) {
      <p>Selected Branch: {{ branch.name }}</p>
    } @else {
      <p>No branch selected</p>
    }
  `
})
export class BranchReaderExampleComponent {
  #checkoutMetadata = inject(CheckoutMetadataService);
  tabId = injectTabId();

  selectedBranch = computed(() => {
    return this.#checkoutMetadata.getSelectedBranch(this.tabId()!);
  });
}
```

## State Management

### CheckoutMetadataService Integration

The component integrates with `CheckoutMetadataService` from `@isa/checkout/data-access`:

```typescript
// Set selected branch (stores the full Branch object)
this.#checkoutMetadata.setSelectedBranch(tabId, branch);

// Get selected branch (returns Branch | undefined)
const branch = this.#checkoutMetadata.getSelectedBranch(tabId);

// Clear selected branch
this.#checkoutMetadata.setSelectedBranch(tabId, undefined);
```

**State Persistence:**
- Branch selection persists in tab metadata
- Available across all checkout components in the same tab
- Cleared when tab is closed or session ends

## Dependencies

### Required Libraries

#### Angular Core
- `@angular/core` - Angular framework
- `@angular/forms` - Form controls and ControlValueAccessor

#### ISA Feature Libraries
- `@isa/checkout/data-access` - CheckoutMetadataService, BranchesResource, Branch type
- `@isa/core/logging` - Logger utility

#### ISA UI Libraries
- `@isa/ui/input-controls` - DropdownButtonComponent, DropdownFilterComponent, DropdownOptionComponent

### Path Alias

Import from: `@isa/checkout/feature/select-branch-dropdown`

```typescript
// Import components
import {
  SelectedBranchDropdownComponent,
  BranchDropdownComponent
} from '@isa/checkout/feature/select-branch-dropdown';
```

## Testing

The library uses **Vitest** with **Angular Testing Utilities** for testing.

### Running Tests

```bash
# Run tests for this library
npx nx test checkout-feature-select-branch-dropdown --skip-nx-cache

# Run tests with coverage
npx nx test checkout-feature-select-branch-dropdown --coverage.enabled=true --skip-nx-cache

# Run tests in watch mode
npx nx test checkout-feature-select-branch-dropdown --watch
```

### Test Configuration

- **Framework:** Vitest
- **Test Runner:** @nx/vite:test
- **Coverage:** v8 provider with Cobertura reports
- **JUnit XML:** `testresults/junit-checkout-feature-select-branch-dropdown.xml`
- **Coverage XML:** `coverage/libs/checkout/feature/select-branch-dropdown/cobertura-coverage.xml`

### Testing Recommendations

#### Component Testing

```typescript
import { TestBed } from '@angular/core/testing';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { SelectedBranchDropdownComponent } from './selected-branch-dropdown.component';
import { CheckoutMetadataService, BranchesResource } from '@isa/checkout/data-access';
import { signal } from '@angular/core';

describe('SelectedBranchDropdownComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [SelectedBranchDropdownComponent],
      providers: [
        {
          provide: CheckoutMetadataService,
          useValue: {
            setSelectedBranch: vi.fn(),
            getSelectedBranch: vi.fn(() => null)
          }
        },
        {
          provide: BranchesResource,
          useValue: {
            resource: {
              hasValue: () => true,
              value: () => []
            }
          }
        }
      ]
    });
  });

  it('should create', () => {
    const fixture = TestBed.createComponent(SelectedBranchDropdownComponent);
    fixture.componentRef.setInput('tabId', 1);
    fixture.detectChanges();
    expect(fixture.componentInstance).toBeTruthy();
  });
});
```

### E2E Attribute Requirements

All interactive elements should include `data-what` and `data-which` attributes:

```html
<!-- Dropdown -->
<select
  data-what="branch-dropdown"
  data-which="branch-selection">
</select>

<!-- Option -->
<option
  data-what="branch-option"
  [attr.data-which]="branch.id">
</option>
```

## Best Practices

### 1. Always Use Tab Context

Ensure tab context is available when using the component:

```typescript
// Good
const tabId = this.#tabService.activatedTabId();
if (tabId) {
  this.#checkoutMetadata.setSelectedBranch(tabId, branch);
}

// Bad (missing tab context validation)
this.#checkoutMetadata.setSelectedBranch(null, branch);
```

### 2. Clear Branch on Checkout Completion

Always clear branch selection when checkout is complete:

```typescript
// Good
completeCheckout() {
  // ... checkout logic
  this.#checkoutMetadata.setSelectedBranch(tabId, undefined);
}

// Bad (leaves stale branch)
completeCheckout() {
  // ... checkout logic
  // Forgot to clear branch!
}
```

### 3. Use Computed Signals for Derived State

Leverage Angular signals for reactive values:

```typescript
// Good
selectedBranch = computed(() => {
  return this.#checkoutMetadata.getSelectedBranch(this.tabId()!);
});

// Bad (manual tracking)
selectedBranch: Branch | undefined;
ngOnInit() {
  effect(() => {
    this.selectedBranch = this.#checkoutMetadata.getSelectedBranch(this.tabId()!);
  });
}
```

### 4. Follow OnPush Change Detection

Always use OnPush change detection for performance:

```typescript
// Good
@Component({
  selector: 'checkout-select-branch-dropdown',
  changeDetection: ChangeDetectionStrategy.OnPush,
  // ...
})

// Bad (default change detection)
@Component({
  selector: 'checkout-select-branch-dropdown',
  // Missing changeDetection
})
```

### 5. Add E2E Attributes

Always include data-what and data-which attributes:

```typescript
// Good
<select
  data-what="branch-dropdown"
  data-which="branch-selection"
  [(ngModel)]="selectedBranch">
</select>

// Bad (no E2E attributes)
<select [(ngModel)]="selectedBranch">
</select>
```

## Architecture Notes

### Component Structure

```
SelectedBranchDropdownComponent (high-level, with metadata integration)
├── Uses BranchDropdownComponent internally
├── CheckoutMetadataService integration
├── Tab context via tabId input
└── Automatic branch persistence

BranchDropdownComponent (low-level, form-compatible)
├── ControlValueAccessor implementation
├── BranchesResource for loading options
├── DropdownButtonComponent from @isa/ui/input-controls
└── Filter support via DropdownFilterComponent
```

### Data Flow

```
SelectedBranchDropdownComponent:
1. Component receives tabId input
   ↓
2. Reads current branch from CheckoutMetadataService.getSelectedBranch(tabId)
   ↓
3. User selects branch from dropdown
   ↓
4. setSelectedBranch(tabId, branch) called
   ↓
5. Other checkout components react to metadata change

BranchDropdownComponent:
1. BranchesResource loads available branches
   ↓
2. User selects branch from dropdown
   ↓
3. selected model emits new value
   ↓
4. ControlValueAccessor notifies form (if used with forms)
```

## License

Internal ISA Frontend library - not for external distribution.
