# 通知

本節詳細介紹了可用於實作即時使用者通知系統的元件和工具。該系統旨在透過專用的 UI 元件和快顯訊息，向使用者及時傳遞更新。

通知系統的核心圍繞 WebSocket 連線建構，使伺服器能夠即時向用戶端推送更新。這確保了使用者無需刷新應用程式即可隨時了解重要事件。

## 架構概覽

通知系統遵循一個直接的、事件驅動的架構。當後端發生值得注意的事件時，會產生一則通知並透過 WebSocket 通道廣播。前端用戶端會監聽此通道，接收通知，並相應地更新 UI。

<!-- DIAGRAM_IMAGE_START:architecture:16:9:1765962229 -->
![Notifications](assets/diagram/notifications-diagram-0.zh-TW.jpg)
<!-- DIAGRAM_IMAGE_END -->

## 核心元件

通知系統主要由兩個 React 元件組成：`NotificationAddon` 和 `NotificationSnackbar`。

### NotificationAddon

`NotificationAddon` 元件是通知的主要使用者介面元素。它會渲染一個鈴鐺圖示，並帶有一個徽章，顯示未讀通知的數量。

#### 功能

-   **未讀計數**：即時顯示未讀通知的數量。
-   **WebSocket 整合**：自動連線到通知 WebSocket 通道並監聽傳入的訊息。
-   **快顯通知**：針對新的元件級別通知觸發快顯訊息。
-   **直接導覽**：作為連結，可導向主通知頁面。

#### 用法

若要使用此元件，請將其匯入並放置在佈局元件中，例如應用程式的標頭。它需要一個 `session` 物件才能正常運作，該物件通常從 session context 中獲取。

```javascript "title=範例：整合 NotificationAddon" icon=logos:javascript
import NotificationAddon from '@arcblock/ux/lib/common/notification-addon';
import { useSessionContext } from '@arcblock/did-connect-react';

export default function AppHeader() {
  const { session } = useSessionContext();

  return (
    <header>
      {/* 其他標頭內容 */}
      <NotificationAddon session={session} />
    </header>
  );
}
```

**重要**：為了讓快顯通知正常運作，您的應用程式必須被 `notistack` 函式庫的 `SnackbarProvider` 包裹。

```javascript "title=範例：被 SnackbarProvider 包裹的 App" icon=logos:javascript
import { SnackbarProvider } from 'notistack';
import App from './App';

function Root() {
  return (
    <SnackbarProvider maxSnack={3}>
      <App />
    </SnackbarProvider>
  );
}
```

#### Props

<x-field-group>
  <x-field data-name="session" data-type="object" data-required="true">
    <x-field-desc markdown>包含使用者和通知資料的 session 物件。該元件依賴 `session.user`、`session.unReadCount` 和 `session.setUnReadCount`。</x-field-desc>
  </x-field>
</x-field-group>

### NotificationSnackbar

此元件為快顯通知提供了一個豐富且標準化的 UI。它由 `NotificationAddon` 透過 `notistack` 的 `enqueueSnackbar` 函式在內部使用，不適合直接使用。

#### 功能

-   **基於嚴重性等級的樣式**：快顯通知的外觀會根據通知的嚴重性等級（`success`、`info`、`warning`、`error`）而改變。
-   **豐富的內容顯示**：除了簡單的標題和描述外，還能顯示結構化的活動通知（例如，「使用者 X 喜歡了您的貼文」）。
-   **互動式連結**：自動將描述中可識別的模式（如使用者 DID 或 DApp 地址）轉換為可點擊的連結。
-   **點擊開啟**：點擊快顯通知可將使用者導覽至詳細的通知檢視。

## WebSocket 整合

即時功能由 `useListenWsClient` hook 管理的 WebSocket 用戶端提供支援。此 hook 為登入的使用者建立連線，並監聽特定事件。

### `useListenWsClient` Hook

此 hook 抽象化了建立和管理 WebSocket 連線的複雜性。它會獲取目前的使用者 session，並初始化一個連線到指定端點的用戶端。

```javascript "title=Hook 用法" icon=logos:javascript
const wsClient = useListenWsClient('user');
```

### 事件

`NotificationAddon` 元件在 `user` 通道上訂閱以下事件：

| Event Name | Description |
| --- | --- |
| `notification:blocklet:create` | 當為使用者建立新通知時觸發。該元件會增加未讀計數，並可能顯示一則快顯訊息。 |
| `notification:blocklet:read` | 當一則或多則通知被讀取時觸發。該元件會將未讀計數減去已讀通知的數量。 |

完整的事件名稱是使用 blocklet 的 DID 和使用者的 DID 動態建構的，例如：`{blocklet.did}/{user.did}/notification:blocklet:create`。

## 關鍵工具

幾個工具函式透過處理和格式化通知資料來支援通知系統。

### `mergeAdjacentNotifications`

此函式將連續的、相似的通知分組為一個單一的、聚合的條目。例如，如果一位使用者連續收到來自不同使用者的多個「喜歡」通知，此函式可以將它們合併為一則通知，如「Alice、Bob 和另外 2 人喜歡了您的貼文」。

### `toClickableSpan`

此工具負責透過將純文字轉換為豐富的互動式內容來增強通知描述。它會解析輸入的字串，識別如使用者 DID 或 DApp 地址等特殊實體，並將它們轉換為可點擊的 HTML `<a>` 標籤。這允許使用者從通知內部直接導覽至使用者的個人資料頁面或 DApp 的頁面。

### `sanitize`

一個圍繞 `DOMPurify` 的封裝函式，用於在渲染 HTML 內容之前對其進行清理和消毒。這是一項安全措施，旨在防止在顯示可能包含使用者生成資料的通知內容時發生跨站腳本（XSS）攻擊。

## 總結

通知系統為保持使用者資訊同步提供了一個強大且即時的解決方案。透過利用 `NotificationAddon` 元件並確保您的應用程式已配置 `SnackbarProvider`，您可以輕鬆地將一個功能齊全的通知中心整合到您的 blocklet 中。底層的 WebSocket 架構確保了更新的即時傳遞，創造出一個動態且反應迅速的使用者體驗。