# Zenskar UI Kit

A React UI component library for building customizable checkout experiences and customer billing management.

## What's New

See the [CHANGELOG](./CHANGELOG.md) for latest updates, bug fixes, and migration guides.

**Latest Updates (v0.1.21):**
- **New:** Custom font support with `elementFonts` prop - Load Google Fonts or custom fonts into payment forms
- Support for both CSS stylesheet fonts (Google Fonts, Adobe Fonts) and custom font files
- New TypeScript types: `PaymentElementFonts`, `CssFontSource`, `CustomFontSource`
- Full documentation and examples for implementing custom fonts
- Enhanced AddPaymentMethod customization with font loading

**Previous Updates (v0.1.20):**
- **New:** AddPaymentMethod `confirmParams` prop for handling hidden billing fields
- Support for programmatic billing data when UI fields are customized away
- Enhanced Stripe integration for flexible payment form configurations

**Previous Updates (v0.1.17-0.1.19):**
- **New:** Type-safe element retrieval with automatic type narrowing for `getElement()` method
- **New:** AddPaymentMethod `reset()` method for clearing form and creating fresh SetupIntent
- Improved TypeScript developer experience with full IntelliSense support
- No more manual type assertions needed when working with elements
- **Fixed:** PaymentElement types now resolve correctly in consumer IDEs instead of showing as `any`
- New `customer.contracts()` and `customer.contractById()` methods
- Payment method type control with `paymentMethodTypes` prop
- Automatic locale detection with `elementLocale` prop (defaults to 'auto')
- TypeScript type exports for AddPaymentMethod element
- New `PaymentHistory` component (replaces TransactionHistory)
- New `customer.payments()` method (replaces transactions())
- Fixed AddPaymentMethod customization bugs
- Improved type exports and documentation

## Installation

```bash
npm install @zenskar/ui-kit
```

## Available Components

The Zenskar UI Kit provides the following components:

- **`BillingInformation`** - Component for displaying customer billing details and address information
- **`PaymentMethods`** - Component for managing actions(e.g updating default payment method) and displaying payment methods including cards and bank accounts
- **`InvoiceHistory`** - Component for displaying customer invoice history with filtering and sorting capabilities
- **`PaymentHistory`** - Component for displaying payment history and financial activity tracking
- **`ManageBillingInformation`** - Element for managing customer billing information with customizable fields and validation modes
- **`AddPaymentMethod`** - Element for adding new payment methods

### Provider & Hooks
- **`ZenskarProvider`** - Required wrapper component that provides context to all library components
- **`useZenskar`** - Hook to access Zenskar service methods for custom state management
- **`useZenskarElements`** - Hook to access element instances for programmatic control
- **`useCheckout`** - Hook to access checkout service methods for plan subscriptions

## Importing Components

### Tree-Shaked Imports (Recommended for optimal bundle size)

Import individual components from their dedicated entry points:

```typescript
// Provider
import { ZenskarProvider } from '@zenskar/ui-kit/provider'

// Individual Components (import only what you need)
import { BillingInformation } from '@zenskar/ui-kit/BillingInformation'
import { PaymentMethods } from '@zenskar/ui-kit/PaymentMethods'
import { InvoiceHistory } from '@zenskar/ui-kit/InvoiceHistory'
import { PaymentHistory } from '@zenskar/ui-kit/PaymentHistory'
import { ManageBillingInformation } from '@zenskar/ui-kit/ManageBillingInformation'
import { AddPaymentMethod } from '@zenskar/ui-kit/AddPaymentMethodElement'

// Hooks
import { useZenskar, useZenskarElements } from '@zenskar/ui-kit/hooks'

// Types
import type { Customer, PaymentMethod, Invoice } from '@zenskar/ui-kit/types'
```

### Barrel Import (Convenience import)

Import everything from the main entry point:

```typescript
import { 
  // Provider (Required)
  ZenskarProvider,
  
  // Components
  BillingInformation,
  PaymentMethods,
  InvoiceHistory,
  PaymentHistory,
  ManageBillingInformation,
  AddPaymentMethod,
  
  // Hooks
  useZenskar,
  useZenskarElements
} from '@zenskar/ui-kit'
```

> **Bundle Optimization**: Use tree-shaked imports for smaller bundle sizes. Each component is built as a separate entry point, allowing bundlers to include only the code you actually use.

## Available Types

The Zenskar UI Kit exports comprehensive TypeScript types for better development experience:

