npm package: @one-payments/angular
Description: Angular wrapper for One Payments SDK
Author: One Payments
Latest version: 1.4.1

# @one-payments/angular

Angular wrapper component for One Payments SDK. Use this package to integrate One Payments into your Angular applications with a native Angular component API.

## Features

- Native Angular standalone component wrapping One Payments web component
- Full TypeScript support with type definitions
- Angular Input/Output decorators
- Zone-aware change detection
- Works with Angular 16+ standalone components

## Installation

```bash
npm install @one-payments/angular @one-payments/adapters-web
# or
yarn add @one-payments/angular @one-payments/adapters-web
# or
pnpm add @one-payments/angular @one-payments/adapters-web
```

## Usage

### Basic Example

```typescript
import { Component } from '@angular/core';
import { OnePaymentComponent } from '@one-payments/angular';
import { PaymentConfig } from '@one-payments/core';
import { createWebAdapters } from '@one-payments/adapters-web';
import type {
  PaymentSucceededPayload,
  PaymentFailedPayload,
  Adapters
} from '@one-payments/angular';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [OnePaymentComponent],
  template: `
    <div class="checkout">
      <h1>Complete Your Payment</h1>
      <one-payment
        [config]="config"
        [adapters]="adapters"
        [amount]="5000"
        currency="SGD"
        [orderId]="orderId"
        firstName="John"
        lastName="Doe"
        email="john@example.com"
        (paymentSuccess)="handleSuccess($event)"
        (paymentError)="handleError($event)"
      />
    </div>
  `,
  styles: [`
    .checkout {
      max-width: 600px;
      margin: 0 auto;
      padding: 24px;
    }
  `]
})
export class CheckoutComponent {
  // Create config using PaymentConfig class (recommended for type safety and validation)
  config = new PaymentConfig({
    apiKey: 'your-api-key',
    secretKey: 'your-secret-key',
    environment: 'demo'
  });

  adapters: Adapters = createWebAdapters();
  orderId = `order-${Date.now()}`;

  handleSuccess(payload: PaymentSucceededPayload) {
    console.log('Payment successful!', payload);
    // Navigate to success page or show confirmation
  }

  handleError(payload: PaymentFailedPayload) {
    console.error('Payment failed:', payload);
    // Show error message to user
  }
}
```

> **Note**: You can also pass a plain config object instead of using `PaymentConfig`, but `PaymentConfig` is recommended as it provides validation and better TypeScript support.

### With State Management

```typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OnePaymentComponent } from '@one-payments/angular';
import { createWebAdapters } from '@one-payments/adapters-web';
import type {
  SDKConfig,
  PaymentSucceededPayload,
  PaymentFailedPayload,
  StateChangedPayload,
  Adapters
} from '@one-payments/angular';

type PaymentStatus = 'idle' | 'processing' | 'success' | 'error';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [CommonModule, OnePaymentComponent],
  template: `
    <div class="checkout">
      <div *ngIf="paymentStatus === 'success'" class="success">
        Payment successful! Thank you for your order.
      </div>

      <div *ngIf="paymentStatus !== 'success'">
        <div *ngIf="paymentStatus === 'error'" class="error">
          {{ errorMessage }}
        </div>

        <div *ngIf="paymentStatus === 'processing'" class="processing">
          Processing your payment...
        </div>

        <one-payment
          [config]="config"
          [adapters]="adapters"
          [amount]="amount"
          [currency]="currency"
          [orderId]="orderId"
          [metadata]="metadata"
          (paymentSuccess)="handleSuccess($event)"
          (paymentError)="handleError($event)"
          (stateChange)="handleStateChange($event)"
        />
      </div>
    </div>
  `,
  styles: [`
    .error {
      padding: 16px;
      background-color: #fee;
      border: 1px solid #fcc;
      border-radius: 4px;
      color: #c00;
      margin-bottom: 16px;
    }

    .processing {
      padding: 16px;
      background-color: #fef3cd;
      border: 1px solid #ffeaa7;
      border-radius: 4px;
      color: #856404;
      margin-bottom: 16px;
    }

    .success {
      padding: 16px;
      background-color: #d4edda;
      border: 1px solid #c3e6cb;
      border-radius: 4px;
      color: #155724;
    }
  `]
})
export class CheckoutComponent {
  paymentStatus: PaymentStatus = 'idle';
  errorMessage = '';

  config: SDKConfig = {
    apiKey: 'your-api-key',
    secretKey: 'your-secret-key',
    environment: 'prod'
  };

  adapters: Adapters = createWebAdapters();
  amount = 5000;
  currency = 'SGD';
  orderId = `order-${Date.now()}`;
  metadata = {
    userId: '12345',
    productId: 'product-abc'
  };

  handleSuccess(payload: PaymentSucceededPayload) {
    this.paymentStatus = 'success';
    console.log('Payment Intent ID:', payload.paymentIntentId);
  }

  handleError(payload: PaymentFailedPayload) {
    this.paymentStatus = 'error';
    this.errorMessage = payload.message;
  }

  handleStateChange(payload: StateChangedPayload) {
    console.log('Payment state:', payload.status);
    if (payload.status === 'processing') {
      this.paymentStatus = 'processing';
    }
  }
}
```

### With Angular Router

