# useConnect

`useConnect` hook 提供了一種強大的程式化方式來開啟、關閉和管理 `DidConnect` UI 模態框。當您需要比宣告式 `Button` 元件提供更多對連線流程的控制時，例如從自訂 UI 元素、選單項目或響應應用程式事件來觸發模態框，這便是理想的解決方案。

這個 hook 是 `Button` 元件背後的引擎，讓您可以直接存取相同的核心功能。

## 運作方式

`useConnect` hook 回傳兩個主要元素：

1.  **`connectHolder`**：一個必須在您的元件樹中渲染的 React 元素。此元素負責在 `DidConnect` 模態框被啟動時進行渲染。在 `open` 函式被呼叫前，它保持不可見。
2.  **`connectApi`**：一個包含您將用來控制模態框生命週期的函式（`open`、`close`、`openPopup`、`loginOAuth`）的物件。

<!-- DIAGRAM_IMAGE_START:flowchart:4:3:1765962229 -->
![useConnect](assets/diagram/use-connect-diagram-0.zh-TW.jpg)
<!-- DIAGRAM_IMAGE_END -->

## 設定

若要使用此 hook，請在您的元件中匯入並呼叫它。然後，確保您在應用程式的某處渲染 `connectHolder`，最好是在頂層元件中，以確保模態框可以覆蓋所有其他內容。

```javascript Basic Setup icon=logos:javascript
import React from 'react';
import { useConnect } from '@arcblock/did-connect-react';

function MyComponent() {
  // 1. 初始化 hook
  const { connectHolder, connectApi } = useConnect();

  const handleLogin = () => {
    // 2. 使用 API 開啟模態框
    connectApi.open({
      action: 'login',
      onSuccess: (result) => {
        console.log('登入成功！', result);
      },
      onClose: () => {
        console.log('模態框已由使用者關閉。');
      }
    });
  };

  return (
    <div>
      <button type="button" onClick={handleLogin}>
        使用 DID 登入
      </button>

      {/* 3. 渲染 holder 元件 */}
      {connectHolder}
    </div>
  );
}

export default MyComponent;
```

## API 參考

`connectApi` 物件提供以下方法來控制連線過程。

### `connectApi.open(options)`

這是觸發並顯示 `DidConnect` 模態框的主要函式。它接受一個 `options` 物件來設定連線會話的行為、外觀和回呼。

**參數 (`options`)**

<x-field-group>
  <x-field data-name="action" data-type="string" data-required="true">
    <x-field-desc markdown>連線請求的目的，例如 `login`、`claim`、`sign` 等。這決定了錢包內的工作流程。</x-field-desc>
  </x-field>
  <x-field data-name="onSuccess" data-type="(result: object) => void" data-required="false">
    <x-field-desc markdown>當使用者在錢包中成功完成操作時執行的回呼函式。`result` 物件包含來自錢包的回應。</x-field-desc>
  </x-field>
  <x-field data-name="onClose" data-type="() => void" data-required="false">
    <x-field-desc markdown>當使用者在未完成操作的情況下手動關閉模態框時執行的回呼函式。</x-field-desc>
  </x-field>
  <x-field data-name="onError" data-type="(error: any) => void" data-required="false">
    <x-field-desc markdown>如果在過程中發生錯誤（例如超時或網路問題）時執行的回呼函式。</x-field-desc>
  </x-field>
  <x-field data-name="messages" data-type="ConnectMessages" data-required="false">
    <x-field-desc markdown>用於自訂模態框中顯示文字的物件。詳情請參閱 `ConnectMessages` 型別。</x-field-desc>
    <x-field data-name="title" data-type="string" data-desc="模態框標題。"></x-field>
    <x-field data-name="scan" data-type="string" data-desc="QR code 旁的文字。"></x-field>
    <x-field data-name="confirm" data-type="string" data-desc="確認步驟的文字。"></x-field>
    <x-field data-name="success" data-type="ReactNode" data-desc="成功畫面的內容。"></x-field>
  </x-field>
  <x-field data-name="popup" data-type="boolean" data-default="true">
    <x-field-desc markdown>若為 `true`，UI 將以模態對話框形式顯示。若為 `false`，則會內聯渲染，需要設定 `containerEl`。</x-field-desc>
  </x-field>
  <x-field data-name="containerEl" data-type="Element" data-required="false">
    <x-field-desc markdown>當 `popup` 設為 `false` 時，`DidConnect` 元件將在此 DOM 元素中渲染。</x-field-desc>
  </x-field>
  <x-field data-name="closeTimeout" data-type="number" data-default="2000">
    <x-field-desc markdown>連線成功後，模態框自動關閉前的延遲時間（毫秒）。</x-field-desc>
  </x-field>
  <x-field data-name="checkInterval" data-type="number" data-default="2000">
    <x-field-desc markdown>輪詢伺服器以檢查會話狀態的間隔時間（毫秒）。</x-field-desc>
  </x-field>
  <x-field data-name="checkTimeout" data-type="number" data-default="300000">
    <x-field-desc markdown>連線嘗試超時前的總時間（毫秒）。</x-field-desc>
  </x-field>
  <x-field data-name="extraParams" data-type="object" data-default="{}">
    <x-field-desc markdown>要包含在會話建立請求中的任何額外參數，這些參數可以在伺服器端擷取。</x-field-desc>
  </x-field>