### Customer & Payment Types
```typescript
import type {
  Customer,                    // Customer billing information and details
  PaymentMethod,              // Individual payment method (card, bank account)
  PaymentMethodsList,         // Paginated list of payment methods
} from '@zenskar/ui-kit'
```

### Invoice & Payment Types
```typescript
import type {
  Invoice,                    // Individual invoice data
  InvoicesList,              // Paginated list of invoices
  Payment,                   // Individual payment record
  PaymentsList,              // Paginated list of payments
} from '@zenskar/ui-kit'
```

### Configuration & Provider Types
```typescript
import type {
  ZenskarProviderProps,      // Props for ZenskarProvider component
  Theme,                     // Theme configuration for styling
  ServiceParams,             // Parameters for service method calls
} from '@zenskar/ui-kit'
```

### Element Types
```typescript
import type {
  ZenskarError,
  // AddPaymentMethod element types
  PaymentElementAppearance,
  PaymentElementOptions,
  PaymentElementLocale,
  PaymentElementFonts,
  CssFontSource,
  CustomFontSource,
  PaymentElementFormResult,
} from '@zenskar/ui-kit'
```

### Checkout Types
```typescript
import type {
  CreateCheckoutRequest,           // Request for creating checkout
  CheckoutResponse,                // Checkout session response
  CheckoutConfirmRequest,          // Request for confirming checkout
  ConfirmCheckoutResponse,         // Confirmation response with contract
  CheckoutEstimates,               // Invoice estimates (current & next)
  CheckoutStatus,                  // Checkout status enum
  ProductQuantityOverride,         // Quantity override for pricing
  ProductQuantityResponse,         // Product quantity in response
} from '@zenskar/ui-kit'
```

## Service Methods

The Zenskar UI Kit provides service methods through the `useZenskar` hook for custom management. These methods work with any state management solution (useState, Zustand, React Query, SWR, etc.).

### Available Service Methods

```typescript
const zenskar = useZenskar()

// Customer service methods
const customerService = zenskar.customer

// Available methods:
await customerService.details()           // Get customer billing information
await customerService.paymentMethods()   // Get customer payment methods
await customerService.invoices(params)   // Get customer invoices with pagination
await customerService.payments(params)   // Get customer payment history with pagination
await customerService.contracts(params)  // Get customer contracts with pagination
await customerService.contractById(id)   // Get a specific contract by ID
```

### Service Method Details

#### `customerService.details()`
Fetches customer billing information and details.
- **Returns**: `Promise<{ data: Customer }>`
- **Usage**: Get current customer information

#### `customerService.paymentMethods()`
Fetches all payment methods from the payment provider.
- **Returns**: `Promise<{ data: PaymentMethodsList }>`
- **Usage**: Display available payment methods

#### `customerService.invoices(params)`
Fetches paginated customer invoices with filtering.
- **Parameters**: `ServiceParams` (limit, cursor sortKey, sortType)
- **Returns**: `Promise<{ data: InvoicesList }>`
- **Usage**: Display invoice history with pagination and sorting

#### `customerService.payments(params)`
Fetches paginated payment history.
- **Parameters**: `ServiceParams` (limit, cursor, sortKey, sortType)
- **Returns**: `Promise<{ data: PaymentsList }>`
- **Usage**: Display payment history with pagination and sorting

#### `customerService.contracts(params)`
Fetches paginated customer contracts.
- **Parameters**: `ServiceParams` (limit, cursor, sortKey, sortType)
- **Returns**: `Promise<{ data: ContractList }>`
- **Usage**: Display customer contracts with pagination and sorting

#### `customerService.contractById(contractId)`
Fetches a specific contract by ID.
- **Parameters**: `contractId` (string, required)
- **Returns**: `Promise<{ data: Contract }>`
- **Usage**: Display detailed contract information

### Checkout Service Methods

The `useCheckout` hook provides methods for creating and managing checkout sessions for plan subscriptions.

```typescript
import { useCheckout } from '@zenskar/ui-kit'

const checkout = useCheckout()

// Available methods:
await checkout.createCheckout(request)      // Create new checkout session
await checkout.confirmCheckout(id, request) // Confirm and finalize checkout
```

#### `checkout.createCheckout(request)`
Creates a new checkout session for plan purchase.
- **Parameters**: `CreateCheckoutRequest` (plan_id, start_date, optional fields)
- **Returns**: `Promise<{ data: CheckoutResponse }>`
- **Usage**: Initialize checkout flow with plan details and estimates