```typescript
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { OnePaymentComponent } from '@one-payments/angular';
import { createWebAdapters } from '@one-payments/adapters-web';
import type {
  SDKConfig,
  PaymentSucceededPayload,
  PaymentFailedPayload
} from '@one-payments/angular';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [OnePaymentComponent],
  template: `
    <one-payment
      [config]="config"
      [adapters]="adapters"
      [amount]="5000"
      currency="SGD"
      [orderId]="orderId"
      (paymentSuccess)="handleSuccess($event)"
      (paymentError)="handleError($event)"
    />
  `
})
export class CheckoutComponent {
  config: SDKConfig = {
    apiKey: 'your-api-key',
    secretKey: 'your-secret-key',
    environment: 'prod'
  };

  adapters = createWebAdapters();
  orderId = `order-${Date.now()}`;

  constructor(private router: Router) {}

  handleSuccess(payload: PaymentSucceededPayload) {
    this.router.navigate(['/success'], {
      queryParams: { paymentId: payload.paymentIntentId }
    });
  }

  handleError(payload: PaymentFailedPayload) {
    this.router.navigate(['/error'], {
      queryParams: { error: payload.message }
    });
  }
}
```

### Using Environment Variables

```typescript
// environment.ts
export const environment = {
  production: false,
  onePayments: {
    apiKey: 'your-dev-api-key',
    secretKey: 'your-dev-secret-key',
    environment: 'dev' as const
  }
};

// checkout.component.ts
import { Component } from '@angular/core';
import { OnePaymentComponent } from '@one-payments/angular';
import { createWebAdapters } from '@one-payments/adapters-web';
import { environment } from '../environments/environment';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [OnePaymentComponent],
  template: `
    <one-payment
      [config]="config"
      [adapters]="adapters"
      [amount]="5000"
      currency="SGD"
      [orderId]="orderId"
      (paymentSuccess)="handleSuccess($event)"
      (paymentError)="handleError($event)"
    />
  `
})
export class CheckoutComponent {
  config = environment.onePayments;
  adapters = createWebAdapters();
  orderId = `order-${Date.now()}`;

  handleSuccess(payload: any) {
    console.log('Success:', payload);
  }

  handleError(payload: any) {
    console.error('Error:', payload);
  }
}
```

### Module-based Applications

If you're not using standalone components, you can still use the component by importing it in your module:

```typescript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { OnePaymentComponent } from '@one-payments/angular';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    OnePaymentComponent  // Import the standalone component
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
```

## API Reference

### OnePaymentComponent Inputs

| Input | Type | Required | Description |
|-------|------|----------|-------------|
| `config` | `SDKConfig \| PaymentConfig` | Yes | SDK configuration - use `new PaymentConfig({...})` (recommended) or plain object |
| `adapters` | `Adapters` | Yes | Platform adapters (use `createWebAdapters()` for web) |
| `amount` | `number` | Yes | Payment amount in smallest currency unit (e.g., cents for USD, SGD) |
| `currency` | `string` | Yes | ISO 4217 currency code (e.g., "USD", "EUR", "SGD") |
| `orderId` | `string` | Yes | Unique order identifier from your system |
| `firstName` | `string` | **Yes** | Customer's first name (required for all payments) |
| `lastName` | `string` | **Yes** | Customer's last name (required for all payments) |
| `email` | `string` | **Yes** | Customer's email address (required for all payments) |
| `excludePaymentMethods` | `PaymentMethodId[]` | No | Array of payment method IDs to exclude from display |
| `width` | `string` | No | Custom width (e.g., "100%", "500px") |
| `maxWidth` | `string` | No | Maximum width constraint (e.g., "600px") |

### OnePaymentComponent Outputs

| Output | Payload | Description |
|--------|---------|-------------|
| `paymentSuccess` | `PaymentSucceededPayload` | Emitted when payment succeeds |
| `paymentError` | `PaymentFailedPayload` | Emitted when payment fails |
| `stateChange` | `StateChangedPayload` | Emitted when payment state changes |

### Types

```typescript
interface SDKConfig {
  apiKey: string;
  secretKey: string;
  environment: 'dev' | 'staging' | 'prod';
}

interface PaymentSucceededPayload {
  paymentIntentId: string;
  amount: number;
  currency: string;
  status: 'succeeded';
  metadata?: Record<string, unknown>;
}

interface PaymentFailedPayload {
  code: string;
  message: string;
  details?: Record<string, unknown>;
}

interface StateChangedPayload {
  status: 'idle' | 'initializing' | 'ready' | 'processing' | 'requires_action' | 'succeeded' | 'failed';
  [key: string]: unknown;
}
```

## Requirements

- Angular >= 16.0.0 (standalone components)
- TypeScript >= 5.0.0
- RxJS >= 7.0.0

For Angular < 16, you can still use this package but may need to adjust the import pattern.

## Related Packages

- [@one-payments/core](../core) - Core SDK types and interfaces
- [@one-payments/web-components](../web-components) - Underlying web component
- [@one-payments/adapters-web](../adapters-web) - Web platform adapters
- [@one-payments/react](../react) - React wrapper
- [@one-payments/vue](../vue) - Vue wrapper
- [@one-payments/react-native](../react-native) - React Native implementation

## License

MIT