</x-field-group>

### `connectApi.close()`

手動關閉 `DidConnect` 模態框。模態框在成功或使用者取消時會自動關閉，但如果您因其他原因需要以程式化方式關閉它，可以呼叫此函式。

```javascript icon=lucide:x-circle
// 範例：在成功回呼中短暫延遲後關閉模態框
connectApi.open({
  action: 'login',
  onSuccess: () => {
    showTemporarySuccessMessage();
    setTimeout(() => {
      connectApi.close();
    }, 1500);
  },
  closeTimeout: 999999 // 防止自動關閉
});
```

### `connectApi.openPopup(params, options)`

此函式提供了一種替代的連線方法，它會在新的瀏覽器彈出視窗中開啟 DID Connect 流程，而不是在當前頁面內的模態框中。這對於某些類似 OAuth 的流程或與無法注入模態框的網站整合時非常有用。

**參數**

<x-field-group>
  <x-field data-name="params" data-type="ConnectProps" data-required="true">
    <x-field-desc markdown>與 `open` 方法的選項類似。一個關鍵區別是 `params.extraParams.provider` 是**必需的**，用於識別驗證方法（例如 'github'、'google'）。</x-field-desc>
  </x-field>
  <x-field data-name="options" data-type="object" data-required="false">
    <x-field-desc markdown>彈出視窗本身的設定。</x-field-desc>
    <x-field data-name="baseUrl" data-type="string" data-desc="用於建構彈出視窗 URL 的基礎 URL。"></x-field>
    <x-field data-name="locale" data-type="string" data-default="en" data-desc="彈出視窗內容的語系。"></x-field>
    <x-field data-name="popupOptions" data-type="object" data-desc="直接傳遞給 `window.open()` 的選項，用於自訂彈出視窗的大小和功能。"></x-field>
  </x-field>
</x-field-group>

**用法**

`openPopup` 函式回傳一個 `Promise`，在成功時會解析並帶有驗證資料，在失敗或取消時則會拒絕。

```javascript icon=lucide:external-link
const handleGithubLogin = async () => {
  try {
    const result = await connectApi.openPopup({
      action: 'login',
      onSuccess: () => console.log('此回呼也會被觸發'),
      extraParams: { provider: 'github' } // 此為必需項
    });
    console.log('透過彈出視窗登入成功：', result);
  } catch (err) {
    if (err.message === 'Popup closed') {
      console.log('使用者已關閉彈出視窗。');
    } else {
      console.error('發生錯誤：', err);
    }
  }
};
```

### `connectApi.loginOAuth(options)`

這是一個輔助函式，用於直接啟動 OAuth 登入流程。它是一個較低層級的工具，由函式庫的其他部分在內部使用。

**參數 (`options`)**

<x-field-group>
  <x-field data-name="provider" data-type="string" data-required="true" data-desc="要使用的 OAuth 提供者，例如 'github'、'google'。"></x-field>
  <x-field data-name="action" data-type="string" data-required="true" data-desc="操作，通常是 'login'。"></x-field>
  <x-field data-name="extraParams" data-type="object" data-required="false" data-desc="OAuth 流程的額外參數。"></x-field>
  <x-field data-name="onLogin" data-type="function" data-required="true" data-desc="登入成功後執行的回呼函式。"></x-field>
</x-field-group>