# 通知

本节详细介绍了可用于实现实时用户通知系统的组件和实用工具。该系统旨在通过专用的 UI 组件和浮动提示消息向用户及时传递更新。

通知系统的核心是围绕 WebSocket 连接构建的，使服务器能够即时向客户端推送更新。这确保用户无需刷新应用程序即可随时了解重要事件。

## 架构概述

通知系统遵循一个简单、事件驱动的架构。当后端发生值得注意的事件时，会生成一个通知并通过 WebSocket 通道广播。前端客户端监听此通道，接收通知，并相应地更新 UI。

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

## 核心组件

通知系统主要由两个 React 组件组成：`NotificationAddon` 和 `NotificationSnackbar`。

### NotificationAddon

`NotificationAddon` 组件是通知的主要用户界面元素。它渲染一个铃铛图标，上面带有一个徽章，显示未读通知的数量。

#### 功能

-   **未读计数**：实时显示未读通知的数量。
-   **WebSocket 集成**：自动连接到通知 WebSocket 通道并监听传入消息。
-   **浮动提示通知**：为新的组件级通知触发浮动提示消息。
-   **直接导航**：作为指向主通知页面的链接。

#### 用法

要使用此组件，请将其导入并放置在布局组件（如应用头部）中。它需要一个 `session` 对象才能正常工作，该对象通常从会话上下文中获取。

```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>
      {/* Other header content */}
      <NotificationAddon session={session} />
    </header>
  );
}
```

**重要提示**：为使浮动提示通知正常工作，您的应用程序必须被 `notistack` 库中的 `SnackbarProvider` 包裹。

```javascript "title=示例：应用被 SnackbarProvider 包裹" 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.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` 钩子管理的 WebSocket 客户端提供支持。该钩子为已登录的用户建立连接并监听特定事件。

### `useListenWsClient` 钩子

该钩子抽象了创建和管理 WebSocket 连接的复杂性。它检索当前用户会话并初始化一个连接到指定端点的客户端。

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

### 事件

`NotificationAddon` 组件在 `user` 通道上订阅以下事件：

| 事件名称 | 描述 |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `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 架构确保更新能够即时传递，从而创造出动态且响应迅速的用户体验。