omninotice-notification-feed 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +266 -2
- package/dist/NotificationFeedPage-B7jnF1LL.js +971 -0
- package/dist/NotificationFeedPage-B7jnF1LL.js.map +1 -0
- package/dist/NotificationFeedPage-F2ht69hw.cjs +2 -0
- package/dist/NotificationFeedPage-F2ht69hw.cjs.map +1 -0
- package/dist/NotificationsFeedProvider-BApcYuJs.cjs +2 -0
- package/dist/NotificationsFeedProvider-BApcYuJs.cjs.map +1 -0
- package/dist/NotificationsFeedProvider-DTr1ulMN.js +35 -0
- package/dist/NotificationsFeedProvider-DTr1ulMN.js.map +1 -0
- package/dist/api/actions.d.ts +5 -0
- package/dist/api/apiFetch.d.ts +28 -0
- package/dist/api/envelope.d.ts +24 -0
- package/dist/api/notificationCounts.d.ts +24 -0
- package/dist/api/notificationDetails.d.ts +74 -0
- package/dist/api/notificationMapper.d.ts +11 -0
- package/dist/api/notifications.d.ts +102 -0
- package/dist/api/requests.d.ts +5 -0
- package/dist/api/schema.d.ts +17 -0
- package/dist/app/contexts/NotificationsContext.d.ts +10 -0
- package/dist/app/contexts/TabContext.d.ts +9 -0
- package/dist/app/providers/NotificationsFeedDataProvider.d.ts +19 -0
- package/dist/app/providers/NotificationsFeedProvider.d.ts +10 -0
- package/dist/app/providers/TabProvider.d.ts +11 -0
- package/dist/components/atoms/Button/Button.d.ts +3 -0
- package/dist/components/atoms/Container/Container.d.ts +4 -0
- package/dist/components/atoms/Loaders/SpinnerLoader/SpinnerLoader.d.ts +4 -0
- package/dist/components/atoms/NotificationIcon/NotificationIcon.d.ts +5 -0
- package/dist/components/atoms/Text/Text.d.ts +2 -0
- package/dist/components/atoms/icons/ArrowIcon.d.ts +2 -0
- package/dist/components/atoms/icons/BellRingIcon.d.ts +1 -0
- package/dist/components/atoms/icons/CheckIcon.d.ts +2 -0
- package/dist/components/atoms/icons/ChevronIcon.d.ts +2 -0
- package/dist/components/atoms/icons/CloseIcon.d.ts +2 -0
- package/dist/components/atoms/index.d.ts +8 -0
- package/dist/components/atoms/types.d.ts +33 -0
- package/dist/components/molecules/NotificationCard/NotificationCard.d.ts +2 -0
- package/dist/components/molecules/NotificationList/NotificationList.d.ts +6 -0
- package/dist/components/molecules/NotificationsState/NotificationsState.d.ts +2 -0
- package/dist/components/molecules/PageTitle/PageTitle.d.ts +1 -0
- package/dist/components/molecules/Tab/Tab.d.ts +1 -0
- package/dist/components/molecules/index.d.ts +3 -0
- package/dist/components/molecules/types.d.ts +60 -0
- package/dist/components/organisms/NotificationDetailsSidebar/NotificationDetailsSidebar.d.ts +8 -0
- package/dist/components/organisms/NotificationsRoot/NotificationsRoot.d.ts +4 -0
- package/dist/components/organisms/NotificationsSection/NotificationsSection.d.ts +1 -0
- package/dist/components/organisms/index.d.ts +1 -0
- package/dist/components/pages/NotificationFeedPage.d.ts +8 -0
- package/dist/config/SettingsContext.d.ts +3 -0
- package/dist/config/settings.config.d.ts +61 -0
- package/dist/helpers/classNames.d.ts +3 -0
- package/dist/helpers/decoder.d.ts +2 -0
- package/dist/helpers/isEmoji.d.ts +1 -0
- package/dist/helpers/renderButtonContent.d.ts +2 -0
- package/dist/helpers/renderIcon.d.ts +2 -0
- package/dist/helpers/resolvePicture.d.ts +18 -0
- package/dist/hooks/useNotificationDetails.d.ts +7 -0
- package/dist/hooks/useNotificationsFeed.d.ts +33 -0
- package/dist/hooks/useTab.d.ts +1 -0
- package/dist/index.d.ts +0 -0
- package/dist/notificationDetails-BEOAyDdp.cjs +2 -0
- package/dist/notificationDetails-BEOAyDdp.cjs.map +1 -0
- package/dist/notificationDetails-CqA8ONhr.js +102 -0
- package/dist/notificationDetails-CqA8ONhr.js.map +1 -0
- package/dist/public.cjs +1 -0
- package/dist/public.d.ts +8 -0
- package/dist/public.js +4 -0
- package/dist/register-all.cjs +2 -0
- package/dist/register-all.cjs.map +1 -0
- package/dist/register-all.d.ts +1 -0
- package/dist/register-all.js +24 -0
- package/dist/register-all.js.map +1 -0
- package/dist/standalone.cjs +1 -0
- package/dist/standalone.d.ts +8 -0
- package/dist/standalone.js +3 -0
- package/dist/style.css +2 -0
- package/package.json +67 -4
package/README.md
CHANGED
|
@@ -1,3 +1,267 @@
|
|
|
1
|
-
#
|
|
1
|
+
# omninotice-notification-feed
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Совместимость с Apiary: `^1.3.0`. Требуется React `>=18.2`.
|
|
4
|
+
|
|
5
|
+
**Карта:** [Подключение](#быстрое-подключение) · [Apiary-слот](#apiary-слот) ·
|
|
6
|
+
[Запросы](#запросы) · [Настройки](#настройки) · [API](#api-пакета) ·
|
|
7
|
+
[CSS-токены](#css-токены) · [Локальный просмотр](#локальный-просмотр)
|
|
8
|
+
|
|
9
|
+
## Быстрое подключение
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
NotificationFeedPage,
|
|
14
|
+
NotificationsFeedProvider,
|
|
15
|
+
} from "omninotice-notification-feed";
|
|
16
|
+
import "omninotice-notification-feed/style.css";
|
|
17
|
+
|
|
18
|
+
export function Notifications() {
|
|
19
|
+
return (
|
|
20
|
+
<NotificationsFeedProvider>
|
|
21
|
+
<NotificationFeedPage />
|
|
22
|
+
</NotificationsFeedProvider>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Этот способ использует провайдеры `@core/data` и действие `@core/actions`.
|
|
28
|
+
Для обычного React-приложения без Apiary используйте точку входа
|
|
29
|
+
`omninotice-notification-feed/standalone` и передайте API-функции:
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import {
|
|
33
|
+
NotificationFeedPage,
|
|
34
|
+
NotificationsFeedProvider,
|
|
35
|
+
} from "omninotice-notification-feed/standalone";
|
|
36
|
+
import "omninotice-notification-feed/style.css";
|
|
37
|
+
|
|
38
|
+
const api = {
|
|
39
|
+
fetchList: (page: number) => myApi.getNotifications({ page }),
|
|
40
|
+
fetchCounts: () => myApi.getNotificationCounts(),
|
|
41
|
+
fetchDetails: (messageId: string, signal?: AbortSignal) =>
|
|
42
|
+
myApi.getNotificationDetails(messageId, { signal }),
|
|
43
|
+
markRead: (messageId: string) => myApi.markNotificationRead(messageId),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function Notifications() {
|
|
47
|
+
return (
|
|
48
|
+
<NotificationsFeedProvider api={api}>
|
|
49
|
+
<NotificationFeedPage />
|
|
50
|
+
</NotificationsFeedProvider>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Функции API должны возвращать ответы в формате, описанном в разделе
|
|
56
|
+
[Запросы](#запросы). Передавайте `signal` в запрос деталей, чтобы он
|
|
57
|
+
отменялся при закрытии панели. `markRead` вызывается после успешной загрузки
|
|
58
|
+
деталей непрочитанного уведомления и при нажатии на действие карточки;
|
|
59
|
+
локальное состояние меняется только после успешного выполнения функции.
|
|
60
|
+
Существующий корневой импорт и Apiary-слот сохраняют прежний контракт.
|
|
61
|
+
|
|
62
|
+
### Apiary-слот
|
|
63
|
+
|
|
64
|
+
В точке входа приложения импортируйте регистрацию и стили:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import "omninotice-notification-feed/register-all";
|
|
68
|
+
import "omninotice-notification-feed/style.css";
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Добавьте компонент в конфигурацию слота:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
{ name: "sidebar", components: [{ id: "notifications", order: 2 }] }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Обёртка `NotificationsFeedProvider` и регистрация компонента выполняются пакетом.
|
|
78
|
+
Хост должен предоставлять `@core/hive`, `@core/data` и `@core/actions`.
|
|
79
|
+
|
|
80
|
+
## Запросы
|
|
81
|
+
|
|
82
|
+
Пакет вызывает провайдеры через `callProvider`. Зарегистрируйте обработчики в
|
|
83
|
+
`@core/data` под этими именами:
|
|
84
|
+
|
|
85
|
+
| Провайдер | Параметры | Результат |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| `notifications.doocot.list` | `{ page: number }` | Ответ списка |
|
|
88
|
+
| `notifications.doocot.counts` | нет | Ответ счётчиков |
|
|
89
|
+
| `notifications.doocot.details` | `{ messageId: string, signal?: AbortSignal }` | Ответ деталей |
|
|
90
|
+
|
|
91
|
+
Пример обработчиков для хоста (замените URL на адреса своего API), которые
|
|
92
|
+
затем нужно зарегистрировать в `@core/data`:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { NOTIFICATION_PROVIDERS } from "omninotice-notification-feed";
|
|
96
|
+
|
|
97
|
+
async function getJson(url: string, signal?: AbortSignal) {
|
|
98
|
+
const response = await fetch(url, { signal });
|
|
99
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
100
|
+
return response.json();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const notificationProviders = {
|
|
104
|
+
[NOTIFICATION_PROVIDERS.list]: ({ page }: { page: number }) =>
|
|
105
|
+
getJson(`/my/chits?page=${page}`),
|
|
106
|
+
[NOTIFICATION_PROVIDERS.counts]: () =>
|
|
107
|
+
getJson("/my/chits/status"),
|
|
108
|
+
[NOTIFICATION_PROVIDERS.details]: ({
|
|
109
|
+
messageId,
|
|
110
|
+
signal,
|
|
111
|
+
}: {
|
|
112
|
+
messageId: string;
|
|
113
|
+
signal?: AbortSignal;
|
|
114
|
+
}) =>
|
|
115
|
+
getJson(
|
|
116
|
+
`/my/chit/${encodeURIComponent(messageId)}`,
|
|
117
|
+
signal,
|
|
118
|
+
),
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Каждый обработчик должен вернуть JSON-ответ в формате ниже. Если в приложении
|
|
123
|
+
уже есть API-клиент, используйте его вместо `fetch`.
|
|
124
|
+
|
|
125
|
+
Провайдер деталей должен передавать `signal` в сетевой запрос, например
|
|
126
|
+
`fetch(url, { signal })`: при закрытии панели запрос отменяется.
|
|
127
|
+
|
|
128
|
+
Все ответы имеют вид `{ detail, data, info }`. `data` — массив:
|
|
129
|
+
|
|
130
|
+
- список: элементы с `status`, `created_date`, `modified_date`, `is_read` и
|
|
131
|
+
`chit` (`message_id`, `message_type`, `title`, `description`, `picture`,
|
|
132
|
+
`action`);
|
|
133
|
+
- счётчики: первый элемент — `{ total_count, unread_count }`;
|
|
134
|
+
- детали: элемент списка с дополнительными `chit.text`, `chit.action` и
|
|
135
|
+
`chit.extra`.
|
|
136
|
+
|
|
137
|
+
`info` содержит `api_version`, `count`, `total`, `page`, `page_size`.
|
|
138
|
+
Пустая страница завершает загрузку. Если стандартная пагинация по
|
|
139
|
+
`total_count` не подходит, передайте `getHasMore(info, loadedCount)` в
|
|
140
|
+
`NotificationsFeedProvider`.
|
|
141
|
+
|
|
142
|
+
После успешной загрузки деталей непрочитанного уведомления и при нажатии на
|
|
143
|
+
действие карточки пакет вызывает `runAction({ type: "mark-read", id })`, где
|
|
144
|
+
`id` — `messageId`. Зарегистрируйте обработчик этого действия в `@core/actions`:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
async function markRead({ id }: { id: string }) {
|
|
148
|
+
const response = await fetch(
|
|
149
|
+
`/my/${encodeURIComponent(id)}/read`,
|
|
150
|
+
{
|
|
151
|
+
method: "PATCH",
|
|
152
|
+
headers: { "Content-Type": "application/json" },
|
|
153
|
+
body: JSON.stringify({ chit_id: id }),
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`id` передаётся как `chit_id` в URL и JSON-теле запроса. Подключите функцию к
|
|
161
|
+
действию `mark-read` в конфигурации `@core/actions`. При ошибке пакет показывает
|
|
162
|
+
сообщение, а локально отмечает уведомление прочитанным только после успеха.
|
|
163
|
+
|
|
164
|
+
## Настройки
|
|
165
|
+
|
|
166
|
+
Передайте настройки в `NotificationsFeedProvider`:
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<NotificationsFeedProvider
|
|
170
|
+
settings={{
|
|
171
|
+
pageTitle: "Уведомления",
|
|
172
|
+
pageSubtitle: "Новости и задачи",
|
|
173
|
+
autoLoadUnread: true,
|
|
174
|
+
sidebarBackdrop: true,
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
<NotificationFeedPage header={<MyHeader />} />
|
|
178
|
+
</NotificationsFeedProvider>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
| Настройка | По умолчанию | Назначение |
|
|
182
|
+
| --- | --- | --- |
|
|
183
|
+
| `pageTitle` | `Уведомления` | Заголовок |
|
|
184
|
+
| `pageSubtitle` | описание ленты | Подзаголовок |
|
|
185
|
+
| `autoLoadUnread` | `true` | Загружать страницы, пока не найдутся непрочитанные |
|
|
186
|
+
| `sidebarBackdrop` | `true` | Затемнение за панелью деталей |
|
|
187
|
+
| `defaultIcon` | иконка уведомления | Иконка без изображения |
|
|
188
|
+
| `notificationState` | тексты пакета | Содержимое состояний `empty`, `error`, `allRead`, `noUnreadLoaded` |
|
|
189
|
+
|
|
190
|
+
Для `notificationState` можно переопределить `title`, `description`, `btn`
|
|
191
|
+
(`title`, `onClick`), `className` и `icon`. Настройки объединяются с
|
|
192
|
+
значениями по умолчанию. `defaultIcon` и `notificationState` доступны при
|
|
193
|
+
прямом использовании `NotificationsFeedProvider`; в `SlotComponentProps.settings`
|
|
194
|
+
поддерживаются только первые четыре настройки таблицы.
|
|
195
|
+
|
|
196
|
+
`NotificationFeedPage` принимает необязательный `header` — React-узел перед
|
|
197
|
+
заголовком страницы.
|
|
198
|
+
|
|
199
|
+
## API пакета
|
|
200
|
+
|
|
201
|
+
Из корневого импорта экспортируются `NotificationsFeedProvider`,
|
|
202
|
+
`NotificationFeedPage`, `SettingsOverrides`, `GetHasMore`, `NOTIFICATION_PROVIDERS`,
|
|
203
|
+
типы ответов и уведомлений (`NotificationsResponse`, `Notification`,
|
|
204
|
+
`NotificationCountsResponse`, `NotificationDetailsResponse`) и соответствующие
|
|
205
|
+
схемы (`NotificationsResponseSchema`, `NotificationCountsResponseSchema`,
|
|
206
|
+
`NotificationDetailsResponseSchema` и схемы элементов). Детали показывают
|
|
207
|
+
`chit.text`, а при его отсутствии — `chit.description`; `chit.action`
|
|
208
|
+
отображается как ссылка.
|
|
209
|
+
|
|
210
|
+
## CSS-токены
|
|
211
|
+
|
|
212
|
+
Токены пакета из `NotificationFeedPage.module.css`:
|
|
213
|
+
|
|
214
|
+
```css
|
|
215
|
+
--omni-main-bg: var(--color-surface, #f5f6f9); /* фон страницы */
|
|
216
|
+
--omni-primary: var(--color-primary, #487bfe); /* основной цвет */
|
|
217
|
+
--omni-primary-hover: var(
|
|
218
|
+
--color-primary-hover,
|
|
219
|
+
hsl(from var(--omni-primary) h s calc(l - 10))
|
|
220
|
+
); /* цвет при наведении */
|
|
221
|
+
--omni-primary-text: var(--color-text-primary, #0c151d); /* основной текст */
|
|
222
|
+
--omni-secondary-text: var(--color-text-secondary, #767a7f); /* вторичный текст */
|
|
223
|
+
--omni-breadcumbs-icon-color: var(--color-icon, #4a5665); /* цвет иконки */
|
|
224
|
+
--omni-sidebar-box-shadow: var(
|
|
225
|
+
--color-shadow,
|
|
226
|
+
0px 0px 1px 0px #00000066,
|
|
227
|
+
-8px 8px 24px -8px #00000029
|
|
228
|
+
); /* тень панели */
|
|
229
|
+
--omni-state-box-shadow: var(--color-shadow, 0px 0px 1px #0000004D); /* тень состояния */
|
|
230
|
+
--omni-nf-bg: var(--color-surface, #ffffff); /* фон карточки */
|
|
231
|
+
--omni-nf-bg-hover: var(
|
|
232
|
+
--color-bg-hover,
|
|
233
|
+
color-mix(in srgb, var(--omni-primary) 12%, white)
|
|
234
|
+
); /* фон при наведении */
|
|
235
|
+
--omni-nf-icon: var(--omni-primary); /* цвет иконки уведомления */
|
|
236
|
+
--omni-nf-icon-error: var(--color-danger, #e65443); /* цвет иконки ошибки */
|
|
237
|
+
--omni-nf-icon-bg: var(
|
|
238
|
+
--color-primary-soft,
|
|
239
|
+
color-mix(in srgb, var(--omni-nf-icon) 25%, white)
|
|
240
|
+
); /* фон иконки уведомления */
|
|
241
|
+
--omni-nf-icon-bg-error: var(
|
|
242
|
+
--color-danger-soft,
|
|
243
|
+
color-mix(in srgb, var(--omni-nf-icon-error) 25%, white)
|
|
244
|
+
); /* фон иконки ошибки */
|
|
245
|
+
--omni-border-color: var(--color-border, #eceef4); /* цвет границы */
|
|
246
|
+
--omni-border-hover: var(--color-text-primary, #0c151d); /* граница при наведении */
|
|
247
|
+
--omni-radius: var(--radius-md, 8px); /* радиус скругления */
|
|
248
|
+
--omni-container-padding-inline: 24px 20px; /* отступы контейнера */
|
|
249
|
+
--omni-nf-icon-container-size: 56px; /* размер контейнера иконки */
|
|
250
|
+
--omni-nf-icon-chevron-size: 24px; /* размер шеврона */
|
|
251
|
+
--omni-tabs-margin-block: 32px; /* отступ вкладок */
|
|
252
|
+
--omni-transition: 0.15s ease-in; /* скорость перехода */
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
В состоянии ошибки `NotificationsState.module.css` переопределяет:
|
|
256
|
+
|
|
257
|
+
```css
|
|
258
|
+
--omni-nf-icon: var(--omni-nf-icon-error); /* цвет иконки ошибки */
|
|
259
|
+
--omni-nf-icon-bg: var(--omni-nf-icon-bg-error); /* фон иконки ошибки */
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Стили компонентов изолированы CSS Modules.
|
|
263
|
+
|
|
264
|
+
## Локальный просмотр
|
|
265
|
+
|
|
266
|
+
`npm run dev` запускает превью с моками из `public/mock`. Создайте их командой
|
|
267
|
+
`npm run generate:mock`; после клонирования её нужно выполнить один раз.
|