mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
📝 docs: update README documentation for 13 libraries
This commit is contained in:
@@ -1,169 +1,232 @@
|
||||
# Scanner Library
|
||||
# @isa/shared/scanner
|
||||
|
||||
Enterprise-grade barcode scanning library for ISA-Frontend using the Scandit SDK, providing mobile barcode scanning capabilities for iOS and Android platforms.
|
||||
|
||||
## Overview
|
||||
|
||||
The `@isa/shared/scanner` library provides enterprise-grade barcode scanning capabilities for the ISA application using the [Scandit SDK](https://www.scandit.com/). It offers a complete, production-ready solution for mobile barcode scanning with comprehensive support for multiple symbologies, platform detection (iOS/Android), ready-state management, and seamless integration with Angular forms and reactive patterns.
|
||||
The `@isa/shared/scanner` library provides a complete, production-ready solution for mobile barcode scanning with comprehensive support for multiple symbologies, platform detection, ready-state management, and seamless integration with Angular's reactive patterns. Built on the [Scandit SDK](https://www.scandit.com/), it offers ready-to-use components, directives, and services for implementing barcode scanning workflows throughout the ISA application.
|
||||
|
||||
**Key Use Cases:**
|
||||
- Barcode scanning for product lookup and inventory management
|
||||
- Product lookup and inventory management
|
||||
- Order processing and verification
|
||||
- Returns and remission workflows
|
||||
- Asset tracking and identification
|
||||
- QR code scanning for digital workflows
|
||||
|
||||
**Type:** Shared component library with services, directives, and ready-to-use UI components
|
||||
**Type:** Shared component library (UI + Services)
|
||||
|
||||
## Installation
|
||||
|
||||
```ts
|
||||
import {
|
||||
ScannerService,
|
||||
ScannerButtonComponent,
|
||||
ScannerReadyDirective
|
||||
} from '@isa/shared/scanner';
|
||||
```
|
||||
|
||||
## 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
|
||||
- **Multiple Symbologies:** EAN-8, EAN-13/UPC-A, UPC-E, Code 128, Code 39, Code 93, Interleaved 2 of 5, QR Code
|
||||
- **Platform Detection:** Automatic iOS/Android detection with unsupported platform handling
|
||||
- **Ready-State Management:** Reactive signals for scanner initialization status
|
||||
- **Overlay UI:** Full-screen camera overlay with CDK integration
|
||||
- **Form Integration:** Output bindings for Angular forms
|
||||
- **Configurable:** Injection tokens for license key, library location, and symbologies
|
||||
- **TypeScript:** Full type safety with Zod schema validation
|
||||
- **Logging:** Integrated with `@isa/core/logging` for debugging
|
||||
- **E2E Testing:** E2E attributes for automated testing (`data-which="scan-button"`)
|
||||
|
||||
## Components and Directives
|
||||
## API Reference
|
||||
|
||||
### ScannerButtonComponent
|
||||
### Services
|
||||
|
||||
A button component that integrates with the scanner service to trigger barcode scanning. It implements `OnDestroy` to properly clean up resources.
|
||||
#### `ScannerService`
|
||||
|
||||
Core service that manages barcode scanning functionality using the Scandit SDK.
|
||||
|
||||
**Properties:**
|
||||
|
||||
- `ready: Signal<boolean>` - Computed signal indicating whether the scanner is initialized and ready to use. Automatically triggers configuration on first access.
|
||||
|
||||
**Methods:**
|
||||
|
||||
- `configure(): Promise<void>` - Manually configure the Scandit SDK. Called automatically by `open()` and the `ready` signal. Handles platform compatibility checks and license validation.
|
||||
- `open(options?: ScannerInputs): Promise<string | null>` - Opens the scanner overlay interface and returns a promise that resolves to the scanned barcode value. Returns `null` if the user cancels scanning.
|
||||
|
||||
**Configuration Options (`ScannerInputs`):**
|
||||
|
||||
```ts
|
||||
type ScannerInputs = {
|
||||
symbologies?: Symbology[]; // Override default barcode types
|
||||
abortSignal?: AbortSignal; // Cancel scanning operation
|
||||
};
|
||||
```
|
||||
|
||||
**Scanner Status:**
|
||||
|
||||
The service tracks initialization through the following states:
|
||||
- `None` - Initial state, not yet initialized
|
||||
- `Initializing` - Configuration in progress
|
||||
- `Ready` - Scanner fully initialized and ready for use
|
||||
- `Error` - Initialization failed
|
||||
|
||||
**Platform Support:**
|
||||
|
||||
Only iOS and Android platforms are supported. Attempting to use the scanner on unsupported platforms will log a warning and prevent initialization. The service throws `PlatformNotSupportedError` for unsupported platforms.
|
||||
|
||||
**Default Symbologies:**
|
||||
|
||||
The scanner recognizes the following barcode formats by default:
|
||||
- EAN-8
|
||||
- EAN-13 / UPC-A
|
||||
- UPC-E
|
||||
- Code 128
|
||||
- Code 39
|
||||
- Code 93
|
||||
- Interleaved 2 of 5
|
||||
- QR Code
|
||||
|
||||
### Components
|
||||
|
||||
#### `ScannerButtonComponent`
|
||||
|
||||
A ready-to-use button component that triggers the barcode scanner when clicked. Automatically handles scanner lifecycle and cleanup.
|
||||
|
||||
**Selector:** `shared-scanner-button`
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `size: InputSignal<IconButtonSize>` - Button size (default: `'large'`)
|
||||
- `disabled: ModelSignal<boolean>` - Whether the button is disabled (default: `false`)
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `scan: OutputEmitterRef<string | null>` - Emits the scanned barcode value or `null` if the user cancels
|
||||
|
||||
**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"`
|
||||
- Only visible when scanner is ready (uses `*sharedScannerReady` directive internally)
|
||||
- Opens full-screen scanner overlay on click
|
||||
- Automatically aborts scanning operations on component destroy
|
||||
- Includes E2E testing attribute: `data-which="scan-button"`
|
||||
- Primary color styling with scanner icon
|
||||
|
||||
**Usage Example:**
|
||||
**Lifecycle:**
|
||||
|
||||
```typescript
|
||||
import { ScannerButtonComponent } from '@isa/core/scanner';
|
||||
- Implements `OnDestroy` to abort any in-progress scanning operations
|
||||
- Uses `AbortController` for proper cleanup
|
||||
|
||||
@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;
|
||||
#### `ScannerComponent`
|
||||
|
||||
onScan(value: string | null) {
|
||||
console.log('Scanned barcode:', value);
|
||||
}
|
||||
Internal component that renders the camera view and handles barcode detection. Used by `ScannerService` via CDK overlay and typically not used directly in application code.
|
||||
|
||||
**Selector:** `shared-scanner`
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `symbologies: InputSignal<Symbology[]>` - Array of barcode types to detect
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `scan: OutputEmitterRef<string>` - Emits detected barcode data
|
||||
|
||||
**Features:**
|
||||
|
||||
- Full-screen camera view with close button
|
||||
- Progress indicator during initialization
|
||||
- Zone-aware event handling for optimal change detection
|
||||
- Automatic camera lifecycle management (on/off)
|
||||
- Cleanup on destroy to prevent memory leaks
|
||||
|
||||
### Directives
|
||||
|
||||
#### `ScannerReadyDirective`
|
||||
|
||||
Structural directive that conditionally renders content based on scanner ready state. Similar to `*ngIf`, but specifically tied to scanner initialization status.
|
||||
|
||||
**Selector:** `*sharedScannerReady`
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `scannerReadyElse: InputSignal<TemplateRef<unknown> | undefined>` - Optional template to show when scanner is not ready (similar to `*ngIf` else template)
|
||||
|
||||
**Features:**
|
||||
|
||||
- Reactive to scanner status changes using Angular effects
|
||||
- Supports else template for fallback content
|
||||
- Automatically updates when scanner becomes ready
|
||||
- No manual subscription management required
|
||||
|
||||
### Injection Tokens
|
||||
|
||||
#### `SCANDIT_LICENSE`
|
||||
|
||||
Injection token for the Scandit license key.
|
||||
|
||||
**Default:** Retrieves from application config at `licence.scandit` path
|
||||
**Type:** `InjectionToken<string>`
|
||||
|
||||
#### `SCANDIT_LIBRARY_LOCATION`
|
||||
|
||||
Injection token for the Scandit SDK library location.
|
||||
|
||||
**Default:** `/scandit` relative to `document.baseURI`
|
||||
**Type:** `InjectionToken<string>`
|
||||
|
||||
#### `SCANDIT_DEFAULT_SYMBOLOGIES`
|
||||
|
||||
Injection token for the default barcode symbologies to scan.
|
||||
|
||||
**Default:** Array of common symbologies (EAN, UPC, Code128, Code39, Code93, ITF, QR)
|
||||
**Type:** `InjectionToken<Symbology[]>`
|
||||
|
||||
### Errors
|
||||
|
||||
#### `PlatformNotSupportedError`
|
||||
|
||||
Thrown when attempting to use the scanner on non-mobile platforms.
|
||||
|
||||
```ts
|
||||
export class PlatformNotSupportedError extends Error {
|
||||
constructor(); // Message: "ScannerService is only supported on iOS and Android platforms"
|
||||
}
|
||||
```
|
||||
|
||||
### ScannerReadyDirective
|
||||
**Behavior:**
|
||||
- Caught by `ScannerService.configure()` and logged as a warning
|
||||
- Prevents scanner initialization on unsupported platforms
|
||||
- Does not crash the application
|
||||
|
||||
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.
|
||||
## Usage Examples
|
||||
|
||||
**Features:**
|
||||
### Basic Programmatic Scanning
|
||||
|
||||
- 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';
|
||||
```ts
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { ScannerService } from '@isa/shared/scanner';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-component',
|
||||
selector: 'app-checkout',
|
||||
template: `
|
||||
<button (click)="scan()" [disabled]="!isReady()">Scan Barcode</button>
|
||||
<div *ngIf="result">Last Scan: {{ result }}</div>
|
||||
`,
|
||||
standalone: true,
|
||||
<button (click)="scanProduct()">Scan Product</button>
|
||||
@if (scannedCode) {
|
||||
<p>Scanned: {{ scannedCode }}</p>
|
||||
}
|
||||
`
|
||||
})
|
||||
export class MyComponent {
|
||||
private scannerService = inject(ScannerService);
|
||||
isReady = this.scannerService.ready;
|
||||
result: string | null = null;
|
||||
export class CheckoutComponent {
|
||||
#scannerService = inject(ScannerService);
|
||||
|
||||
async scan() {
|
||||
const options: ScannerInputs = {
|
||||
// Optional configuration
|
||||
// symbologies: [...] // Specify barcode types
|
||||
};
|
||||
scannedCode: string | null = null;
|
||||
|
||||
async scanProduct() {
|
||||
try {
|
||||
this.result = await this.scannerService.open(options);
|
||||
this.scannedCode = await this.#scannerService.open();
|
||||
if (this.scannedCode) {
|
||||
console.log('Product code:', this.scannedCode);
|
||||
// Process the scanned code (e.g., fetch product details)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Scanning failed:', error);
|
||||
}
|
||||
@@ -171,53 +234,381 @@ export class MyComponent {
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
### Using Scanner Button Component
|
||||
|
||||
The scanner module uses injection tokens for configuration:
|
||||
```ts
|
||||
import { Component } from '@angular/core';
|
||||
import { ScannerButtonComponent } from '@isa/shared/scanner';
|
||||
|
||||
- `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
|
||||
@Component({
|
||||
selector: 'app-inventory',
|
||||
imports: [ScannerButtonComponent],
|
||||
template: `
|
||||
<h2>Inventory Lookup</h2>
|
||||
|
||||
**Custom Configuration Example:**
|
||||
<shared-scanner-button
|
||||
[size]="'large'"
|
||||
[disabled]="isProcessing"
|
||||
(scan)="onScan($event)"
|
||||
/>
|
||||
|
||||
```typescript
|
||||
import { SCANDIT_LICENSE, SCANDIT_LIBRARY_LOCATION } from '@isa/core/scanner';
|
||||
@if (lastScan) {
|
||||
<div class="scan-result">
|
||||
<p>Last scanned: {{ lastScan }}</p>
|
||||
<p>Product: {{ productName }}</p>
|
||||
</div>
|
||||
}
|
||||
`
|
||||
})
|
||||
export class InventoryComponent {
|
||||
lastScan: string | null = null;
|
||||
productName: string = '';
|
||||
isProcessing = false;
|
||||
|
||||
async onScan(code: string | null) {
|
||||
if (code) {
|
||||
this.lastScan = code;
|
||||
this.isProcessing = true;
|
||||
await this.processBarcode(code);
|
||||
this.isProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async processBarcode(code: string) {
|
||||
// Fetch product details from API
|
||||
const response = await fetch(`/api/products/${code}`);
|
||||
const product = await response.json();
|
||||
this.productName = product.name;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scanning with Custom Symbologies
|
||||
|
||||
```ts
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { ScannerService } from '@isa/shared/scanner';
|
||||
import { Symbology } from 'scandit-web-datacapture-barcode';
|
||||
|
||||
@NgModule({
|
||||
@Component({
|
||||
selector: 'app-qr-scanner',
|
||||
template: `
|
||||
<button (click)="scanQRCode()">Scan QR Code Only</button>
|
||||
<button (click)="scanEAN()">Scan Product Barcode</button>
|
||||
`
|
||||
})
|
||||
export class QRScannerComponent {
|
||||
#scannerService = inject(ScannerService);
|
||||
|
||||
async scanQRCode() {
|
||||
// Only scan QR codes
|
||||
const result = await this.#scannerService.open({
|
||||
symbologies: [Symbology.QR]
|
||||
});
|
||||
|
||||
if (result) {
|
||||
this.handleQRCode(result);
|
||||
}
|
||||
}
|
||||
|
||||
async scanEAN() {
|
||||
// Only scan EAN barcodes
|
||||
const result = await this.#scannerService.open({
|
||||
symbologies: [Symbology.EAN8, Symbology.EAN13UPCA]
|
||||
});
|
||||
|
||||
if (result) {
|
||||
this.handleProductCode(result);
|
||||
}
|
||||
}
|
||||
|
||||
private handleQRCode(data: string) {
|
||||
console.log('QR Code:', data);
|
||||
}
|
||||
|
||||
private handleProductCode(code: string) {
|
||||
console.log('Product Code:', code);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Scanner Ready Directive
|
||||
|
||||
```ts
|
||||
import { Component } from '@angular/core';
|
||||
import { ScannerButtonComponent, ScannerReadyDirective } from '@isa/shared/scanner';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-lookup',
|
||||
imports: [ScannerButtonComponent, ScannerReadyDirective],
|
||||
template: `
|
||||
<div *sharedScannerReady="; else scannerNotReady">
|
||||
<h2>Scan Product Barcode</h2>
|
||||
<p>Point your camera at a barcode to scan</p>
|
||||
<shared-scanner-button (scan)="onScan($event)" />
|
||||
</div>
|
||||
|
||||
<ng-template #scannerNotReady>
|
||||
<div class="fallback">
|
||||
<p>Camera scanner is not available on this device</p>
|
||||
<p>Please enter the barcode manually:</p>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter barcode"
|
||||
(input)="onManualEntry($event)"
|
||||
/>
|
||||
</div>
|
||||
</ng-template>
|
||||
`
|
||||
})
|
||||
export class ProductLookupComponent {
|
||||
onScan(code: string | null) {
|
||||
if (code) {
|
||||
this.lookupProduct(code);
|
||||
}
|
||||
}
|
||||
|
||||
onManualEntry(event: Event) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
if (input.value.length >= 8) {
|
||||
this.lookupProduct(input.value);
|
||||
}
|
||||
}
|
||||
|
||||
private lookupProduct(barcode: string) {
|
||||
console.log('Looking up product:', barcode);
|
||||
// Fetch product by barcode
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Cancelling a Scan Operation
|
||||
|
||||
```ts
|
||||
import { Component, inject, OnDestroy } from '@angular/core';
|
||||
import { ScannerService } from '@isa/shared/scanner';
|
||||
|
||||
@Component({
|
||||
selector: 'app-advanced-scanner',
|
||||
template: `
|
||||
<button (click)="startScan()" [disabled]="isScanning">
|
||||
{{ isScanning ? 'Scanning...' : 'Start Scan' }}
|
||||
</button>
|
||||
<button (click)="cancelScan()" [disabled]="!isScanning">
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@if (errorMessage) {
|
||||
<p class="error">{{ errorMessage }}</p>
|
||||
}
|
||||
`
|
||||
})
|
||||
export class AdvancedScannerComponent implements OnDestroy {
|
||||
#scannerService = inject(ScannerService);
|
||||
#abortController = new AbortController();
|
||||
|
||||
isScanning = false;
|
||||
errorMessage = '';
|
||||
|
||||
async startScan() {
|
||||
this.isScanning = true;
|
||||
this.errorMessage = '';
|
||||
|
||||
try {
|
||||
const result = await this.#scannerService.open({
|
||||
abortSignal: this.#abortController.signal
|
||||
});
|
||||
|
||||
if (result) {
|
||||
console.log('Scanned:', result);
|
||||
} else {
|
||||
console.log('Scan was cancelled by user');
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorMessage = 'Scan was cancelled or failed';
|
||||
console.error('Scan error:', error);
|
||||
} finally {
|
||||
this.isScanning = false;
|
||||
}
|
||||
}
|
||||
|
||||
cancelScan() {
|
||||
this.#abortController.abort();
|
||||
this.#abortController = new AbortController(); // Create new controller for next scan
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.#abortController.abort();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Checking Scanner Readiness
|
||||
|
||||
```ts
|
||||
import { Component, inject, effect } from '@angular/core';
|
||||
import { ScannerService } from '@isa/shared/scanner';
|
||||
|
||||
@Component({
|
||||
selector: 'app-scanner-status',
|
||||
template: `
|
||||
<div class="status-indicator">
|
||||
@if (scannerReady()) {
|
||||
<span class="ready">Scanner Ready</span>
|
||||
} @else {
|
||||
<span class="initializing">Initializing Scanner...</span>
|
||||
}
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class ScannerStatusComponent {
|
||||
#scannerService = inject(ScannerService);
|
||||
|
||||
scannerReady = this.#scannerService.ready;
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
if (this.scannerReady()) {
|
||||
console.log('Scanner initialized successfully');
|
||||
// Perform actions when scanner becomes ready
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
The library requires a Scandit license key configured in your application config:
|
||||
|
||||
```json
|
||||
{
|
||||
"licence": {
|
||||
"scandit": "YOUR_SCANDIT_LICENSE_KEY"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The Scandit SDK library files must be available at `/scandit/` relative to your application's base URI.
|
||||
|
||||
### Custom Configuration via Injection Tokens
|
||||
|
||||
Override default configuration by providing custom values:
|
||||
|
||||
```ts
|
||||
import {
|
||||
SCANDIT_LICENSE,
|
||||
SCANDIT_LIBRARY_LOCATION,
|
||||
SCANDIT_DEFAULT_SYMBOLOGIES
|
||||
} from '@isa/shared/scanner';
|
||||
import { Symbology } from 'scandit-web-datacapture-barcode';
|
||||
|
||||
// In your providers array (e.g., app.config.ts):
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
// Custom license key
|
||||
{
|
||||
provide: SCANDIT_LICENSE,
|
||||
useValue: 'YOUR-SCANDIT-LICENSE-KEY',
|
||||
useValue: 'YOUR-CUSTOM-LICENSE-KEY'
|
||||
},
|
||||
// Custom library location
|
||||
// Custom library location (e.g., CDN)
|
||||
{
|
||||
provide: SCANDIT_LIBRARY_LOCATION,
|
||||
useValue: 'https://cdn.example.com/scandit/',
|
||||
useValue: 'https://cdn.example.com/scandit/'
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
// Custom default symbologies (only QR and Code128)
|
||||
{
|
||||
provide: SCANDIT_DEFAULT_SYMBOLOGIES,
|
||||
useValue: [Symbology.QR, Symbology.Code128]
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Core Dependencies
|
||||
|
||||
- **@angular/core** - Angular framework (signals, effects, DI)
|
||||
- **@angular/cdk** - CDK platform detection and overlay
|
||||
- **scandit-web-datacapture-core** - Scandit SDK core functionality
|
||||
- **scandit-web-datacapture-barcode** - Scandit barcode scanning module
|
||||
- **zod** - Configuration schema validation
|
||||
|
||||
### ISA Dependencies
|
||||
|
||||
- **@isa/core/config** - Application configuration management
|
||||
- **@isa/core/logging** - Logging utilities with factory pattern
|
||||
- **@isa/ui/buttons** - Icon button component
|
||||
- **@isa/icons** - Icon library (scanner and close icons)
|
||||
|
||||
## Error Handling
|
||||
|
||||
The scanner library includes error handling for various scenarios:
|
||||
The scanner library provides comprehensive error handling:
|
||||
|
||||
- `PlatformNotSupportedError` is thrown when the scanner is used on unsupported platforms
|
||||
- Configuration errors are logged and propagated
|
||||
- Aborted scan operations are handled gracefully
|
||||
### Platform Compatibility
|
||||
|
||||
## Requirements
|
||||
```ts
|
||||
// Automatically handled by ScannerService
|
||||
if (!platform.IOS && !platform.ANDROID) {
|
||||
// Logs warning and prevents initialization
|
||||
// Does not crash the application
|
||||
}
|
||||
```
|
||||
|
||||
- The Scandit SDK must be properly installed and configured
|
||||
- Requires a valid Scandit license key
|
||||
- Currently supports iOS and Android platforms
|
||||
### Configuration Errors
|
||||
|
||||
```ts
|
||||
try {
|
||||
await scannerService.configure();
|
||||
} catch (error) {
|
||||
// Configuration errors are logged and set status to 'Error'
|
||||
console.error('Scanner configuration failed:', error);
|
||||
}
|
||||
```
|
||||
|
||||
### Scan Operation Errors
|
||||
|
||||
```ts
|
||||
try {
|
||||
const result = await scannerService.open();
|
||||
} catch (error) {
|
||||
// Handle abort or configuration errors
|
||||
if (error.message === 'Scanner aborted') {
|
||||
console.log('User cancelled scanning');
|
||||
} else {
|
||||
console.error('Scanning failed:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
- **Signals & Effects:** Uses Angular signals for reactive state management and effects for side effect handling
|
||||
- **CDK Overlay:** Integrates with Angular CDK Overlay for full-screen scanner UI with backdrop and positioning
|
||||
- **Camera Lifecycle:** Automatic camera management (on/off state) with proper cleanup
|
||||
- **Zone Management:** Zone-aware event handling for optimal change detection performance
|
||||
- **Standalone:** All components and directives are standalone for easy tree-shaking
|
||||
- **Logging:** Comprehensive logging with `@isa/core/logging` factory pattern
|
||||
- **Memory Safety:** Proper cleanup in `OnDestroy` lifecycle hooks to prevent memory leaks
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
- **Supported Platforms:** iOS and Android only
|
||||
- **Scandit License:** Valid Scandit SDK license key required
|
||||
- **Camera Permissions:** Application must request and obtain camera permissions
|
||||
- **Library Files:** Scandit SDK files must be accessible at configured location
|
||||
|
||||
## E2E Testing
|
||||
|
||||
The scanner components include E2E testing attributes for easier selection in automated tests:
|
||||
The scanner components include E2E testing attributes for automated test selection:
|
||||
|
||||
- ScannerButton includes `data-which="scan-button"` for E2E test selection
|
||||
- `ScannerButtonComponent` includes `data-which="scan-button"` attribute
|
||||
- Use this attribute to locate and interact with the scanner button in E2E tests
|
||||
|
||||
```ts
|
||||
// Example E2E test
|
||||
await page.click('[data-which="scan-button"]');
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user