#### `checkout.confirmCheckout(checkoutId, request)`
Confirms and finalizes a checkout session, creating the contract.
- **Parameters**: `checkoutId` (string, required), `CheckoutConfirmRequest` (optional payment_method_id)
- **Returns**: `Promise<{ data: ConfirmCheckoutResponse }>`
- **Usage**: Complete checkout and create customer contract

### Service Usage Examples

#### React + TypeScript Example

```typescript
import React, { useState, useEffect } from 'react'
import { useZenskar } from '@zenskar/ui-kit'
import type { Customer, InvoicesList, ZenskarError } from '@zenskar/ui-kit'

const CustomerDashboard = () => {
  const zenskar = useZenskar()
  const [customer, setCustomer] = useState<Customer | null>(null)
  const [invoices, setInvoices] = useState<InvoicesList | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true)
      setError(null)
      
      try {
        // Fetch customer details
        const { data: customerData } = await zenskar.customer.details()
        setCustomer(customerData)
        
        // Fetch recent invoices
        const { data: invoicesData } = await zenskar.customer.invoices({ limit: 10 })
        setInvoices(invoicesData)
      } catch (err) {
        const zenskarError = err as ZenskarError
        setError(zenskarError.message)
      } finally {
        setLoading(false)
      }
    }

    fetchData()
  }, [])

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error}</div>

  return (
    <div>
      <h2>Customer: {customer?.customer_name}</h2>
      <p>Email: {customer?.email}</p>
      
      <h3>Recent Invoices ({invoices?.results?.length || 0})</h3>
      {invoices?.results?.map(invoice => (
        <div key={invoice.id}>
          {invoice.invoice_number} - ${invoice.invoice_total} ({invoice.status})
        </div>
      ))}
    </div>
  )
}
```

#### React Query Example

```typescript
import { useQuery } from '@tanstack/react-query'
import { useZenskar } from '@zenskar/ui-kit'
import type { Customer, InvoicesList } from '@zenskar/ui-kit'

// Custom hooks
const useCustomerDetails = () => {
  const zenskar = useZenskar()
  return useQuery({
    queryKey: ['customer', 'details'],
    queryFn: async (): Promise<Customer> => {
      const { data } = await zenskar.customer.details()
      return data
    },
    staleTime: 5 * 60 * 1000, // 5 minutes
  })
}

const useCustomerInvoices = () => {
  const zenskar = useZenskar()
  return useQuery({
    queryKey: ['customer', 'invoices'],
    queryFn: async (): Promise<InvoicesList> => {
      const { data } = await zenskar.customer.invoices({ limit: 10 })
      return data
    },
    staleTime: 1 * 60 * 1000, // 1 minute
  })
}

// Component
const CustomerDashboardWithQuery = () => {
  const { data: customer, isLoading: customerLoading, error: customerError } = useCustomerDetails()
  const { data: invoices, isLoading: invoicesLoading, error: invoicesError } = useCustomerInvoices()

  if (customerLoading || invoicesLoading) return <div>Loading...</div>
  if (customerError || invoicesError) return <div>Error loading data</div>

  return (
    <div>
      <h2>Customer: {customer?.customer_name}</h2>
      <p>Email: {customer?.email}</p>
      
      <h3>Recent Invoices ({invoices?.results?.length || 0})</h3>
      {invoices?.results?.map(invoice => (
        <div key={invoice.id}>
          {invoice.invoice_number} - ${invoice.invoice_total} ({invoice.status})
        </div>
      ))}
    </div>
  )
}
```

#### Checkout Flow Example

