@aslaluroba/help-center-react 3.0.21 → 3.2.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.
@@ -1,16 +1,16 @@
1
- import ReviewDialog from "@/ui/review-dialog";
2
- import { useEffect, useState } from "react";
3
- import { apiRequest } from "../core/api";
4
- import { ClientAblyService } from "../core/AblyService";
5
- import { useLocalTranslation } from "../useLocalTranslation";
6
- import "../globals.css";
7
- import { HelpScreenData, Message, Option, ReviewProps } from "@/lib/types";
8
- import FloatingMessage from "./floating-message";
9
- import HelpButton from "./help-button";
10
- import HelpPopup from "./help-popup";
11
- import { defaultLanguage } from "@/i18n";
12
- import { LanguageProvider } from "@/lib/LanguageContext";
13
- import { getThemeStyles } from "@/lib/theme-utils";
1
+ import ReviewDialog from '@/ui/review-dialog';
2
+ import { useEffect, useState } from 'react';
3
+ import { apiRequest } from '../core/api';
4
+ import { ClientAblyService } from '../core/AblyService';
5
+ import { useLocalTranslation } from '../useLocalTranslation';
6
+ import '../globals.css';
7
+ import { HelpScreenData, Message, Option, ReviewProps } from '@/lib/types';
8
+ import FloatingMessage from './floating-message';
9
+ import HelpButton from './help-button';
10
+ import HelpPopup from './help-popup';
11
+ import { defaultLanguage } from '@/i18n';
12
+ import { LanguageProvider } from '@/lib/LanguageContext';
13
+ import { getThemeStyles } from '@/lib/theme-utils';
14
14
 
