npm package: @shopkit/discounts
Description: Discount and coupon management for e-commerce storefronts
Latest version: 0.1.3

# @shopkit/discounts

Discount and coupon management for e-commerce storefronts.

## Installation

```bash
npm install @shopkit/discounts @shopkit/cart
# or
bun add @shopkit/discounts @shopkit/cart
```

## Quick Start

### 1. Implement the discount service

```typescript
import { IDiscountService, DiscountResult, DiscountValidationResult, OffersResult } from '@shopkit/discounts';

class MyDiscountService implements IDiscountService {
  async applyDiscount(cartId: string, code: string): Promise<DiscountResult> {
    const response = await fetch('/api/discount/apply', {
      method: 'POST',
      body: JSON.stringify({ cartId, code }),
    });
    return response.json();
  }

  async removeDiscount(cartId: string): Promise<void> {
    await fetch('/api/discount/remove', {
      method: 'POST',
      body: JSON.stringify({ cartId }),
    });
  }

  async validateDiscount(code: string, cartData: unknown): Promise<DiscountValidationResult> {
    const response = await fetch('/api/discount/validate', {
      method: 'POST',
      body: JSON.stringify({ code, cartData }),
    });
    return response.json();
  }

  async getOffers(cartId: string): Promise<OffersResult> {
    const response = await fetch(`/api/discount/offers?cartId=${cartId}`);
    return response.json();
  }

  async getCartData(cartId: string): Promise<unknown> {
    const response = await fetch(`/api/cart/${cartId}`);
    return response.json();
  }
}

export const discountService = new MyDiscountService();
```

### 2. Use the discount hook

```tsx
import { useDiscount } from '@shopkit/discounts';
import { discountService } from './services/discount-service';

function CouponForm() {
  const {
    couponCode,
    setCouponCode,
    applyCoupon,
    removeCoupon,
    appliedDiscount,
    isDiscountLoading,
    availableOffers,
  } = useDiscount({
    discountService,
    onError: (error) => console.error(error.message),
  });

  return (
    <div>
      {appliedDiscount ? (
        <div>
          <p>Applied: {appliedDiscount.code}</p>
          <p>Discount: ${appliedDiscount.amount}</p>
          <button onClick={removeCoupon}>Remove</button>
        </div>
      ) : (
        <form onSubmit={(e) => { e.preventDefault(); applyCoupon(); }}>
          <input
            value={couponCode}
            onChange={(e) => setCouponCode(e.target.value)}
            placeholder="Enter coupon code"
          />
          <button type="submit" disabled={isDiscountLoading}>
            Apply
          </button>
        </form>
      )}

      {availableOffers.length > 0 && (
        <div>
          <h4>Available Offers</h4>
          {availableOffers.map((offer: any) => (
            <button key={offer.code} onClick={() => applyCoupon(offer.code)}>
              {offer.title}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}
```

## API Reference

### Types

#### `IDiscountService`

Interface for discount service implementations.

```typescript
interface IDiscountService {
  applyDiscount(cartId: string, code: string): Promise<DiscountResult>;
  removeDiscount(cartId: string): Promise<void>;
  validateDiscount(code: string, cartData: unknown): Promise<DiscountValidationResult>;
  getOffers?(cartId: string): Promise<OffersResult>;
  getCartData?(cartId: string): Promise<unknown>;
}
```

#### `AppliedDiscount`

Represents an applied discount.

```typescript
interface AppliedDiscount {
  code: string;
  message: string;
  amount: number;
  totalPrice: number;
}
```

### Hooks

#### `useDiscount(options)`

Main hook for managing discounts.

**Options:**
- `discountService: IDiscountService` - Required discount service implementation
- `onError?: (error: Error) => void` - Error callback

**Returns:**
- `appliedDiscount: AppliedDiscount | null` - Currently applied discount
- `couponCode: string` - Current coupon code input
- `setCouponCode: (code: string) => void` - Set coupon code
- `availableOffers: unknown[]` - Available discount offers
- `unavailableOffers: unknown[]` - Unavailable discount offers
- `isDiscountLoading: boolean` - Loading state
- `isRemovingDiscount: boolean` - Removing discount state
- `applyCoupon: (code?: string) => Promise<void>` - Apply a coupon
- `removeCoupon: () => Promise<void>` - Remove applied coupon
- `validateAfterCartChange: () => Promise<void>` - Re-validate after cart changes
- `refreshOffers: () => Promise<void>` - Refresh available offers
- `refreshCartData: () => Promise<unknown>` - Refresh cart data

## Requirements

- `@shopkit/cart` must be configured and initialized
- React 18+

## License

MIT