```typescript
import React, { useState } from 'react'
import { useCheckout } from '@zenskar/ui-kit'
import type { CheckoutResponse, ZenskarError } from '@zenskar/ui-kit'

const CheckoutFlow = ({ planId }: { planId: string }) => {
  const checkout = useCheckout()
  const [session, setSession] = useState<CheckoutResponse | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const handleCreateCheckout = async () => {
    setLoading(true)
    setError(null)

    try {
      // Create checkout session
      const { data } = await checkout.createCheckout({
        plan_id: planId,
        start_date: '2025-01-01',
        success_url: 'https://example.com/success',
      })
      setSession(data)
    } catch (err) {
      const zenskarError = err as ZenskarError
      setError(zenskarError.message)
    } finally {
      setLoading(false)
    }
  }

  const handleConfirmCheckout = async () => {
    if (!session) return
    setLoading(true)

    try {
      // Confirm checkout and create contract
      // Optional: Specify payment method ID from zenskar.customer.paymentMethods()
      // If omitted, uses customer's default payment method
      const { data } = await checkout.confirmCheckout(session.id, {
        payment_method_id: 'ea94efc5-ed4c-446c-9b8b-54cb1356e01c',
      })
      console.log('Contract created:', data.contract_id)
    } catch (err) {
      const zenskarError = err as ZenskarError
      setError(zenskarError.message)
    } finally {
      setLoading(false)
    }
  }

  if (error) return <div>Error: {error}</div>

  return (
    <div>
      {!session ? (
        <button onClick={handleCreateCheckout} disabled={loading}>
          {loading ? 'Creating...' : 'Start Checkout'}
        </button>
      ) : (
        <div>
          <p>Checkout Status: {session.checkout_status}</p>
          <button onClick={handleConfirmCheckout} disabled={loading}>
            {loading ? 'Confirming...' : 'Confirm Purchase'}
          </button>
        </div>
      )}
    </div>
  )
}
```

#### AddPaymentMethod Element Example

```typescript
import React, { useState } from 'react'
import { AddPaymentMethod, useZenskar, useZenskarElements } from '@zenskar/ui-kit'

const AddPaymentExample = () => {
  const zenskar = useZenskar()
  const elements = useZenskarElements()
  const [loading, setLoading] = useState(false)

  const addPaymentElement = elements?.getElement('add-payment-method')

  const handleConfirm = async () => {
    if (!elements || !zenskar) return
    setLoading(true)

    try {
      const { data, error } = await zenskar.addPaymentMethod()
      if (error) {
        console.error('Payment method error:', error)
      } else {
        console.log('Payment method added successfully!')
        // Handle success - navigate, refresh data, etc.
      }
    } catch (err) {
      console.error('An unexpected error occurred:', err)
    } finally {
      setLoading(false)
    }
  }

  const handleCancel = () => {
    addPaymentElement?.clear()
  }

  return (
    <div className="max-w-md mx-auto p-6 space-y-6">
      <h2 className="text-2xl font-bold">Add Payment Method</h2>
      
      <AddPaymentMethod onReady={() => console.log('Payment form ready')} />
      
      <div className="flex gap-2">
        <button
          onClick={handleConfirm}
          disabled={loading}
          className="flex-1 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 disabled:opacity-50"
        >
          {loading ? 'Adding...' : 'Confirm'}
        </button>
        
        <button
          onClick={handleCancel}
          disabled={loading}
          className="flex-1 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300"
        >
          Cancel
        </button>
      </div>
    </div>
  )
}
```

#### Type-Safe Element Retrieval (New in v0.1.17)

The `useZenskarElements()` hook now provides automatic TypeScript type narrowing for element instances, eliminating the need for manual type assertions.

```typescript
import { useZenskarElements } from '@zenskar/ui-kit'

const MyComponent = () => {
  const elements = useZenskarElements()

  // ✅ Automatic type narrowing - TypeScript knows the exact type!
  const addPaymentElement = elements?.getElement('add-payment-method')
  // Type: AddPaymentMethodElementInstance | null

  if (addPaymentElement) {
    // Full IntelliSense support - no type casting needed
    await addPaymentElement.submit()    // ✅ TypeScript knows this exists
    addPaymentElement.reset()           // ✅ TypeScript knows this exists
    const isEmpty = addPaymentElement.isEmpty  // ✅ TypeScript knows this exists
  }

  // Works for all element types
  const billingElement = elements?.getElement('manage-billing-information')
  // Type: ManageBillingInformationElementInstance | null

  if (billingElement) {
    const data = billingElement.getValue()  // ✅ TypeScript knows this exists
    await billingElement.validate()         // ✅ TypeScript knows this exists
  }

  return <div>...</div>
}
```

**Benefits:**
- ✅ No more `as AddPaymentMethodElementInstance` type assertions
- ✅ Full IntelliSense auto-completion for element-specific methods
- ✅ Compile-time type checking catches errors immediately
- ✅ Better developer experience with zero runtime impact

#### AddPaymentMethod `reset()` Method (New in v0.1.17)

The AddPaymentMethod element includes a `reset()` method that creates a fresh SetupIntent and clears the payment form. This is particularly useful after successful payment submission when you want to allow users to add another payment method without remounting the component.

