@ion299/sdk-react-native 0.1.0-beta.1
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/CHANGELOG.md +17 -0
- package/ChatPlatformSdk.podspec +20 -0
- package/README.md +315 -0
- package/android/build.gradle +54 -0
- package/android/src/main/AndroidManifest.xml +18 -0
- package/android/src/main/java/com/chatplatform/sdk/ChatSdkDownloaderModule.kt +240 -0
- package/android/src/main/java/com/chatplatform/sdk/ChatSdkFilePickerModule.kt +165 -0
- package/android/src/main/java/com/chatplatform/sdk/ChatSdkPackage.kt +15 -0
- package/android/src/main/res/xml/chat_sdk_file_paths.xml +7 -0
- package/ios/ChatSdkDownloader.m +10 -0
- package/ios/ChatSdkDownloader.swift +141 -0
- package/ios/ChatSdkFilePicker.m +9 -0
- package/ios/ChatSdkFilePicker.swift +161 -0
- package/lib/commonjs/ChatSDK.js +193 -0
- package/lib/commonjs/ChatSDK.js.map +1 -0
- package/lib/commonjs/api.js +195 -0
- package/lib/commonjs/api.js.map +1 -0
- package/lib/commonjs/attachmentUtils.js +39 -0
- package/lib/commonjs/attachmentUtils.js.map +1 -0
- package/lib/commonjs/components/AttachmentGallery.js +367 -0
- package/lib/commonjs/components/AttachmentGallery.js.map +1 -0
- package/lib/commonjs/components/ChatScreen.js +286 -0
- package/lib/commonjs/components/ChatScreen.js.map +1 -0
- package/lib/commonjs/components/MessageBubble.js +227 -0
- package/lib/commonjs/components/MessageBubble.js.map +1 -0
- package/lib/commonjs/components/MessageInput.js +273 -0
- package/lib/commonjs/components/MessageInput.js.map +1 -0
- package/lib/commonjs/components/SurveyOverlay.js +499 -0
- package/lib/commonjs/components/SurveyOverlay.js.map +1 -0
- package/lib/commonjs/downloaders/defaultAttachmentDownloader.js +28 -0
- package/lib/commonjs/downloaders/defaultAttachmentDownloader.js.map +1 -0
- package/lib/commonjs/filePicker.js +25 -0
- package/lib/commonjs/filePicker.js.map +1 -0
- package/lib/commonjs/index.js +27 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/native/NativeChatSdkDownloader.js +28 -0
- package/lib/commonjs/native/NativeChatSdkDownloader.js.map +1 -0
- package/lib/commonjs/native/NativeChatSdkFilePicker.js +17 -0
- package/lib/commonjs/native/NativeChatSdkFilePicker.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/realtime.js +242 -0
- package/lib/commonjs/realtime.js.map +1 -0
- package/lib/commonjs/safeArea.js +18 -0
- package/lib/commonjs/safeArea.js.map +1 -0
- package/lib/commonjs/session.js +159 -0
- package/lib/commonjs/session.js.map +1 -0
- package/lib/commonjs/surveyCache.js +30 -0
- package/lib/commonjs/surveyCache.js.map +1 -0
- package/lib/commonjs/theme.js +29 -0
- package/lib/commonjs/theme.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/useChat.js +145 -0
- package/lib/commonjs/useChat.js.map +1 -0
- package/lib/module/ChatSDK.js +189 -0
- package/lib/module/ChatSDK.js.map +1 -0
- package/lib/module/api.js +190 -0
- package/lib/module/api.js.map +1 -0
- package/lib/module/attachmentUtils.js +33 -0
- package/lib/module/attachmentUtils.js.map +1 -0
- package/lib/module/components/AttachmentGallery.js +362 -0
- package/lib/module/components/AttachmentGallery.js.map +1 -0
- package/lib/module/components/ChatScreen.js +281 -0
- package/lib/module/components/ChatScreen.js.map +1 -0
- package/lib/module/components/MessageBubble.js +222 -0
- package/lib/module/components/MessageBubble.js.map +1 -0
- package/lib/module/components/MessageInput.js +268 -0
- package/lib/module/components/MessageInput.js.map +1 -0
- package/lib/module/components/SurveyOverlay.js +494 -0
- package/lib/module/components/SurveyOverlay.js.map +1 -0
- package/lib/module/downloaders/defaultAttachmentDownloader.js +22 -0
- package/lib/module/downloaders/defaultAttachmentDownloader.js.map +1 -0
- package/lib/module/filePicker.js +20 -0
- package/lib/module/filePicker.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/NativeChatSdkDownloader.js +23 -0
- package/lib/module/native/NativeChatSdkDownloader.js.map +1 -0
- package/lib/module/native/NativeChatSdkFilePicker.js +13 -0
- package/lib/module/native/NativeChatSdkFilePicker.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/realtime.js +236 -0
- package/lib/module/realtime.js.map +1 -0
- package/lib/module/safeArea.js +14 -0
- package/lib/module/safeArea.js.map +1 -0
- package/lib/module/session.js +154 -0
- package/lib/module/session.js.map +1 -0
- package/lib/module/surveyCache.js +23 -0
- package/lib/module/surveyCache.js.map +1 -0
- package/lib/module/theme.js +25 -0
- package/lib/module/theme.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/useChat.js +141 -0
- package/lib/module/useChat.js.map +1 -0
- package/lib/typescript/commonjs/ChatSDK.d.ts +49 -0
- package/lib/typescript/commonjs/ChatSDK.d.ts.map +1 -0
- package/lib/typescript/commonjs/api.d.ts +31 -0
- package/lib/typescript/commonjs/api.d.ts.map +1 -0
- package/lib/typescript/commonjs/attachmentUtils.d.ts +12 -0
- package/lib/typescript/commonjs/attachmentUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/AttachmentGallery.d.ts +16 -0
- package/lib/typescript/commonjs/components/AttachmentGallery.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/ChatScreen.d.ts +16 -0
- package/lib/typescript/commonjs/components/ChatScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/MessageBubble.d.ts +12 -0
- package/lib/typescript/commonjs/components/MessageBubble.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/MessageInput.d.ts +14 -0
- package/lib/typescript/commonjs/components/MessageInput.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/SurveyOverlay.d.ts +13 -0
- package/lib/typescript/commonjs/components/SurveyOverlay.d.ts.map +1 -0
- package/lib/typescript/commonjs/downloaders/defaultAttachmentDownloader.d.ts +3 -0
- package/lib/typescript/commonjs/downloaders/defaultAttachmentDownloader.d.ts.map +1 -0
- package/lib/typescript/commonjs/filePicker.d.ts +4 -0
- package/lib/typescript/commonjs/filePicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +7 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/NativeChatSdkDownloader.d.ts +24 -0
- package/lib/typescript/commonjs/native/NativeChatSdkDownloader.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/NativeChatSdkFilePicker.d.ts +17 -0
- package/lib/typescript/commonjs/native/NativeChatSdkFilePicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/realtime.d.ts +42 -0
- package/lib/typescript/commonjs/realtime.d.ts.map +1 -0
- package/lib/typescript/commonjs/safeArea.d.ts +4 -0
- package/lib/typescript/commonjs/safeArea.d.ts.map +1 -0
- package/lib/typescript/commonjs/session.d.ts +45 -0
- package/lib/typescript/commonjs/session.d.ts.map +1 -0
- package/lib/typescript/commonjs/surveyCache.d.ts +5 -0
- package/lib/typescript/commonjs/surveyCache.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme.d.ts +21 -0
- package/lib/typescript/commonjs/theme.d.ts.map +1 -0
- package/lib/typescript/commonjs/types.d.ts +156 -0
- package/lib/typescript/commonjs/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/useChat.d.ts +16 -0
- package/lib/typescript/commonjs/useChat.d.ts.map +1 -0
- package/lib/typescript/module/ChatSDK.d.ts +49 -0
- package/lib/typescript/module/ChatSDK.d.ts.map +1 -0
- package/lib/typescript/module/api.d.ts +31 -0
- package/lib/typescript/module/api.d.ts.map +1 -0
- package/lib/typescript/module/attachmentUtils.d.ts +12 -0
- package/lib/typescript/module/attachmentUtils.d.ts.map +1 -0
- package/lib/typescript/module/components/AttachmentGallery.d.ts +16 -0
- package/lib/typescript/module/components/AttachmentGallery.d.ts.map +1 -0
- package/lib/typescript/module/components/ChatScreen.d.ts +16 -0
- package/lib/typescript/module/components/ChatScreen.d.ts.map +1 -0
- package/lib/typescript/module/components/MessageBubble.d.ts +12 -0
- package/lib/typescript/module/components/MessageBubble.d.ts.map +1 -0
- package/lib/typescript/module/components/MessageInput.d.ts +14 -0
- package/lib/typescript/module/components/MessageInput.d.ts.map +1 -0
- package/lib/typescript/module/components/SurveyOverlay.d.ts +13 -0
- package/lib/typescript/module/components/SurveyOverlay.d.ts.map +1 -0
- package/lib/typescript/module/downloaders/defaultAttachmentDownloader.d.ts +3 -0
- package/lib/typescript/module/downloaders/defaultAttachmentDownloader.d.ts.map +1 -0
- package/lib/typescript/module/filePicker.d.ts +4 -0
- package/lib/typescript/module/filePicker.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +7 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/native/NativeChatSdkDownloader.d.ts +24 -0
- package/lib/typescript/module/native/NativeChatSdkDownloader.d.ts.map +1 -0
- package/lib/typescript/module/native/NativeChatSdkFilePicker.d.ts +17 -0
- package/lib/typescript/module/native/NativeChatSdkFilePicker.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/realtime.d.ts +42 -0
- package/lib/typescript/module/realtime.d.ts.map +1 -0
- package/lib/typescript/module/safeArea.d.ts +4 -0
- package/lib/typescript/module/safeArea.d.ts.map +1 -0
- package/lib/typescript/module/session.d.ts +45 -0
- package/lib/typescript/module/session.d.ts.map +1 -0
- package/lib/typescript/module/surveyCache.d.ts +5 -0
- package/lib/typescript/module/surveyCache.d.ts.map +1 -0
- package/lib/typescript/module/theme.d.ts +21 -0
- package/lib/typescript/module/theme.d.ts.map +1 -0
- package/lib/typescript/module/types.d.ts +156 -0
- package/lib/typescript/module/types.d.ts.map +1 -0
- package/lib/typescript/module/useChat.d.ts +16 -0
- package/lib/typescript/module/useChat.d.ts.map +1 -0
- package/package.json +75 -0
- package/react-native.config.js +10 -0
- package/src/ChatSDK.ts +237 -0
- package/src/api.ts +228 -0
- package/src/attachmentUtils.ts +49 -0
- package/src/components/AttachmentGallery.tsx +363 -0
- package/src/components/ChatScreen.tsx +267 -0
- package/src/components/MessageBubble.tsx +208 -0
- package/src/components/MessageInput.tsx +280 -0
- package/src/components/SurveyOverlay.tsx +469 -0
- package/src/downloaders/defaultAttachmentDownloader.ts +27 -0
- package/src/filePicker.ts +22 -0
- package/src/index.ts +30 -0
- package/src/native/NativeChatSdkDownloader.ts +49 -0
- package/src/native/NativeChatSdkFilePicker.ts +30 -0
- package/src/realtime.ts +278 -0
- package/src/safeArea.ts +8 -0
- package/src/session.ts +196 -0
- package/src/surveyCache.ts +24 -0
- package/src/theme.ts +49 -0
- package/src/types.ts +199 -0
- package/src/useChat.ts +190 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// Конфигурация при инициализации SDK.
|
|
2
|
+
// token может быть либо plain-строкой (тогда baseUrl обязателен),
|
|
3
|
+
// либо base64-закодированным JSON вида {"token":"...","baseUrl":"..."}.
|
|
4
|
+
export interface ChatSDKConfig {
|
|
5
|
+
token: string
|
|
6
|
+
baseUrl?: string
|
|
7
|
+
locale?: 'ru' | 'en'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Данные пользователя при логине
|
|
11
|
+
export interface ChatSDKUser {
|
|
12
|
+
userId: string
|
|
13
|
+
name?: string
|
|
14
|
+
surname?: string
|
|
15
|
+
email?: string
|
|
16
|
+
phone?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Данные устройства (опционально)
|
|
20
|
+
export interface ChatSDKDevice {
|
|
21
|
+
platform?: 'ios' | 'android' | 'other'
|
|
22
|
+
appVersion?: string
|
|
23
|
+
bundleId?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Тема виджета из ЧП
|
|
27
|
+
export interface ChatSDKTheme {
|
|
28
|
+
widgetTitle: string
|
|
29
|
+
colorType: 'single' | 'gradient'
|
|
30
|
+
themeColor: string
|
|
31
|
+
colorStart: string | null
|
|
32
|
+
colorEnd: string | null
|
|
33
|
+
imageLogo: string | null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Параметры Reverb из ответа /session
|
|
37
|
+
export interface ReverbConfig {
|
|
38
|
+
key: string
|
|
39
|
+
host: string
|
|
40
|
+
port: number
|
|
41
|
+
scheme: 'http' | 'https'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Полный конфиг из /session или /config
|
|
45
|
+
export interface MobileConfig extends ChatSDKTheme {
|
|
46
|
+
apiBaseUrl: string
|
|
47
|
+
reverb: ReverbConfig
|
|
48
|
+
broadcastAuthEndpoint: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Ответ POST /session
|
|
52
|
+
export interface SessionResponse {
|
|
53
|
+
sessionToken: string
|
|
54
|
+
expiresAt: string
|
|
55
|
+
contactId: string
|
|
56
|
+
config: MobileConfig
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Одно сообщение в чате
|
|
60
|
+
export interface ChatMessage {
|
|
61
|
+
id: string
|
|
62
|
+
type: 'contact' | 'user' | 'system' | 'event'
|
|
63
|
+
text: string | null
|
|
64
|
+
time: string
|
|
65
|
+
createdAt: number
|
|
66
|
+
sender?: { name: string } | null
|
|
67
|
+
attachments?: ChatAttachment[]
|
|
68
|
+
buttons?: ChatButton[] | null
|
|
69
|
+
serverMessageId?: number | null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Вложение
|
|
73
|
+
export interface ChatAttachment {
|
|
74
|
+
id: number
|
|
75
|
+
url: string
|
|
76
|
+
filename: string
|
|
77
|
+
mime: string
|
|
78
|
+
size: number
|
|
79
|
+
type: 'image' | 'video' | 'audio' | 'document'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Файл для отправки из SDK (используется хост-приложением)
|
|
83
|
+
export interface AttachmentInput {
|
|
84
|
+
uri: string
|
|
85
|
+
name: string
|
|
86
|
+
type: string
|
|
87
|
+
size?: number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Вложение с контекстом сообщения (для галереи)
|
|
91
|
+
export interface GalleryAttachment extends ChatAttachment {
|
|
92
|
+
messageTime: string
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Кнопка бота
|
|
96
|
+
export interface ChatButton {
|
|
97
|
+
text: string
|
|
98
|
+
callback_data: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Ответ GET /messages
|
|
102
|
+
export interface MessagesResponse {
|
|
103
|
+
operator: { id: number; name: string } | null
|
|
104
|
+
messages: ChatMessage[]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface ChatOperator {
|
|
108
|
+
id: number
|
|
109
|
+
name: string
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Payload для handleNotification (из push)
|
|
113
|
+
export interface NotificationPayload {
|
|
114
|
+
token: string
|
|
115
|
+
contactId: string
|
|
116
|
+
conversationId?: string
|
|
117
|
+
messageId?: string
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface OperatorChangedEventPayload {
|
|
121
|
+
token: string
|
|
122
|
+
contactId: string
|
|
123
|
+
previousOperator: ChatOperator | null
|
|
124
|
+
operator: ChatOperator | null
|
|
125
|
+
occurredAt: string
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface NewMessageEventPayload {
|
|
129
|
+
token: string
|
|
130
|
+
contactId: string
|
|
131
|
+
message: ChatMessage
|
|
132
|
+
operator: ChatOperator | null
|
|
133
|
+
occurredAt: string
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface MessagesUpdatedEventPayload {
|
|
137
|
+
messages: ChatMessage[]
|
|
138
|
+
operator: ChatOperator | null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type ChatSDKEventName =
|
|
142
|
+
| 'stateChange'
|
|
143
|
+
| 'error'
|
|
144
|
+
| 'operatorChanged'
|
|
145
|
+
| 'newMessage'
|
|
146
|
+
| 'messagesUpdated'
|
|
147
|
+
| 'connectedChange'
|
|
148
|
+
|
|
149
|
+
// Конфиг CSI-опроса с сервера
|
|
150
|
+
export interface SurveyConfig {
|
|
151
|
+
visible: true
|
|
152
|
+
title: string
|
|
153
|
+
description: string
|
|
154
|
+
range: [number, number]
|
|
155
|
+
badRange: [number, number]
|
|
156
|
+
badMessage: string
|
|
157
|
+
goodMessage: string
|
|
158
|
+
afterCommentMessage: string
|
|
159
|
+
commentEnabled: boolean
|
|
160
|
+
badRangeEnabled: boolean
|
|
161
|
+
commentRequired: boolean
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type SurveyConfigResponse = SurveyConfig | { visible: false }
|
|
165
|
+
|
|
166
|
+
// Внутреннее состояние SDK
|
|
167
|
+
export type SDKState =
|
|
168
|
+
| 'idle'
|
|
169
|
+
| 'initializing'
|
|
170
|
+
| 'ready'
|
|
171
|
+
| 'authenticated'
|
|
172
|
+
| 'error'
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Кастомные тексты для <ChatScreen />.
|
|
176
|
+
* Все поля опциональны — непереданные значения берутся из встроенного дефолта.
|
|
177
|
+
*/
|
|
178
|
+
export interface ChatStrings {
|
|
179
|
+
/** Заголовок хедера. По умолчанию: widgetTitle из конфига → 'Чат' */
|
|
180
|
+
headerTitle?: string
|
|
181
|
+
/** Текст пустого экрана чата */
|
|
182
|
+
emptyStateText?: string
|
|
183
|
+
/** Placeholder в поле ввода */
|
|
184
|
+
inputPlaceholder?: string
|
|
185
|
+
/** Текст кнопки/индикатора отправки */
|
|
186
|
+
sendingText?: string
|
|
187
|
+
/** Текст кнопки повтора при ошибке */
|
|
188
|
+
errorRetry?: string
|
|
189
|
+
/** Заголовок оверлея CSI-опроса (если не задан сервером) */
|
|
190
|
+
surveyTitle?: string
|
|
191
|
+
/** Текст кнопки отправки оценки в опросе */
|
|
192
|
+
surveySubmit?: string
|
|
193
|
+
/** Текст кнопки пропуска опроса */
|
|
194
|
+
surveySkip?: string
|
|
195
|
+
/** Текст кнопки закрытия результата опроса */
|
|
196
|
+
surveyClose?: string
|
|
197
|
+
/** Текст кнопки скачивания в галерее */
|
|
198
|
+
galleryDownload?: string
|
|
199
|
+
}
|
package/src/useChat.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
|
+
import { ChatSDK } from './ChatSDK'
|
|
3
|
+
import { isSurveyEventSeen, markSurveyEventSeen, deleteSurveyEvent } from './surveyCache'
|
|
4
|
+
import type {
|
|
5
|
+
AttachmentInput,
|
|
6
|
+
ChatAttachment,
|
|
7
|
+
ChatMessage,
|
|
8
|
+
SurveyConfig,
|
|
9
|
+
} from './types'
|
|
10
|
+
|
|
11
|
+
export interface UseChatReturn {
|
|
12
|
+
messages: ChatMessage[]
|
|
13
|
+
isLoading: boolean
|
|
14
|
+
isSending: boolean
|
|
15
|
+
connected: boolean
|
|
16
|
+
error: string | null
|
|
17
|
+
survey: SurveyConfig | null
|
|
18
|
+
sendMessage: (text: string, files?: AttachmentInput[]) => Promise<void>
|
|
19
|
+
sendCallback: (messageId: number, callbackData: string) => Promise<void>
|
|
20
|
+
submitSurvey: (rating: number, comment?: string) => Promise<void>
|
|
21
|
+
dismissSurvey: () => void
|
|
22
|
+
retry: () => void
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function filterVisible(all: ChatMessage[]): ChatMessage[] {
|
|
26
|
+
return all.filter((m) => !(m.type === 'event' && m.text === 'status_changed'))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function useChat(): UseChatReturn {
|
|
30
|
+
const [messages, setMessages] = useState<ChatMessage[]>(() => filterVisible(ChatSDK.getMessages()))
|
|
31
|
+
const [isLoading, setIsLoading] = useState(ChatSDK.getMessages().length === 0)
|
|
32
|
+
const [isSending, setIsSending] = useState(false)
|
|
33
|
+
const [connected, setConnected] = useState(ChatSDK.isRealtimeConnected())
|
|
34
|
+
const [error, setError] = useState<string | null>(null)
|
|
35
|
+
const [survey, setSurvey] = useState<SurveyConfig | null>(null)
|
|
36
|
+
|
|
37
|
+
const api = ChatSDK.getApi()
|
|
38
|
+
const lastCloseEventRef = useRef<string | null>(null)
|
|
39
|
+
|
|
40
|
+
const checkSurvey = useCallback(
|
|
41
|
+
async (eventMessageId: string, closeEventCreatedAt?: number) => {
|
|
42
|
+
const contactId = api.getContactId()
|
|
43
|
+
if (!contactId) return
|
|
44
|
+
if (isSurveyEventSeen(contactId, eventMessageId)) return
|
|
45
|
+
|
|
46
|
+
markSurveyEventSeen(contactId, eventMessageId)
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const cfg = await api.getSurveyConfig(closeEventCreatedAt)
|
|
50
|
+
if (cfg.visible) {
|
|
51
|
+
setSurvey(cfg as SurveyConfig)
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
deleteSurveyEvent(contactId, eventMessageId)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
[api],
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const unsubMessages = ChatSDK.on('messagesUpdated', ({ messages: all }) => {
|
|
62
|
+
setMessages(filterVisible(all))
|
|
63
|
+
setIsLoading(false)
|
|
64
|
+
setError(null)
|
|
65
|
+
|
|
66
|
+
const closeEvent = all.findLast(
|
|
67
|
+
(m) => m.type === 'event' && m.text === 'status_changed',
|
|
68
|
+
)
|
|
69
|
+
if (closeEvent && closeEvent.id !== lastCloseEventRef.current) {
|
|
70
|
+
lastCloseEventRef.current = closeEvent.id
|
|
71
|
+
void checkSurvey(closeEvent.id, closeEvent.createdAt)
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const unsubConnected = ChatSDK.on('connectedChange', (value) => setConnected(value))
|
|
76
|
+
|
|
77
|
+
return () => {
|
|
78
|
+
unsubMessages()
|
|
79
|
+
unsubConnected()
|
|
80
|
+
}
|
|
81
|
+
}, [checkSurvey])
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
void (async () => {
|
|
85
|
+
try {
|
|
86
|
+
const user = ChatSDK.getUser()
|
|
87
|
+
await api.startDialog({
|
|
88
|
+
name: user?.name,
|
|
89
|
+
surname: user?.surname,
|
|
90
|
+
email: user?.email,
|
|
91
|
+
phone: user?.phone,
|
|
92
|
+
})
|
|
93
|
+
} catch (e) {
|
|
94
|
+
console.warn('ChatSDK: startDialog failed (non-fatal):', e)
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
await ChatSDK.refreshMessages()
|
|
98
|
+
} catch (e) {
|
|
99
|
+
setError(e instanceof Error ? e.message : 'Ошибка загрузки')
|
|
100
|
+
setIsLoading(false)
|
|
101
|
+
}
|
|
102
|
+
})()
|
|
103
|
+
}, [api])
|
|
104
|
+
|
|
105
|
+
const sendMessage = useCallback(
|
|
106
|
+
async (text: string, files?: AttachmentInput[]) => {
|
|
107
|
+
if (!text.trim() && (!files || files.length === 0)) return
|
|
108
|
+
setIsSending(true)
|
|
109
|
+
setError(null)
|
|
110
|
+
|
|
111
|
+
const tempId = `temp-${Date.now()}`
|
|
112
|
+
const tempAttachments: ChatAttachment[] = (files ?? []).map((f, i) => ({
|
|
113
|
+
id: -(i + 1),
|
|
114
|
+
url: f.uri,
|
|
115
|
+
filename: f.name,
|
|
116
|
+
mime: f.type,
|
|
117
|
+
size: f.size ?? 0,
|
|
118
|
+
type: f.type.startsWith('image/') ? 'image'
|
|
119
|
+
: f.type.startsWith('video/') ? 'video'
|
|
120
|
+
: f.type.startsWith('audio/') ? 'audio'
|
|
121
|
+
: 'document',
|
|
122
|
+
}))
|
|
123
|
+
|
|
124
|
+
const tempMsg: ChatMessage = {
|
|
125
|
+
id: tempId,
|
|
126
|
+
type: 'contact',
|
|
127
|
+
text: text.trim() || null,
|
|
128
|
+
time: new Date().toLocaleTimeString('ru', { hour: '2-digit', minute: '2-digit' }),
|
|
129
|
+
createdAt: Date.now(),
|
|
130
|
+
attachments: tempAttachments,
|
|
131
|
+
}
|
|
132
|
+
setMessages((prev) => [...prev, tempMsg])
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
await api.sendMessage(text, files)
|
|
136
|
+
await ChatSDK.refreshMessages()
|
|
137
|
+
} catch (e) {
|
|
138
|
+
setError(e instanceof Error ? e.message : 'Ошибка отправки')
|
|
139
|
+
setMessages((prev) => prev.filter((m) => m.id !== tempId))
|
|
140
|
+
} finally {
|
|
141
|
+
setIsSending(false)
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
[api],
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
const sendCallback = useCallback(
|
|
148
|
+
async (messageId: number, callbackData: string) => {
|
|
149
|
+
try {
|
|
150
|
+
await api.sendCallback(messageId, callbackData)
|
|
151
|
+
await ChatSDK.refreshMessages()
|
|
152
|
+
} catch (e) {
|
|
153
|
+
setError(e instanceof Error ? e.message : 'Ошибка отправки')
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
[api],
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
const submitSurvey = useCallback(
|
|
160
|
+
async (rating: number, comment?: string) => {
|
|
161
|
+
await api.submitCsi(rating, comment)
|
|
162
|
+
},
|
|
163
|
+
[api],
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
const dismissSurvey = useCallback(() => setSurvey(null), [])
|
|
167
|
+
|
|
168
|
+
const retry = useCallback(() => {
|
|
169
|
+
setIsLoading(true)
|
|
170
|
+
setError(null)
|
|
171
|
+
void ChatSDK.refreshMessages().catch((e) => {
|
|
172
|
+
setError(e instanceof Error ? e.message : 'Ошибка загрузки')
|
|
173
|
+
setIsLoading(false)
|
|
174
|
+
})
|
|
175
|
+
}, [])
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
messages,
|
|
179
|
+
isLoading,
|
|
180
|
+
isSending,
|
|
181
|
+
connected,
|
|
182
|
+
error,
|
|
183
|
+
survey,
|
|
184
|
+
sendMessage,
|
|
185
|
+
sendCallback,
|
|
186
|
+
submitSurvey,
|
|
187
|
+
dismissSurvey,
|
|
188
|
+
retry,
|
|
189
|
+
}
|
|
190
|
+
}
|