# CheckoutForm

`CheckoutForm` 元件是處理付款連結和結帳會話的主要進入點。它作為一個高階封裝器，根據提供的 ID 擷取所有必要的資料，並呈現適當的付款或捐款介面。此元件是將完整的結帳流程整合到您應用程式中最簡單的方法。

務必將 `CheckoutForm` 或其任何父層元件用 `PaymentProvider` 包裹，以確保它能存取必要的情境資訊，例如會話資訊和 API 設定。更多詳細資訊，請參閱 [PaymentProvider 文件](./providers-payment-provider.md)。

## 運作方式

該元件會協調整個結帳流程：

1.  **初始化**：它會以一個 `paymentLink` ID (前綴為 `plink_`) 或一個 `checkoutSession` ID (前綴為 `cs_`) 掛載。
2.  **資料擷取**：它會與付款後端通訊，以擷取所有必要的情境資訊，包括付款方式、訂單項目和顧客詳細資訊。
3.  **UI 渲染**：根據 `formType` prop，它會在內部渲染標準的 `Payment` 元件或專門的 `DonationForm` 元件。
4.  **狀態管理**：它會處理付款的整個生命週期，包括載入狀態、完成狀態和錯誤處理。

```d2 Basic Flow of CheckoutForm icon=lucide:workflow
direction: down
shape: sequence_diagram

User-Action: {
  shape: c4-person
  label: "使用者"
}

Application: {
  label: "您的 React 應用程式"

  CheckoutForm-Component: {
    label: "CheckoutForm"
  }

  Payment-Component: {
    label: "付款元件"
  }

  Donation-Component: {
    label: "捐款表單元件"
  }
}

Payment-API: {
  label: "付款後端 API"
  shape: cylinder
}

User-Action -> Application.CheckoutForm-Component: "1. 以 'id' prop 掛載"
Application.CheckoutForm-Component -> Payment-API: "2. 擷取會話資料"
Payment-API -> Application.CheckoutForm-Component: "3. 回傳結帳情境"

alt "若 formType 為 'payment'" {
  Application.CheckoutForm-Component -> Application.Payment-Component: "4. 渲染付款 UI"
}

alt "若 formType 為 'donation'" {
  Application.CheckoutForm-Component -> Application.Donation-Component: "5. 渲染捐款 UI"
}

User-Action -> Application.Payment-Component: "6. 完成付款"
User-Action -> Application.Donation-Component: "7. 完成捐款"

```

## Props

`CheckoutForm` 元件接受以下 props：

| Prop          | Type                                                                       | Required | Default       | Description                                                                                             |
|---------------|----------------------------------------------------------------------------|----------|---------------|-------------------------------------------------------------------------------------------------------------------------|
| `id`          | `string`                                                                   | 是      | -             | 付款連結 (`plink_...`) 或結帳會話 (`cs_...`) 的唯一識別碼。                                |
| `mode`        | `'standalone'` \| `'inline'` \| `'popup'` \| `'inline-minimal'` \| `'popup-minimal'` | 否       | `'inline'`    | 定義渲染模式。`'standalone'` 用於全頁檢視，`'inline'` 用於嵌入容器中。                  |
| `formType`    | `'payment'` \| `'donation'`                                                 | 否       | `'payment'`   | 決定要渲染的表單類型。使用 `'donation'` 來實現專門的捐款流程。                          |
| `onPaid`      | `(res: CheckoutContext) => void`                                           | 否       | -             | 付款成功後執行的回呼函式。接收最終的結帳情境作為參數。               |
| `onError`     | `(err: Error) => void`                                                     | 否       | `console.error` | 在過程中發生錯誤時執行的回呼函式。                                                   |
| `onChange`    | `(data: CheckoutFormData) => void`                                         | 否       | -             | 任何表單欄位值變更時觸發的回呼函式。                                                         |
| `goBack`      | `() => void`                                                               | 否       | -             | 如果提供，會渲染一個返回按鈕，並在點擊時呼叫此函式。                                                |
| `extraParams` | `Record<string, any>`                                                      | 否       | `{}`          | 從付款連結啟動會話時，要傳遞到 URL 中的額外參數物件。                  |
| `theme`       | `'default'` \| `'inherit'` \| `PaymentThemeOptions`                            | 否       | `'default'`   | 控制元件的主題。`'inherit'` 使用父層主題，或者您可以傳遞一個自訂主題物件。             |
| `action`      | `string`                                                                   | 否       | `''`          | 用於自訂 UI 元素（如按鈕文字）或追蹤特定流程的字串識別碼。                   |

## 使用方式

### 基本的內嵌付款表單

這是將付款表單直接嵌入到您應用程式 UI 中最常見的使用案例。該元件會在內部處理所有邏輯。

```tsx MyStorePage.tsx icon=lucide:shopping-cart
import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';
import { useSessionContext } from './hooks/session-context'; // 您應用程式的 session hook

export default function MyStorePage() {
  const { session, connectApi } = useSessionContext();

  const handlePaymentSuccess = (result) => {
    console.log('付款成功！', result);
    alert('感謝您的購買！');
  };

  const handlePaymentError = (error) => {
    console.error('付款失敗：', error);
    alert('抱歉，您的付款無法處理。');
  };

  return (
    <PaymentProvider session={session} connectApi={connectApi}>
      <div style={{ maxWidth: '960px', margin: '0 auto' }}>
        <h1>結帳</h1>
        <CheckoutForm
          id="plink_xxxxxxxxxxxxxx" // 請替換成您的付款連結 ID
          mode="inline"
          onPaid={handlePaymentSuccess}
          onError={handlePaymentError}
        />
      </div>
    </PaymentProvider>
  );
}
```

### 獨立的全頁結帳

使用 `mode="standalone"` 來渲染一個專用的全頁結帳體驗。這非常適合您將使用者重新導向到一個單獨頁面以完成付款的場景。

```tsx CheckoutPage.tsx icon=lucide:layout-template
import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';
import { useSessionContext } from './hooks/session-context';

export default function CheckoutPage() {
  const { session, connectApi } = useSessionContext();
  const paymentLinkId = 'plink_xxxxxxxxxxxxxx'; // 可從 URL 參數中取得

  return (
    <PaymentProvider session={session} connectApi={connectApi}>
      <CheckoutForm id={paymentLinkId} mode="standalone" />
    </PaymentProvider>
  );
}
```

### 捐款表單

透過設定 `formType="donation"`，該元件會渲染一個專為捐款活動量身打造的特殊 UI，包括金額預設和福利顯示等功能。

```tsx DonationPage.tsx icon=lucide:gift
import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';
import { useSessionContext } from './hooks/session-context';

export default function DonationPage() {
  const { session, connectApi } = useSessionContext();

  return (
    <PaymentProvider session={session} connectApi={connectApi}>
      <div style={{ padding: '2rem' }}>
        <h2>支持我們的事業</h2>
        <CheckoutForm
          id="plink_yyyyyyyyyyyyyy" // 請替換成您的捐款連結 ID
          formType="donation"
          onPaid={() => alert('感謝您的慷慨捐款！')}
        />
      </div>
    </PaymentProvider>
  );
}
```