# CheckoutDonate

`CheckoutDonate` 元件提供了一個彈性且易於整合的解決方案，可為您的應用程式增加捐贈功能。它支援多種顯示模式，從開啟結帳對話方塊的簡單按鈕到由您完全控制的自訂 UI。

此元件必須同時被 `PaymentProvider` 和 `DonateProvider` 包裹才能正常運作。`DonateProvider` 負責管理應用程式特定範圍內捐贈實例的設定和狀態。

## 運作方式

捐贈流程由 `DonateProvider` 和 `CheckoutDonate` 共同協調。以下是高層次的概述：

<!-- DIAGRAM_IMAGE_START:flowchart:4:3::1765377352 -->
![CheckoutDonate](assets/diagram/components-checkout-checkout-donate-01.zh-TW.jpg)
<!-- DIAGRAM_IMAGE_END -->

1.  **初始化**：`DonateProvider` 從後端獲取並快取捐贈設定（如預設金額、按鈕文字），並透過唯一的 `mountLocation` 進行識別。
2.  **渲染**：`CheckoutDonate` 根據檢索到的設定及其 props 渲染按鈕或自訂 UI。
3.  **互動**：當使用者發起捐贈時，`CheckoutDonate` 會開啟一個包含為該捐贈預先設定好的 `CheckoutForm` 的對話方塊。
4.  **支付**：使用者透過 `CheckoutForm` 完成支付。
5.  **確認**：成功支付後，會觸發 `onPaid` 回呼，且元件會自動刷新支持者列表。

## Provider 設定

在使用 `CheckoutDonate` 之前，您必須用 `PaymentProvider` 和 `DonateProvider` 包裹您的元件樹。

```tsx Provider Setup Example icon=logos:react
import {
  PaymentProvider,
  DonateProvider,
  CheckoutDonate,
} from '@blocklet/payment-react';
import { useSessionContext } from '../hooks/session-context'; // 您的 session context hook

function DonationPage() {
  const { session, connect } = useSessionContext();

  // 確保在渲染 provider 之前載入 session
  if (!session) {
    return <div>Loading...</div>;
  }

  return (
    <PaymentProvider session={session} connect={connect}>
      <DonateProvider
        mountLocation="unique-page-identifier" // 此捐贈情境的唯一金鑰
        description="給我很棒的部落格文章的捐贈"
        defaultSettings={{
          btnText: '支持我',
        }}>
        {/* 您的 CheckoutDonate 元件放在這裡 */}
        <CheckoutDonate 
          settings={{
            target: "post-123",
            title: "支持作者",
            description: "如果您覺得這篇文章有幫助，歡迎請我喝杯咖啡",
            reference: "https://your-site.com/posts/123",
            beneficiaries: [
              {
                address: "z2qa...",
                share: "100",
              },
            ],
          }}
        />
      </DonateProvider>
    </PaymentProvider>
  );
}
```

更多詳情，請參閱 [`DonateProvider`](./providers-donate-provider.md) 文件。

## 元件 Props

### `DonateProps`

| Prop | Type | Description |
| --- | --- | --- |
| `settings` | `CheckoutDonateSettings` | **必填。** 此特定捐贈實例的設定。 |
| `onPaid` | `(session) => void` | 選填。成功支付後執行的回呼函式。 |
| `onError` | `(error) => void` | 選填。發生錯誤時執行的回呼函式。 |
| `mode` | `'default' \| 'inline' \| 'custom'` | 選填。渲染模式。預設為 `'default'`。 |
| `livemode` | `boolean` | 選填。覆寫來自 `PaymentProvider` 的 `livemode`。 |
| `timeout` | `number` | 選填。支付後關閉對話方塊前等待的毫秒數。預設為 `5000`。 |
| `theme` | `'default' \| 'inherit' \| object` | 選填。主題自訂選項。請參閱 [主題設定](./guides-theming.md) 指南。 |
| `children` | `(openDialog, donateTotalAmount, supporters, loading, donateSettings) => React.ReactNode` | 選填。僅在 `mode="custom"` 時使用的 render prop 函式。 |

### `CheckoutDonateSettings`

此物件被傳遞給 `settings` prop，並定義了捐贈的核心細節。