```typescript
import React, { useState } from 'react'
import { AddPaymentMethod, useZenskar, useZenskarElements } from '@zenskar/ui-kit'

const AddMultiplePaymentMethods = () => {
  const zenskar = useZenskar()
  const elements = useZenskarElements()
  const [loading, setLoading] = useState(false)
  const [successMessage, setSuccessMessage] = useState('')

  const addPaymentElement = elements?.getElement('add-payment-method')

  const handleAddPayment = async () => {
    if (!zenskar || !addPaymentElement) return
    setLoading(true)

    try {
      const { data, error } = await zenskar.addPaymentMethod()
      if (error) {
        console.error('Payment method error:', error)
      } else {
        setSuccessMessage('Payment method added successfully!')

        // ✅ Reset the form to allow adding another payment method
        // This creates a new SetupIntent and clears all payment data
        addPaymentElement.reset()

        // Clear success message after 3 seconds
        setTimeout(() => setSuccessMessage(''), 3000)
      }
    } catch (err) {
      console.error('An unexpected error occurred:', err)
    } finally {
      setLoading(false)
    }
  }

  return (
    <div className="max-w-md mx-auto p-6 space-y-4">
      <h2 className="text-2xl font-bold">Add Payment Methods</h2>

      {successMessage && (
        <div className="p-3 bg-green-100 text-green-800 rounded">
          {successMessage}
        </div>
      )}

      <AddPaymentMethod />

      <button
        onClick={handleAddPayment}
        disabled={loading}
        className="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
      >
        {loading ? 'Adding...' : 'Add Payment Method'}
      </button>

      <p className="text-sm text-gray-600">
        You can add multiple payment methods. The form will reset after each successful addition.
      </p>
    </div>
  )
}
```

**Use cases for `reset()`:**
- ✅ Allow users to add multiple payment methods in succession
- ✅ Clear sensitive payment data after successful submission
- ✅ Refresh the form without unmounting/remounting the component
- ✅ Provide better UX for "Add Another Payment Method" workflows
- ✅ Reset form state after errors to allow retry with fresh data

**Without `reset()`:** You would need to unmount and remount the entire AddPaymentMethod component, causing unnecessary re-renders and API calls.

**With `reset()`:** The form instantly clears and creates a new SetupIntent, providing a seamless experience for adding multiple payment methods.

#### ManageBillingInformation Element Example

> **Important Note**: To display existing customer billing details, you must pass `defaultValues` in the `options` prop. You can get the customer data using `zenskar.customerData` from the `useZenskar` hook.

```typescript
import React, { useState } from 'react'
import { ManageBillingInformation, useZenskar, useZenskarElements } from '@zenskar/ui-kit'

const ManageBillingExample = () => {
  const zenskar = useZenskar()
  const elements = useZenskarElements()
  const [loading, setLoading] = useState(false)

  // Get the element instance for control
  const manageBillingElement = elements?.getElement('manage-billing-information')

  // Get customer data from useZenskar hook - this is REQUIRED to show existing customer billing details
  const customerData = zenskar.customerData // Direct access to customer data

  const handleSave = async () => {
    if (!manageBillingElement || !zenskar) return
    setLoading(true)

    try {
      // Validate form first
      const isValid = await manageBillingElement.validate()
      if (!isValid) {
        console.error('Form validation failed')
        return
      }

      const { data, error } = await zenskar.updateBillingInformation()
      if (error) {
        console.error('Update error:', error)
      } else {
        console.log('Billing information updated successfully!')
        // Handle success - show toast, navigate, etc.
      }
    } catch (err) {
      console.error('An unexpected error occurred:', err)
    } finally {
      setLoading(false)
    }
  }

  const handleReset = () => {
    manageBillingElement?.clear()
  }

  return (
    <div className="max-w-2xl mx-auto p-6 space-y-6">
      <h2 className="text-2xl font-bold">Manage Billing Information</h2>
      
      {/* The Element with options */}
      <ManageBillingInformation
        options={{
          defaultValues: customerData, // Customer data from useZenskar hook
          fields: ['email', 'address', 'ship_to_address', 'tax_info'], // Optional: control which fields to show
          validationMode: 'onChange' // Optional: 'onChange' | 'onBlur' | 'onSubmit'
        }}
        onReady={() => console.log('Billing form ready')}
      />
      
      {/* Action Buttons */}
      <div className="flex gap-2">
        <button
          onClick={handleSave}
          disabled={loading || !manageBillingElement?.isValid || !manageBillingElement?.isReady}
          className="flex-1 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 disabled:opacity-50"
        >
          {loading ? 'Saving...' : 'Save Changes'}
        </button>
        
        <button
          onClick={handleReset}
          disabled={loading}
          className="flex-1 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300"
        >
          Reset Form
        </button>
      </div>
    </div>
  )
}
```

