# Scanner Library

## Overview

The Scanner library provides barcode scanning capabilities for the ISA application using the [Scandit SDK](https://www.scandit.com/). It offers a complete solution for mobile barcode scanning with support for various barcode formats, ready-state detection, and seamless form integration.

## Features

- Barcode scanning with support for multiple symbologies:
  - EAN8
  - EAN13/UPCA
  - UPCE
  - Code128
  - Code39
  - Code93
  - Interleaved 2 of 5
  - QR Code
- Platform detection (iOS/Android support)
- Ready-state detection with conditional rendering
- Form control integration via output bindings
- Configuration through injection tokens
- Error handling for unsupported platforms

## Components and Directives

### ScannerButtonComponent

A button component that integrates with the scanner service to trigger barcode scanning. It implements `OnDestroy` to properly clean up resources.

**Features:**

- Only appears when scanner is ready
- Can be disabled through binding
- Configurable size
- Emits scanned value through output binding
- Includes E2E testing attribute `data-which="scan-button"`

**Usage Example:**

```typescript
import { ScannerButtonComponent } from '@isa/core/scanner';

@Component({
  selector: 'app-my-component',
  template: `
    <shared-scanner-button
      [disabled]="isDisabled"
      [size]="'large'"
      (scan)="onScan($event)"
    >
    </shared-scanner-button>
  `,
  imports: [ScannerButtonComponent],
  standalone: true,
})
export class MyComponent {
  isDisabled = false;

  onScan(value: string | null) {
    console.log('Scanned barcode:', value);
  }
}
```

### ScannerReadyDirective

A structural directive (`*sharedScannerReady`) that conditionally renders its content based on the scanner's ready state. Similar to `*ngIf`, but specifically tied to scanner readiness.

**Features:**

- Only renders content when the scanner is ready
- Supports an optional else template for when the scanner is not ready
- Uses Angular's effect system for reactive updates

**Usage Example:**

```typescript
import { ScannerReadyDirective } from '@isa/core/scanner';

@Component({
  selector: 'app-my-component',
  template: `
    <div *sharedScannerReady>
      <!-- Content only shown when scanner is ready -->
      <p>Scanner is ready to use</p>
      <button (click)="startScanning()">Scan Now</button>
    </div>

    <!-- Alternative with else template -->
    <div *sharedScannerReady="; else notReady">
      <p>Scanner is ready</p>
    </div>

    <ng-template #notReady>
      <p>Scanner is not yet ready</p>
      <app-spinner></app-spinner>
    </ng-template>
  `,
  imports: [ScannerReadyDirective],
  standalone: true,
})
export class MyComponent {
  // Component logic
}
```

### ScannerComponent

Internal component used by ScannerService to render the camera view and process barcode scanning.

**Features:**

- Integrates with Scandit SDK
- Handles camera setup and barcode detection
- Emits scanned values
- Includes a close button to cancel scanning

## Services

### ScannerService

Core service that provides barcode scanning functionality.

**Features:**

- Initializes and configures Scandit SDK
- Checks platform compatibility
- Manages scanner lifecycle
- Provides a reactive `ready` signal
- Handles scanning operations with proper cleanup

**Usage Example:**

```typescript
import { ScannerService, ScannerInputs } from '@isa/core/scanner';
import { Component, inject } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `
    <button (click)="scan()" [disabled]="!isReady()">Scan Barcode</button>
    <div *ngIf="result">Last Scan: {{ result }}</div>
  `,
  standalone: true,
})
export class MyComponent {
  private scannerService = inject(ScannerService);
  isReady = this.scannerService.ready;
  result: string | null = null;

  async scan() {
    const options: ScannerInputs = {
      // Optional configuration
      // symbologies: [...] // Specify barcode types
    };

    try {
      this.result = await this.scannerService.open(options);
    } catch (error) {
      console.error('Scanning failed:', error);
    }
  }
}
```

## Configuration

The scanner module uses injection tokens for configuration:

- `SCANDIT_LICENSE` - The Scandit license key (defaults to config value at 'licence.scandit')
- `SCANDIT_LIBRARY_LOCATION` - The location of the Scandit library (defaults to '/scandit' relative to base URI)
- `SCANDIT_DEFAULT_SYMBOLOGIES` - The default barcode symbologies to use

**Custom Configuration Example:**

```typescript
import { SCANDIT_LICENSE, SCANDIT_LIBRARY_LOCATION } from '@isa/core/scanner';
import { Symbology } from 'scandit-web-datacapture-barcode';

@NgModule({
  providers: [
    // Custom license key
    {
      provide: SCANDIT_LICENSE,
      useValue: 'YOUR-SCANDIT-LICENSE-KEY',
    },
    // Custom library location
    {
      provide: SCANDIT_LIBRARY_LOCATION,
      useValue: 'https://cdn.example.com/scandit/',
    },
  ],
})
export class AppModule {}
```

## Error Handling

The scanner library includes error handling for various scenarios:

- `PlatformNotSupportedError` is thrown when the scanner is used on unsupported platforms
- Configuration errors are logged and propagated
- Aborted scan operations are handled gracefully

## Requirements

- The Scandit SDK must be properly installed and configured
- Requires a valid Scandit license key
- Currently supports iOS and Android platforms

## E2E Testing

The scanner components include E2E testing attributes for easier selection in automated tests:

- ScannerButton includes `data-which="scan-button"` for E2E test selection