| Property | Type | Description |
| --- | --- | --- |
| `target` | `string` | **必填。** 捐贈目標的唯一識別碼（例如，文章 ID、專案名稱）。 |
| `title` | `string` | **必填。** 顯示在捐贈對話方塊頂部的標題。 |
| `description` | `string` | **必填。** 顯示在捐贈對話方塊中的簡短描述。 |
| `reference` | `string` | **必填。** 與捐贈相關的 URL，用於參考。 |
| `beneficiaries` | `PaymentBeneficiary[]` | **必填。** 一個物件陣列，定義資金接收者。每個物件都需要 `address`（收款人的 DID）和 `share`（百分比）。 |
| `amount` | `object` | 選填。設定捐贈金額，包括 `presets`（例如 `['1', '5', '10']`）、預設的 `preset`、`minimum`、`maximum` 以及是否允許 `custom` 金額。 |
| `appearance` | `object` | 選填。自訂外觀和風格，包括 `button`（文字、圖示、樣式）和 `history` 顯示（`'avatar'` 或 `'table'`）。 |

## 使用範例

### 預設模式

這是使用 `CheckoutDonate` 最簡單的方式。它會渲染一個按鈕，該按鈕會開啟一個捐贈對話方塊，並附上近期支持者的摘要。

```tsx Default Donation Button icon=logos:react
import {
  PaymentProvider,
  DonateProvider,
  CheckoutDonate,
} from '@blocklet/payment-react';
import { useSessionContext } from '../hooks/session-context';

function App() {
  const { session, connect } = useSessionContext();

  if (!session) {
    return <div>Loading session...</div>;
  }

  return (
    <PaymentProvider session={session} connect={connect}>
      <DonateProvider
        mountLocation="blog-post-123"
        description="給部落格文章 123 的捐贈"
        defaultSettings={{
          btnText: '請我喝杯咖啡',
          historyType: 'avatar',
        }}>
        <CheckoutDonate
          settings={{
            target: 'post-123',
            title: '支持作者',
            description: '如果您覺得這篇文章有幫助，請考慮小額捐款。',
            reference: 'https://example.com/posts/123',
            beneficiaries: [
              {
                address: 'z2qa...gCLd', // 作者的 DID 地址
                share: '100',
              },
            ],
          }}
          onPaid={() => {
            console.log('捐贈成功！');
          }}
        />
      </DonateProvider>
    </PaymentProvider>
  );
}
```

### 自訂 UI 模式

若要完全控制使用者介面，請使用 `mode="custom"` 並提供一個 render prop 作為 `children`。此函式讓您能存取捐贈狀態，包括募集的總金額和支持者列表，從而讓您能夠建立完全自訂的顯示方式。

```tsx Custom Donation UI icon=logos:react
import {
  PaymentProvider,
  DonateProvider,
  CheckoutDonate,
} from '@blocklet/payment-react';
import { useSessionContext } from '../hooks/session-context';
import { CircularProgress, Button } from '@mui/material';

function CustomDonationDisplay() {
  const { session, connect } = useSessionContext();

  if (!session) {
    return <div>Loading session...</div>;
  }

  const donateSettings = {
    target: 'post-123',
    title: '支持作者',
    description: '如果您覺得這篇文章有幫助，請考慮小額捐款。',
    reference: 'https://example.com/posts/123',
    beneficiaries: [
      {
        address: 'z2qa...gCLd', // 作者的 DID 地址
        share: '100',
      },
    ],
  };

  return (
    <PaymentProvider session={session} connect={connect}>
      <DonateProvider
        mountLocation="blog-post-123"
        description="給部落格文章 123 的捐贈">
        <CheckoutDonate mode="custom" settings={donateSettings}>
          {(openDonate, totalAmount, supporters, loading, settings) => (
            <div style={{ border: '1px solid #ccc', padding: '16px', borderRadius: '8px' }}>
              <h2>我們的支持者</h2>
              <p>總捐贈金額：<strong>{totalAmount}</strong></p>
              <Button variant="contained" onClick={openDonate}>
                {settings?.appearance?.button?.text || '立即捐贈'}
              </Button>
              {loading ? (
                <CircularProgress style={{ marginTop: '16px' }} />
              ) : (
                <ul style={{ listStyle: 'none', padding: 0, marginTop: '16px' }}>
                  {(supporters.supporters || []).map((supporter) => (
                    <li key={supporter.id}>
                      <span>{supporter.customer?.name}</span>
                    </li>
                  ))}
                </ul>
              )}
            </div>
          )}
        </CheckoutDonate>
      </DonateProvider>
    </PaymentProvider>
  );
}
```

`children` 函式會收到以下參數：

-   `openDonate`：一個手動觸發捐贈對話方塊的函式。
-   `totalAmount`：已捐贈總金額的格式化字串（例如 `"125.00 T"`）。
-   `supporters`：一個 `DonateHistory` 物件，包含 `supporters` 陣列和貨幣資訊。
-   `loading`：一個布林值，表示是否正在獲取支持者資料。
-   `settings`：已解析的捐贈設定，由 `DonateProvider` 和 props 合併而成。