## AddPaymentMethod Element Customization

The AddPaymentMethod element uses Stripe's secure, PCI-compliant payment elements to collect payment method information. Through the `elementOptions` and `elementAppearance` props, you can customize the payment form fields, styling, and behavior to match your application's design.

### Stripe Elements Integration

We leverage Stripe's proven payment infrastructure which provides:
- **PCI Compliance** - Secure payment data collection without PCI burden on your application
- **Multiple Payment Types** - Support for cards, bank accounts, and various regional payment methods
- **Customizable UI** - Full control over styling and form fields through Stripe's Element options

### Available Props

#### `elementOptions`
Configure which payment fields are displayed and their behavior.

#### `elementAppearance`
Customize the visual styling of the payment form elements.

#### `confirmParams`
Optional parameters for Stripe's payment confirmation. Use this when you've hidden billing fields from the UI but need to provide them programmatically (e.g., when hiding the country field, you must provide the country via `confirmParams`).

#### `elementLocale`
Control the language of payment form labels and error messages. Defaults to `'auto'` for automatic detection.

#### `elementFonts`
Load custom fonts for the payment form using CSS stylesheets or custom font files.

### Customization Examples

#### Basic Styling Customization

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithCustomStyling = () => {
  return (
    <AddPaymentMethod
      elementAppearance={{
        theme: 'stripe', // 'stripe' | 'night' | 'flat'
        variables: {
          colorPrimary: '#0570de',
          colorBackground: '#ffffff',
          colorText: '#30313d',
          colorDanger: '#df1b41',
          fontFamily: 'Ideal Sans, system-ui, sans-serif',
          spacingUnit: '2px',
          borderRadius: '4px',
          // Add more design tokens as needed
        },
        rules: {
          '.Input': {
            backgroundColor: '#f6f9fc',
            border: '1px solid #e6ebf1',
          },
          '.Input:focus': {
            border: '1px solid #0570de',
            boxShadow: '0 0 0 2px rgba(5, 112, 222, 0.2)',
          },
          '.Label': {
            color: '#6b7c93',
            fontWeight: '500',
            fontSize: '13px',
          },
        },
      }}
      onReady={() => console.log('Custom styled payment form ready')}
    />
  )
}
```

#### Advanced Field Configuration

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithCustomFields = () => {
  return (
    <AddPaymentMethod
      elementOptions={{
        layout: {
          type: 'tabs', // 'tabs' | 'accordion'
          defaultCollapsed: false,
          radios: false,
          spacedAccordionItems: true,
        },
        fields: {
          billingDetails: {
            name: 'auto', // 'auto' | 'never'
            email: 'auto',
            phone: 'never',
            address: {
              country: 'auto',
              line1: 'auto',
              line2: 'never',
              city: 'auto',
              state: 'auto',
              postalCode: 'auto',
            },
          },
        },
        terms: {
          card: 'never', // 'auto' | 'always' | 'never'
          bancontact: 'never',
          ideal: 'never',
          sepaDebit: 'auto',
          usBankAccount: 'auto',
        },
      }}
      elementAppearance={{
        theme: 'stripe',
        variables: {
          fontFamily: 'system-ui, sans-serif',
          colorPrimary: '#635bff',
        },
      }}
      onReady={() => console.log('Payment form with custom fields ready')}
    />
  )
}
```

#### Dark Theme Example

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const DarkThemePaymentForm = () => {
  return (
    <AddPaymentMethod
      elementAppearance={{
        theme: 'night', // Built-in dark theme
        variables: {
          colorPrimary: '#635bff',
          colorBackground: '#1a1a1a',
          colorText: '#ffffff',
          colorDanger: '#fa755a',
          borderRadius: '8px',
        },
        rules: {
          '.Input': {
            backgroundColor: '#2d2d2d',
            border: '1px solid #404040',
            color: '#ffffff',
          },
          '.Input:focus': {
            border: '1px solid #635bff',
            boxShadow: '0 0 0 2px rgba(99, 91, 255, 0.3)',
          },
          '.Label': {
            color: '#b4b4b4',
          },
        },
      }}
      onReady={() => console.log('Dark theme payment form ready')}
    />
  )
}
```

#### Minimal Fields Configuration

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const MinimalPaymentForm = () => {
  return (
    <AddPaymentMethod
      elementOptions={{
        fields: {
          billingDetails: {
            name: 'never',
            email: 'never',
            phone: 'never',
            address: 'never',
          },
        },
        layout: {
          type: 'accordion',
          defaultCollapsed: false,
          radios: true,
          spacedAccordionItems: false,
        },
      }}
      elementAppearance={{
        theme: 'flat',
        variables: {
          colorPrimary: '#000000',
          borderRadius: '0px',
          fontFamily: 'monospace',
        },
      }}
      onReady={() => console.log('Minimal payment form ready')}
    />
  )
}
```

