@aslaluroba/help-center-react 2.0.4 → 2.0.6
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/dist/core/api.d.ts +4 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.js +994 -25294
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +995 -25295
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/types.d.ts +4 -0
- package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +1 -0
- package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +1 -1
- package/dist/ui/help-center.d.ts +1 -1
- package/dist/ui/help-popup.d.ts +9 -3
- package/dist/ui/review-dialog/index.d.ts +8 -0
- package/dist/ui/review-dialog/rating.d.ts +12 -0
- package/package.json +26 -5
- package/src/assets/icons/arrowRight.svg +1 -1
- package/src/assets/icons/closeCircle.svg +1 -1
- package/src/components/ui/agent-response/agent-response.tsx +36 -34
- package/src/components/ui/header.tsx +2 -3
- package/src/core/SignalRService.ts +25 -25
- package/src/core/api.ts +180 -44
- package/src/globals.css +0 -9
- package/src/index.ts +3 -2
- package/src/lib/config.ts +25 -25
- package/src/lib/types.ts +5 -0
- package/src/locales/ar.json +18 -1
- package/src/locales/en.json +26 -8
- package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +31 -33
- package/src/ui/chatbot-popup/chat-window-screen/header.tsx +47 -53
- package/src/ui/chatbot-popup/chat-window-screen/index.tsx +182 -88
- package/src/ui/chatbot-popup/options-list-screen/header.tsx +24 -20
- package/src/ui/chatbot-popup/options-list-screen/index.tsx +24 -24
- package/src/ui/chatbot-popup/options-list-screen/option-card.tsx +9 -4
- package/src/ui/help-center.tsx +189 -159
- package/src/ui/help-popup.tsx +241 -165
- package/src/ui/review-dialog/index.tsx +106 -0
- package/src/ui/review-dialog/rating.tsx +78 -0
- package/tsconfig.json +48 -0
package/src/ui/help-center.tsx
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import '
|
|
1
|
+
import ReviewDialog from '@/ui/review-dialog';
|
|
2
|
+
import React, { useEffect, useState } from 'react';
|
|
3
|
+
import { apiRequest } from '../core/api';
|
|
4
|
+
import { ClientSignalRService } from '../core/SignalRService';
|
|
5
|
+
import { configService } from '../lib/config';
|
|
6
|
+
import { useLocalTranslation } from '../useLocalTranslation';
|
|
7
|
+
import '../globals.css';
|
|
8
|
+
import { HelpScreenData, Message, Option, ReviewProps } from '../lib/types';
|
|
9
|
+
import { FloatingMessage } from './floating-message';
|
|
10
|
+
import { HelpButton } from './help-button';
|
|
11
|
+
import { HelpPopup } from './help-popup';
|
|
11
12
|
|
|
12
13
|
interface HelpCenterProps {
|
|
13
|
-
helpScreenId: string
|
|
14
|
-
language: string
|
|
14
|
+
helpScreenId: string;
|
|
15
|
+
language: string;
|
|
15
16
|
user?: {
|
|
16
|
-
id?: string
|
|
17
|
-
name?: string
|
|
18
|
-
email?: string
|
|
19
|
-
avatar?: string
|
|
20
|
-
}
|
|
21
|
-
showArrow?: boolean
|
|
22
|
-
messageLabel?: string | null
|
|
23
|
-
showHelpScreen?: boolean
|
|
17
|
+
id?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
email?: string;
|
|
20
|
+
avatar?: string;
|
|
21
|
+
};
|
|
22
|
+
showArrow?: boolean;
|
|
23
|
+
messageLabel?: string | null;
|
|
24
|
+
showHelpScreen?: boolean;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export function HelpCenter({
|
|
@@ -29,93 +30,113 @@ export function HelpCenter({
|
|
|
29
30
|
showArrow = true,
|
|
30
31
|
language = 'en',
|
|
31
32
|
messageLabel = null,
|
|
32
|
-
showHelpScreen = false
|
|
33
|
+
showHelpScreen = false,
|
|
33
34
|
}: HelpCenterProps) {
|
|
34
|
-
const { t } = useLocalTranslation(language)
|
|
35
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
36
|
-
const [showArrowAnimation, setShowArrowAnimation] = useState(showArrow)
|
|
37
|
-
const [helpScreenData, setHelpScreenData] = useState<HelpScreenData | null>(null)
|
|
38
|
-
const [status, setStatus] = useState('idle')
|
|
39
|
-
const [error, setError] = useState('')
|
|
40
|
-
const [selectedOption, setSelectedOption] = useState<Option | null>(null)
|
|
41
|
-
|
|
42
|
-
const [sessionId, setSessionId] = useState<string | null>(null)
|
|
43
|
-
const [isSignalRConnected, setIsSignalRConnected] = useState(false)
|
|
44
|
-
const [isChatClosed, setIsChatClosed] = useState(false)
|
|
45
|
-
const [messages, setMessages] = useState<Message[]>([])
|
|
46
|
-
const [needsAgent, setNeedsAgent] = useState(false)
|
|
47
|
-
const [assistantStatus, setAssistantStatus] = useState('idle')
|
|
35
|
+
const { t } = useLocalTranslation(language);
|
|
36
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
37
|
+
const [showArrowAnimation, setShowArrowAnimation] = useState(showArrow);
|
|
38
|
+
const [helpScreenData, setHelpScreenData] = useState<HelpScreenData | null>(null);
|
|
39
|
+
const [status, setStatus] = useState('idle');
|
|
40
|
+
const [error, setError] = useState('');
|
|
41
|
+
const [selectedOption, setSelectedOption] = useState<Option | null>(null);
|
|
42
|
+
|
|
43
|
+
const [sessionId, setSessionId] = useState<string | null>(null);
|
|
44
|
+
const [isSignalRConnected, setIsSignalRConnected] = useState(false);
|
|
45
|
+
const [isChatClosed, setIsChatClosed] = useState(false);
|
|
46
|
+
const [messages, setMessages] = useState<Message[]>([]);
|
|
47
|
+
const [needsAgent, setNeedsAgent] = useState(false);
|
|
48
|
+
const [assistantStatus, setAssistantStatus] = useState('idle');
|
|
49
|
+
|
|
50
|
+
const [isReviewDialogOpen, setIsReviewDialogOpen] = useState(false);
|
|
48
51
|
|
|
49
52
|
const handleTogglePopup = () => {
|
|
50
|
-
setIsOpen(!isOpen)
|
|
51
|
-
setShowArrowAnimation(isOpen)
|
|
52
|
-
}
|
|
53
|
+
setIsOpen(!isOpen);
|
|
54
|
+
setShowArrowAnimation(isOpen);
|
|
55
|
+
};
|
|
53
56
|
|
|
54
57
|
const handleCloseArrowAnimation = () => {
|
|
55
|
-
setShowArrowAnimation(false)
|
|
56
|
-
}
|
|
58
|
+
setShowArrowAnimation(false);
|
|
59
|
+
};
|
|
57
60
|
|
|
58
61
|
const handleReceiveMessage = (message: string, senderType: number, needsAgent: boolean) => {
|
|
59
|
-
// Update agent status if needed
|
|
60
62
|
if (needsAgent) {
|
|
61
|
-
setNeedsAgent(true)
|
|
63
|
+
setNeedsAgent(true);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
...prevMessages,
|
|
67
|
-
{
|
|
66
|
+
setMessages((prevMessages) => {
|
|
67
|
+
const newMessage = {
|
|
68
68
|
id: Date.now(),
|
|
69
69
|
senderType: senderType,
|
|
70
70
|
messageContent: message,
|
|
71
71
|
sentAt: new Date(),
|
|
72
|
-
isSeen: true
|
|
73
|
-
}
|
|
74
|
-
|
|
72
|
+
isSeen: true,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const updatedMessages = [...prevMessages, newMessage];
|
|
76
|
+
|
|
77
|
+
return updatedMessages;
|
|
78
|
+
});
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
80
|
+
setAssistantStatus('idle');
|
|
81
|
+
};
|
|
79
82
|
|
|
80
|
-
const handleEndChat = async () => {
|
|
81
|
-
if (!sessionId || !selectedOption) return
|
|
83
|
+
const handleEndChat = async (option?: Option) => {
|
|
84
|
+
if (!sessionId || !selectedOption) return;
|
|
82
85
|
|
|
83
86
|
try {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
await ClientSignalRService.stopConnection();
|
|
88
|
+
setIsSignalRConnected(false);
|
|
89
|
+
setAssistantStatus('idle');
|
|
87
90
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
const response = await apiRequest(`Client/ClientChatSession/${sessionId}/close`, 'POST');
|
|
92
|
+
if (!response.ok) throw new Error('Failed to close chat session');
|
|
93
|
+
|
|
94
|
+
setIsReviewDialogOpen(true);
|
|
95
|
+
if (option) {
|
|
96
|
+
handleStartChat(option);
|
|
92
97
|
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('Error ending chat:', error);
|
|
100
|
+
setError('Failed to end chat session');
|
|
101
|
+
setAssistantStatus('idle');
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const handleSendChatReview = async ({ comment, rating }: ReviewProps) => {
|
|
106
|
+
if (!sessionId) return;
|
|
107
|
+
|
|
108
|
+
const payload = { rating, comment };
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
110
|
+
try {
|
|
111
|
+
const response = await apiRequest(`Client/ClientChatSession/${sessionId}/review`, 'POST', payload);
|
|
112
|
+
if (!response.ok) throw new Error('Failed to send chat review');
|
|
96
113
|
|
|
97
|
-
|
|
98
|
-
setTimeout(() => {
|
|
99
|
-
setMessages([])
|
|
100
|
-
setSelectedOption(null)
|
|
101
|
-
}, 3000)
|
|
114
|
+
setIsReviewDialogOpen(false);
|
|
102
115
|
} catch (error) {
|
|
103
|
-
console.error('Error
|
|
104
|
-
setError('Failed to
|
|
116
|
+
console.error('Error sending chat review:', error);
|
|
117
|
+
setError('Failed to send chat review');
|
|
105
118
|
}
|
|
106
|
-
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleCloseChatReview = () => {
|
|
122
|
+
setIsReviewDialogOpen(false);
|
|
123
|
+
};
|
|
107
124
|
|
|
108
125
|
const handleStartChat = async (option: Option) => {
|
|
109
|
-
await startNewChatSession(option)
|
|
110
|
-
}
|
|
126
|
+
await startNewChatSession(option);
|
|
127
|
+
};
|
|
111
128
|
|
|
112
129
|
const startNewChatSession = async (option: Option) => {
|
|
130
|
+
if (isSignalRConnected || sessionId) {
|
|
131
|
+
handleEndChat();
|
|
132
|
+
}
|
|
113
133
|
try {
|
|
114
|
-
setStatus('loading')
|
|
115
|
-
setError('')
|
|
116
|
-
setMessages([])
|
|
134
|
+
setStatus('loading');
|
|
135
|
+
setError('');
|
|
136
|
+
setMessages([]);
|
|
137
|
+
|
|
138
|
+
const tokenResponse = await configService.getToken();
|
|
117
139
|
|
|
118
|
-
const tokenResponse = await configService.getToken()
|
|
119
140
|
const chatSessionCreateDto = {
|
|
120
141
|
helpScreenId: helpScreenId,
|
|
121
142
|
optionId: option.id,
|
|
@@ -123,79 +144,82 @@ export function HelpCenter({
|
|
|
123
144
|
user: {
|
|
124
145
|
id: user.id,
|
|
125
146
|
name: user.name,
|
|
126
|
-
email: user.email
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
}
|
|
147
|
+
email: user.email,
|
|
148
|
+
},
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
130
151
|
|
|
131
|
-
const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto)
|
|
152
|
+
const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto);
|
|
132
153
|
|
|
133
154
|
if (!response.ok) {
|
|
134
|
-
throw new Error('Failed to create chat session')
|
|
155
|
+
throw new Error('Failed to create chat session');
|
|
135
156
|
}
|
|
136
157
|
|
|
137
|
-
const createdSession = await response.json()
|
|
158
|
+
const createdSession = await response.json();
|
|
138
159
|
|
|
139
|
-
setSessionId(createdSession.id)
|
|
160
|
+
setSessionId(createdSession.id);
|
|
140
161
|
|
|
141
|
-
// Add greeting message if available
|
|
142
162
|
if (option.assistant?.greeting) {
|
|
143
163
|
setMessages([
|
|
144
164
|
{
|
|
145
165
|
id: Date.now(),
|
|
146
|
-
senderType: 3,
|
|
166
|
+
senderType: 3,
|
|
147
167
|
messageContent: option.assistant.greeting,
|
|
148
168
|
sentAt: new Date(),
|
|
149
|
-
isSeen: true
|
|
150
|
-
}
|
|
151
|
-
])
|
|
169
|
+
isSeen: true,
|
|
170
|
+
},
|
|
171
|
+
]);
|
|
152
172
|
} else {
|
|
153
|
-
// Default greeting if none provided
|
|
154
173
|
setMessages([
|
|
155
174
|
{
|
|
156
175
|
id: Date.now(),
|
|
157
176
|
senderType: 3,
|
|
158
177
|
messageContent: 'Hello! How can I assist you today?\nمرحباً! كيف يمكنني مساعدتك اليوم؟',
|
|
159
178
|
sentAt: new Date(),
|
|
160
|
-
isSeen: true
|
|
161
|
-
}
|
|
162
|
-
])
|
|
179
|
+
isSeen: true,
|
|
180
|
+
},
|
|
181
|
+
]);
|
|
163
182
|
}
|
|
164
183
|
|
|
165
|
-
|
|
166
|
-
|
|
184
|
+
await ClientSignalRService.startConnection(createdSession.id, tokenResponse, handleReceiveMessage);
|
|
185
|
+
|
|
186
|
+
// Verify the connection is actually active
|
|
187
|
+
if (!ClientSignalRService.isConnectionActive()) {
|
|
188
|
+
throw new Error('SignalR connection failed to establish properly');
|
|
189
|
+
}
|
|
167
190
|
|
|
168
|
-
setIsSignalRConnected(true)
|
|
169
|
-
setIsChatClosed(false)
|
|
170
|
-
setStatus('succeeded')
|
|
191
|
+
setIsSignalRConnected(true);
|
|
192
|
+
setIsChatClosed(false);
|
|
193
|
+
setStatus('succeeded');
|
|
171
194
|
} catch (error) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
setStatus('failed')
|
|
195
|
+
setError(error instanceof Error ? error.message : 'Failed to start chat session');
|
|
196
|
+
setStatus('failed');
|
|
175
197
|
}
|
|
176
|
-
}
|
|
198
|
+
};
|
|
177
199
|
|
|
178
200
|
const handleSendMessage = async (message: string) => {
|
|
179
|
-
|
|
201
|
+
// Only send message if SignalR is connected
|
|
202
|
+
if (!isSignalRConnected) {
|
|
203
|
+
setError('Connection lost. Please try again.');
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let currentSessionId = sessionId;
|
|
180
208
|
|
|
181
209
|
if (message.trim() !== '') {
|
|
182
210
|
try {
|
|
183
|
-
|
|
184
|
-
setAssistantStatus('typing')
|
|
211
|
+
setAssistantStatus('typing');
|
|
185
212
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
])
|
|
213
|
+
const userMessage = {
|
|
214
|
+
id: Date.now(),
|
|
215
|
+
senderType: 1,
|
|
216
|
+
messageContent: message,
|
|
217
|
+
sentAt: new Date(),
|
|
218
|
+
isSeen: false,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
setMessages((prevMessages) => [...prevMessages, userMessage]);
|
|
197
222
|
|
|
198
|
-
// Create a new chat session if not started yet
|
|
199
223
|
if (!currentSessionId) {
|
|
200
224
|
const chatSessionCreateDto = {
|
|
201
225
|
helpScreenId: helpScreenId,
|
|
@@ -203,73 +227,76 @@ export function HelpCenter({
|
|
|
203
227
|
user: {
|
|
204
228
|
id: user?.id,
|
|
205
229
|
name: user?.name,
|
|
206
|
-
email: user?.email
|
|
207
|
-
}
|
|
208
|
-
}
|
|
230
|
+
email: user?.email,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
209
233
|
|
|
210
|
-
const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto)
|
|
234
|
+
const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto);
|
|
211
235
|
|
|
212
236
|
if (!response.ok) {
|
|
213
|
-
throw new Error('Failed to create chat session')
|
|
237
|
+
throw new Error('Failed to create chat session');
|
|
214
238
|
}
|
|
215
239
|
|
|
216
|
-
const createdSession = await response.json()
|
|
217
|
-
setSessionId(createdSession.id)
|
|
218
|
-
currentSessionId = createdSession.id
|
|
240
|
+
const createdSession = await response.json();
|
|
241
|
+
setSessionId(createdSession.id);
|
|
242
|
+
currentSessionId = createdSession.id;
|
|
219
243
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
setIsSignalRConnected(true)
|
|
244
|
+
const tokenResponse = await configService.getToken();
|
|
245
|
+
await ClientSignalRService.startConnection(createdSession.id, tokenResponse, handleReceiveMessage);
|
|
246
|
+
setIsSignalRConnected(true);
|
|
224
247
|
}
|
|
225
248
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const response = await apiRequest(
|
|
249
|
+
const messageDto = { messageContent: message };
|
|
250
|
+
|
|
251
|
+
const response = await apiRequest(
|
|
252
|
+
`Client/ClientChatSession/${currentSessionId}/send-message`,
|
|
253
|
+
'POST',
|
|
254
|
+
messageDto
|
|
255
|
+
);
|
|
229
256
|
|
|
230
257
|
if (!response.ok) {
|
|
231
|
-
throw new Error('Failed to send message')
|
|
258
|
+
throw new Error('Failed to send message');
|
|
232
259
|
}
|
|
233
260
|
|
|
234
|
-
|
|
235
|
-
|
|
261
|
+
setMessages((prevMessages) =>
|
|
262
|
+
prevMessages.map((msg) => (msg.senderType === 1 && !msg.isSeen ? { ...msg, isSeen: true } : msg))
|
|
263
|
+
);
|
|
236
264
|
} catch (error) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
])
|
|
265
|
+
setAssistantStatus('idle');
|
|
266
|
+
const errorMessage = {
|
|
267
|
+
id: Date.now(),
|
|
268
|
+
senderType: 3,
|
|
269
|
+
messageContent:
|
|
270
|
+
'Failed to send the message. Please try again.\n لم يتم إرسال الرسالة. يرجى المحاولة مرة أخرى.',
|
|
271
|
+
sentAt: new Date(),
|
|
272
|
+
isSeen: true,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
setMessages((prevMessages) => [...prevMessages, errorMessage]);
|
|
249
276
|
}
|
|
250
277
|
}
|
|
251
|
-
}
|
|
278
|
+
};
|
|
252
279
|
|
|
253
280
|
useEffect(() => {
|
|
254
281
|
if (isOpen && helpScreenId) {
|
|
255
|
-
setStatus('loading')
|
|
282
|
+
setStatus('loading');
|
|
256
283
|
|
|
257
284
|
apiRequest(`client/clientHelpScreen/${helpScreenId}`)
|
|
258
285
|
.then((res) => res.json())
|
|
259
286
|
.then((data) => {
|
|
260
|
-
setHelpScreenData(data)
|
|
261
|
-
setStatus('succeeded')
|
|
262
|
-
setError('')
|
|
287
|
+
setHelpScreenData(data);
|
|
288
|
+
setStatus('succeeded');
|
|
289
|
+
setError('');
|
|
263
290
|
})
|
|
264
291
|
.catch((err) => {
|
|
265
|
-
setError(err.message)
|
|
266
|
-
setStatus('failed')
|
|
267
|
-
})
|
|
292
|
+
setError(err.message);
|
|
293
|
+
setStatus('failed');
|
|
294
|
+
});
|
|
268
295
|
}
|
|
269
|
-
}, [isOpen, helpScreenId])
|
|
296
|
+
}, [isOpen, helpScreenId]);
|
|
270
297
|
|
|
271
298
|
return (
|
|
272
|
-
<div className=
|
|
299
|
+
<div className='babylai-help-center-container mb-4'>
|
|
273
300
|
{showArrowAnimation && !isOpen && (
|
|
274
301
|
<FloatingMessage onClose={handleCloseArrowAnimation} message={messageLabel || t('homeSdk.needAssistance')} />
|
|
275
302
|
)}
|
|
@@ -298,6 +325,9 @@ export function HelpCenter({
|
|
|
298
325
|
showHelpScreen={showHelpScreen}
|
|
299
326
|
/>
|
|
300
327
|
)}
|
|
328
|
+
{isOpen && !!isReviewDialogOpen && (
|
|
329
|
+
<ReviewDialog handleSubmit={handleSendChatReview} onClose={handleCloseChatReview} />
|
|
330
|
+
)}
|
|
301
331
|
</div>
|
|
302
|
-
)
|
|
332
|
+
);
|
|
303
333
|
}
|