15
15
  interface HelpCenterProps {
16
16
  helpScreenId: string;
@@ -43,11 +43,9 @@ const HelpCenterContent = ({
43
43
  const { t } = useLocalTranslation();
44
44
  const [isOpen, setIsOpen] = useState(false);
45
45
  const [showArrowAnimation, setShowArrowAnimation] = useState(showArrow);
46
- const [helpScreenData, setHelpScreenData] = useState<HelpScreenData | null>(
47
- null,
48
- );
49
- const [status, setStatus] = useState("idle");
50
- const [error, setError] = useState("");
46
+ const [helpScreenData, setHelpScreenData] = useState<HelpScreenData | null>(null);
47
+ const [status, setStatus] = useState('idle');
48
+ const [error, setError] = useState('');
51
49
  const [selectedOption, setSelectedOption] = useState<Option | null>(null);
52
50
 
53
51
  const [sessionId, setSessionId] = useState<string | null>(null);
@@ -56,7 +54,7 @@ const HelpCenterContent = ({
56
54
  const [isChatClosed, setIsChatClosed] = useState(false);
57
55
  const [messages, setMessages] = useState<Message[]>([]);
58
56
  const [needsAgent, setNeedsAgent] = useState(false);
59
- const [assistantStatus, setAssistantStatus] = useState("idle");
57
+ const [assistantStatus, setAssistantStatus] = useState('idle');
60
58
  const [isReviewDialogOpen, setIsReviewDialogOpen] = useState(false);
61
59
 
62
60
  const handleTogglePopup = () => {
@@ -72,24 +70,26 @@ const HelpCenterContent = ({
72
70
  message: string,
73
71
  senderType: number,
74
72
  needsAgent: boolean,
73
+ attachments: string[] = []
75
74
  ) => {
76
75
  if (needsAgent) {
77
76
  setNeedsAgent(true);
78
77
  }
79
78
 
80
79
  setMessages((prevMessages) => {
81
- const newMessage = {
80
+ const newMessage: Message = {
82
81
  id: Date.now(),
83
82
  senderType: senderType,
84
83
  messageContent: message,
85
84
  sentAt: new Date(),
86
85
  isSeen: true,
86
+ ...(attachments.length > 0 && { attachmentIds: attachments }),
87
87
  };
88
88
 
89
89
  return [...prevMessages, newMessage];
90
90
  });
91
91
 
92
- setAssistantStatus("idle");
92
+ setAssistantStatus('idle');
93
93
  };
94
94
 
95
95
  const handleEndChat = async () => {
@@ -98,15 +98,12 @@ const HelpCenterContent = ({
98
98
  try {
99
99
  await ClientAblyService.stopConnection();
100
100
  setIsAblyConnected(false);
101
- setAssistantStatus("idle");
101
+ setAssistantStatus('idle');
102
102
 
103
- const response = await apiRequest(
104
- `Client/ClientChatSession/${sessionId}/close`,
105
- "POST",
106
- null,
107
- { language: language },
108
- );
109
- if (!response.ok) throw new Error("Failed to close chat session");
103
+ const response = await apiRequest(`Client/ClientChatSession/${sessionId}/close`, 'POST', null, {
104
+ language: language,
105
+ });
106
+ if (!response.ok) throw new Error('Failed to close chat session');
110
107
 
111
108
  // Store sessionId for review before clearing the main sessionId
112
109
  setReviewSessionId(sessionId);
@@ -118,9 +115,8 @@ const HelpCenterContent = ({
118
115
 
119
116
  setIsReviewDialogOpen(true);
120
117
  } catch (error) {
121
- console.error("Error ending chat:", error);
122
- setError("Failed to end chat session");
123
- setAssistantStatus("idle");
118
+ setError('Failed to end chat session');
119
+ setAssistantStatus('idle');
124
120
  // Even if there's an error, clear the session state to prevent stuck state
125
121
  setReviewSessionId(sessionId);
126
122
  setSessionId(null);
@@ -134,18 +130,14 @@ const HelpCenterContent = ({
134
130
  const payload = { rating, comment };
135
131
 
136
132
  try {
137
- const response = await apiRequest(
138
- `Client/ClientChatSession/${reviewSessionId}/review`,
139
- "POST",
140
- payload,
141
- { language },
142
- );
143
- if (!response.ok) throw new Error("Failed to send chat review");
133
+ const response = await apiRequest(`Client/ClientChatSession/${reviewSessionId}/review`, 'POST', payload, {
134
+ language,
135
+ });
136
+ if (!response.ok) throw new Error('Failed to send chat review');
144
137
 
145
138
  handleCloseChatReview();
146
139
  } catch (error) {
147
- console.error("Error sending chat review:", error);
148
- setError("Failed to send chat review");
140
+ setError('Failed to send chat review');
149
141
  }
150
142
  };
151
143
 
@@ -159,20 +151,19 @@ const HelpCenterContent = ({
159
151
  {
160
152
  id: Date.now(),
161
153
  senderType: 3,
162
- messageContent:
163
- option?.assistant?.greeting || "مرحباً! كيف يمكنني مساعدتك اليوم؟",
154
+ messageContent: option?.assistant?.greeting || 'مرحباً! كيف يمكنني مساعدتك اليوم؟',
164
155
  sentAt: new Date(),
165
156
  isSeen: true,
166
157
  },
167
158
  ]);
168
159
  setIsChatClosed(false);
169
- setStatus("succeeded");
160
+ setStatus('succeeded');
170
161
  };
171
162
 
172
163
  const startNewChatSession = async (option: Option): Promise<string> => {
173
164
  try {
174
- setStatus("loading");
175
- setError("");
165
+ setStatus('loading');
166
+ setError('');
176
167
 
177
168
  const chatSessionCreateDto = {
178
169
  helpScreenId: helpScreenId,
@@ -186,15 +177,12 @@ const HelpCenterContent = ({
186
177
  }),
187
178
  };
188
179
 
189
- const response = await apiRequest(
190
- "Client/ClientChatSession/create-session",
191
- "POST",
192
- chatSessionCreateDto,
193
- { language },
194
- );
180
+ const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto, {
181
+ language,
182
+ });
195
183
 
196
184
  if (!response.ok) {
197
- throw new Error("Failed to create chat session");
185
+ throw new Error('Failed to create chat session');
198
186
  }
199
187
 
200
188
  const responseData = await response.json();
@@ -206,39 +194,53 @@ const HelpCenterContent = ({
206
194
  newSessionId,
207
195
  responseData.ablyToken,
208
196
  handleReceiveMessage,
209
- responseData.chatSession.tenantId,
197
+ responseData.chatSession.tenantId
210
198
  );
211
199
 
212
200
  // Verify the connection is actually active
213
201
  if (!ClientAblyService.isConnectionActive()) {
214
- throw new Error("Ably connection failed to establish properly");
202
+ throw new Error('Ably connection failed to establish properly');
215
203
  }
216
204
 
217
205
  setIsAblyConnected(true);
218
206
  setIsChatClosed(false);
219
- setStatus("succeeded");
207
+ setStatus('succeeded');
220
208
 
221
209
  return newSessionId; // Return the session ID
222
210
  } catch (error) {
223
- setError(
224
- error instanceof Error ? error.message : "Failed to start chat session",
225
- );
226
- setStatus("failed");
211
+ setError(error instanceof Error ? error.message : 'Failed to start chat session');
212
+ setStatus('failed');
227
213
  throw error; // Re-throw to handle in calling function
228
214
  }
229
215
  };
230
216
 
231
- const handleSendMessage = async (message: string) => {
232
- if (message.trim() !== "") {
217
+ const handleEnsureSession = async (): Promise<string> => {
218
+ // If we already have a session ID and connection, return it
219
+ if (sessionId && isAblyConnected) {
220
+ return sessionId;
221
+ }
222
+
223
+ // If we have a selected option but no session, create one
224
+ if (selectedOption) {
225
+ const newSessionId = await startNewChatSession(selectedOption);
226
+ return newSessionId;
227
+ }
228
+
229
+ throw new Error('No option selected');
230
+ };
231
+
232
+ const handleSendMessage = async (message: string, attachmentIds: string[] = []) => {
233
+ if (message.trim() !== '') {
233
234
  try {
234
- setAssistantStatus("typing");
235
+ setAssistantStatus('typing');
235
236
 
236
- const userMessage = {
237
+ const userMessage: Message = {
237
238
  id: Date.now(),
238
239
  senderType: 1,
239
240
  messageContent: message,
240
241
  sentAt: new Date(),
241
242
  isSeen: false,
243
+ attachmentIds: attachmentIds.length > 0 ? attachmentIds : undefined,
242
244
  };
243
245
 
244
246
  setMessages((prevMessages) => [...prevMessages, userMessage]);
@@ -251,37 +253,36 @@ const HelpCenterContent = ({
251
253
  }
252
254
 
253
255
  if (!currentSessionId) {
254
- throw new Error("No active session available");
256
+ throw new Error('No active session available');
255
257
  }
256
258
 
257
- const messageDto = { messageContent: message };
259
+ const messageDto = {
260
+ messageContent: message,
261
+ ...(attachmentIds.length > 0 && { attachmentIds }),
262
+ };
263
+
258
264
  const response = await apiRequest(
259
265
  `Client/ClientChatSession/${currentSessionId}/send-message`,
260
- "POST",
266
+ 'POST',
261
267
  messageDto,
262
- { language },
268
+ { language }
263
269
  );
264
270
 
265
271
  if (!response.ok) {
266
- throw new Error("Failed to send message");
272
+ throw new Error('Failed to send message');
267
273
  }
268
274
 
269
275
  setMessages((prevMessages) => {
270
- return prevMessages.map((msg) =>
271
- msg.senderType === 1 && !msg.isSeen
272
- ? { ...msg, isSeen: true }
273
- : msg,
274
- );
276
+ return prevMessages.map((msg) => (msg.senderType === 1 && !msg.isSeen ? { ...msg, isSeen: true } : msg));
275
277
  });
276
278
  } catch (error) {
277
- console.error("Error in handleSendMessage:", error);
278
- setAssistantStatus("idle");
279
+ setAssistantStatus('idle');
279
280
 
280
- const errorMessage = {
281
+ const errorMessage: Message = {
281
282
  id: Date.now(),
282
283
  senderType: 3,
283
284
  messageContent:
284
- "Failed to send the message. Please try again.\n لم يتم إرسال الرسالة. يرجى المحاولة مرة أخرى.",
285
+ 'Failed to send the message. Please try again.\n لم يتم إرسال الرسالة. يرجى المحاولة مرة أخرى.',
285
286
  sentAt: new Date(),
286
287
  isSeen: true,
287
288
  };
@@ -293,20 +294,20 @@ const HelpCenterContent = ({
293
294
 
294
295
  useEffect(() => {
295
296
  if (isOpen && helpScreenId) {
296
- setStatus("loading");
297
+ setStatus('loading');
297
298
 
298
- apiRequest(`client/clientHelpScreen/${helpScreenId}`, "GET", null, {
299
+ apiRequest(`client/clientHelpScreen/${helpScreenId}`, 'GET', null, {
299
300
  language,
300
301
  })
301
302
  .then((res) => res.json())
302
303
  .then((data) => {
303
304
  setHelpScreenData(data);
304
- setStatus("succeeded");
305
- setError("");
305
+ setStatus('succeeded');
306
+ setError('');
306
307
  })
307
308
  .catch((err) => {
308
309
  setError(err.message);
309
- setStatus("failed");
310
+ setStatus('failed');
310
311
  });
311
312
  }
312
313
  }, [isOpen, helpScreenId]);
@@ -314,12 +315,9 @@ const HelpCenterContent = ({
314
315
  const themeStyles = getThemeStyles({ primaryColor, secondaryColor });
315
316
 
316
317
  return (
317
- <div className="babylai-help-center-container mb-4" style={themeStyles}>
318
+ <div className='babylai-help-center-container mb-4' style={themeStyles}>
318
319
  {showArrowAnimation && !isOpen && (
319
- <FloatingMessage
320
- onClose={handleCloseArrowAnimation}
321
- message={messageLabel || t("homeSdk.needAssistance")}
322
- />
320
+ <FloatingMessage onClose={handleCloseArrowAnimation} message={messageLabel || t('homeSdk.needAssistance')} />
323
321
  )}
324
322
 
325
323
  <HelpButton onClick={handleTogglePopup} />
@@ -334,6 +332,7 @@ const HelpCenterContent = ({
334
332
  user={user}
335
333
  onStartChat={handleStartChat}
336
334
  onSendMessage={handleSendMessage}
335
+ onEnsureSession={handleEnsureSession}
337
336
  onEndChat={handleEndChat}
338
337
  messages={messages}
339
338
  needsAgent={needsAgent}
@@ -348,10 +347,7 @@ const HelpCenterContent = ({
348
347
  />
349
348
  )}
350
349
  {isOpen && !!isReviewDialogOpen && reviewSessionId && (
351
- <ReviewDialog
352
- handleSubmit={handleSendChatReview}
353
- onClose={handleCloseChatReview}
354
- />
350
+ <ReviewDialog handleSubmit={handleSendChatReview} onClose={handleCloseChatReview} />
355
351
  )}
356
352
  </div>
357
353
  );
@@ -21,7 +21,8 @@ type HelpPopupProps = {
21
21
  error: string | null;
22
22
  user: any;
23
23
  onStartChat: (option: Option) => void;
24
- onSendMessage: (message: string) => void;
24
+ onSendMessage: (message: string, attachmentIds: string[]) => void;
25
+ onEnsureSession: () => Promise<string>;
25
26
  onEndChat: (option?: Option) => void;
26
27
  messages: Message[];
27
28
  needsAgent: boolean;
@@ -42,6 +43,7 @@ const HelpPopup = ({
42
43
  error,
43
44
  onStartChat,
44
45
  onSendMessage,
46
+ onEnsureSession,
45
47
  onEndChat,
46
48
  messages,
47
49
  assistantStatus,
@@ -112,9 +114,9 @@ const HelpPopup = ({
112
114
  );
113
115
 
114
116
  const handleSendMessage = useCallback(
115
- (message: string) => {
117
+ (message: string, attachmentIds: string[]) => {
116
118
  if (message.trim()) {
117
- onSendMessage(message.trim());
119
+ onSendMessage(message.trim(), attachmentIds);
118
120
  }
119
121
  },
120
122
  [onSendMessage]
@@ -167,6 +169,7 @@ const HelpPopup = ({
167
169
  />
168
170
  <ChatWindow
169
171
  onSendMessage={handleSendMessage}
172
+ onEnsureSession={onEnsureSession}
170
173
  messages={memoizedMessages}
171
174
  assistantStatus={assistantStatus}
172
175
  needsAgent={needsAgent}
@@ -188,11 +191,7 @@ const HelpPopup = ({
188
191
  />
189
192
  );
190
193
  }
191
- return <HomeScreen
192
- setIsShowList={setIsShowList}
193
- onClose={onClose}
194
- logoUrl={logoUrl}
195
- />;
194
+ return <HomeScreen setIsShowList={setIsShowList} onClose={onClose} logoUrl={logoUrl} />;
196
195
  }, [
197
196
  showChat,
198
197
  selectedOption,
@@ -202,6 +201,7 @@ const HelpPopup = ({
202
201
  isShowList,
203
202
  setIsShowList,
204
203
  handleSendMessage,
204
+ onEnsureSession,
205
205
  memoizedMessages,
206
206
  assistantStatus,
207
207
  needsAgent,
@@ -210,6 +210,8 @@ const HelpPopup = ({
210
210
  setExpandedOption,
211
211
  handleStartChat,
212
212
  showHelpScreen,
213
+ isAblyConnected,
214
+ logoUrl,
213
215
  ]);
214
216
 
215
217
  // Memoize confirmation modal
@@ -311,6 +313,6 @@ md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-roun
311
313
  </div>
312
314
  </div>
313
315
  );
314
- }
316
+ };
315
317
 
316
318
  export default HelpPopup;
@@ -1,19 +1,20 @@
1
- import { useLocalTranslation } from "@/useLocalTranslation";
1
+ import { useLocalTranslation } from '@/useLocalTranslation';
2
2
 
3
3
  const PoweredBy: React.FC = () => {
4
4
  const { t } = useLocalTranslation();
5
5
 
6
6
  return (
7
- <section className="dark:babylai-text-white babylai-font-bold babylai-text-center babylai-px-8 babylai-py-2 babylai-w-full">
7
+ <section className='dark:babylai-text-white babylai-font-bold babylai-text-center babylai-px-8 babylai-py-2 babylai-w-full'>
8
8
  <a
9
- href="https://www.babylai.net/"
10
- target="_blank"
11
- rel="noopener noreferrer"
12
- className="babylai-text-xs babylai-opacity-60 hover:babylai-opacity-100 babylai-transition-all">
9
+ href='https://www.babylai.net/'
10
+ target='_blank'
11
+ rel='noopener noreferrer'
12
+ className='babylai-text-xs babylai-opacity-60 hover:babylai-opacity-100 babylai-transition-all'
13
+ >
13
14
  {t('homeSdk.poweredBy')} BabylAI © 2025
14
15
  </a>
15
16
  </section>
16
- )
17
- }
17
+ );
18
+ };
18
19
 
19
- export default PoweredBy
20
+ export default PoweredBy;