#### Hidden Billing Fields with confirmParams

When you customize the payment form to hide certain billing fields (like country), you can provide that information programmatically using the `confirmParams` prop:

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithHiddenCountry = () => {
  return (
    <AddPaymentMethod
      elementOptions={{
        fields: {
          billingDetails: {
            address: {
              country: 'never', // Hide country field from UI
            },
          },
        },
      }}
      confirmParams={{
        payment_method_data: {
          billing_details: {
            address: {
              country: 'US', // Provide country programmatically
            },
          },
        },
      }}
      onReady={() => console.log('Payment form ready')}
    />
  )
}
```

This is useful when you want to:
- Simplify the payment form by hiding fields you already know
- Set billing information based on user account data or location
- Create a streamlined checkout experience

### Payment Method Type Control

Control which payment methods are available in the form using the `paymentMethodTypes` prop:

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

// Card payments only (skips organization config fetch)
const CardOnlyPaymentForm = () => {
  return (
    <AddPaymentMethod
      paymentMethodTypes={['card']}
      onReady={() => console.log('Card payment form ready')}
    />
  )
}

// Both card and US bank account
const MultiPaymentForm = () => {
  return (
    <AddPaymentMethod
      paymentMethodTypes={['card', 'us_bank_account']}
      onReady={() => console.log('Multi-payment form ready')}
    />
  )
}

// Use organization config (default behavior)
const DefaultPaymentForm = () => {
  return <AddPaymentMethod />
}
```

**Behavior:**
- If `paymentMethodTypes` is provided with values: Uses these types directly, skips organization config fetch
- If `paymentMethodTypes` is empty array `[]` or not provided: Fetches payment types from organization config
- If invalid types are provided: Logs error to console and filters to supported types only
- Supported types: `'card'`, `'us_bank_account'`

### Localization Support

Control the language of payment form labels and error messages using the `elementLocale` prop:

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

// Automatic language detection (default)
const AutoLocaleForm = () => {
  return <AddPaymentMethod elementLocale="auto" />
}

// Spanish
const SpanishForm = () => {
  return <AddPaymentMethod elementLocale="es" />
}

// French
const FrenchForm = () => {
  return <AddPaymentMethod elementLocale="fr" />
}

// German
const GermanForm = () => {
  return <AddPaymentMethod elementLocale="de" />
}
```

**Supported locales:** `'auto'` (default), `'en'`, `'es'`, `'fr'`, `'de'`, `'ja'`, `'zh'`, and [many more](https://stripe.com/docs/js/appendix/supported_locales).

### Custom Fonts Support

Load custom fonts into the payment form using the `elementFonts` prop. This accepts both CSS stylesheet URLs (like Google Fonts) and custom font file URLs.

#### Using CSS Fonts (Google Fonts, Adobe Fonts, etc.)

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithGoogleFonts = () => {
  return (
    <AddPaymentMethod
      elementFonts={[
        {
          cssSrc: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap'
        }
      ]}
      elementAppearance={{
        variables: {
          fontFamily: 'Poppins, sans-serif',
        }
      }}
      onReady={() => console.log('Payment form with custom font ready')}
    />
  )
}
```

#### Using Custom Font Files

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithCustomFont = () => {
  return (
    <AddPaymentMethod
      elementFonts={[
        {
          family: 'Avenir',
          src: 'url(https://my-domain.com/assets/avenir.woff)',
          weight: '500',
        }
      ]}
      elementAppearance={{
        variables: {
          fontFamily: 'Avenir, sans-serif',
        }
      }}
      onReady={() => console.log('Payment form with custom font ready')}
    />
  )
}
```

#### Using Multiple Font Sources

```typescript
import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithMultipleFonts = () => {
  return (
    <AddPaymentMethod
      elementFonts={[
        // Load from CSS stylesheet
        {
          cssSrc: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'
        },
        // Load custom font file
        {
          family: 'CustomFont',
          src: 'url(https://example.com/fonts/custom.woff2)',
          weight: '400',
          display: 'swap'
        }
      ]}
      elementAppearance={{
        variables: {
          fontFamily: 'Roboto, CustomFont, sans-serif',
        }
      }}
      onReady={() => console.log('Payment form with multiple fonts ready')}
    />
  )
}
```

**Font Configuration Options:**

For CSS fonts (`cssSrc`):
- `cssSrc`: URL of the CSS stylesheet containing font definitions

For custom fonts:
- `family`: CSS font-family name (required)
- `src`: URL of the font file in CSS url() format (required)
- `weight`: Font weight (e.g., '400', '500', '700', 'bold')
- `style`: Font style (e.g., 'normal', 'italic', 'oblique')
- `display`: Font display strategy (e.g., 'auto', 'swap', 'fallback')
- `unicodeRange`: Unicode range the font supports

**Note:** After loading fonts with `elementFonts`, remember to apply them using `elementAppearance.variables.fontFamily`.

### TypeScript Type Exports

Import TypeScript types for type-safe configuration:

```typescript
import type {
  PaymentElementAppearance,
  PaymentElementOptions,
  PaymentElementLocale,
  PaymentElementFonts,
  CssFontSource,
  CustomFontSource,
  PaymentElementFormResult,
} from '@zenskar/ui-kit'

// Type-safe appearance configuration
const appearance: PaymentElementAppearance = {
  theme: 'night',
  variables: {
    colorPrimary: '#635bff',
    colorBackground: '#1a1a1a',
    colorText: '#ffffff',
    borderRadius: '8px',
  },
  rules: {
    '.Input': {
      backgroundColor: '#2d2d2d',
      border: '1px solid #404040',
    },
  },
}

// Type-safe element options
const options: PaymentElementOptions = {
  layout: {
    type: 'tabs',
    defaultCollapsed: false,
  },
  fields: {
    billingDetails: {
      name: 'auto',
      email: 'auto',
      phone: 'never',
    },
  },
}

// Type-safe locale
const locale: PaymentElementLocale = 'fr'

// Type-safe fonts
const fonts: PaymentElementFonts = [
  { cssSrc: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap' },
  {
    family: 'CustomFont',
    src: 'url(https://example.com/fonts/custom.woff2)',
    weight: '400'
  }
]

// Use in component
const TypeSafePaymentForm = () => {
  return (
    <AddPaymentMethod
      elementAppearance={appearance}
      elementOptions={options}
      elementLocale={locale}
      elementFonts={fonts}
    />
  )
}
```

### Stripe Elements Documentation

For complete customization options, refer to:
- [Stripe Elements Appearance API](https://stripe.com/docs/elements/appearance-api) - Comprehensive styling guide

### Security & Compliance

- All payment data is processed directly by Stripe's secure servers
- Zenskar never handles raw payment card data
- Automatic PCI compliance when using Stripe Elements
- Built-in fraud detection and 3D Secure support

## Importing Styles

Import the CSS styles in your application:

```typescript
import '@zenskar/ui-kit/styles'
```

### Troubleshooting Style Imports

If you're getting errors when importing styles, add the following declarations to your `global.d.ts` or `vite-env.d.ts` file (if you are using Vite):

```typescript
// Declare style module
declare module "@zenskar/ui-kit/styles" {
  export {};
}

// Optional: If your project complains about CSS imports elsewhere
declare module "*.css";
```

# ZenskarProvider Usage Example

## ✅ Correct Usage (Required)

```tsx
import '@zenskar/ui-kit/styles'
import { ZenskarProvider, BillingInformation, PaymentHistory } from '@zenskar/ui-kit'

function App() {
  return (
    <ZenskarProvider
      organisationId="your-org-id"
      customerId="customer-123"
      token="your-auth-token"
      theme={customTheme}
    >
      <BillingInformation />
      <PaymentHistory />
    </ZenskarProvider>
  )
}
```

## ❌ Incorrect Usage (Will Show Error)

### Missing ZenskarProvider
```tsx
// This will show error: "Component must be wrapped with ZenskarProvider"
<BillingInformation />
<PaymentHistory />
```

### Missing Organisation ID or Customer ID
```tsx
// This will show error: "Organisation ID is required"
<ZenskarProvider customerId="customer-123">
  <BillingInformation />
</ZenskarProvider>
```
