@aslaluroba/help-center-react 3.0.20 → 3.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.
@@ -1,4 +1,5 @@
1
1
  import AgentResponse from '@/components/ui/agent-response/agent-response';
2
+ import { ImageAttachment, ImagePreviewDialog } from '@/components/ui';
2
3
  import { Message } from '@/lib/types';
3
4
  import ChatWindowFooter from '@/ui/chatbot-popup/chat-window-screen/footer';
4
5
  import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react';
@@ -6,9 +7,12 @@ import LoadingGif from './../../../assets/animatedLogo.gif';
6
7
  import Seperator from './../../../assets/icons/seperator.svg';
7
8
  import LogoIcon from './../../../assets/logo.svg';
8
9
  import HumanIcon from './../../../assets/icons/user.svg';
10
+ import { presignDownload } from '@/core/api';
11
+ import { useLocalTranslation } from '../../../useLocalTranslation';
9
12
 
10
13
  interface ChatWindowProps {
11
- onSendMessage: (message: string) => void;
14
+ onSendMessage: (message: string, attachmentIds: string[]) => void;
15
+ onEnsureSession: () => Promise<string>;
12
16
  messages: Message[];
13
17
  assistantStatus: string;
14
18
  needsAgent: boolean;
@@ -23,17 +27,28 @@ const MessageComponent = React.memo(
23
27
  messages,
24
28
  firstHumanAgentIndex,
25
29
  onType,
30
+ onImageClick,
26
31
  }: {
27
32
  message: Message;
28
33
  index: number;
29
34
  messages: Message[];
30
35
  firstHumanAgentIndex: number;
31
36
  onType: () => void;
37
+ onImageClick: (attachmentIds: string[], clickedIndex: number) => void;
32
38
  }) => {
33
39
  const isFirstInSequence = index === 0 || messages[index - 1].senderType !== message.senderType;
34
40
  const isFirstHumanAgentMessage = index === firstHumanAgentIndex && message.senderType === 2;
35
41
  const textDirection = message.senderType === 1 ? 'babylai-justify-end' : 'babylai-justify-start';
36
42
 
43
+ const handleImageClick = useCallback(
44
+ (clickedIndex: number) => {
45
+ if (message.attachmentIds && message.attachmentIds.length > 0) {
46
+ onImageClick(message.attachmentIds, clickedIndex);
47
+ }
48
+ },
49
+ [message.attachmentIds, onImageClick]
50
+ );
51
+
37
52
  return (
38
53
  <div key={message.id}>
39
54
  {isFirstHumanAgentMessage && (
@@ -59,12 +74,26 @@ const MessageComponent = React.memo(
59
74
  )}
60
75
  {!isFirstInSequence && <div className='babylai-flex-shrink-0 babylai-me-3 babylai-w-8'></div>}
61
76
 
62
- <AgentResponse
63
- messageContent={message.messageContent}
64
- senderType={message.senderType}
65
- messageId={message.id}
66
- onType={onType}
67
- />
77
+ <div className='babylai-flex babylai-flex-col babylai-gap-2'>
78
+ {message.attachmentIds && message.attachmentIds.length > 0 && (
79
+ <div className='babylai-flex babylai-flex-row babylai-flex-wrap babylai-gap-2 babylai-max-w-full'>
80
+ {message.attachmentIds.map((attachmentId, imgIndex) => (
81
+ <ImageAttachment
82
+ key={attachmentId}
83
+ fileId={attachmentId}
84
+ enablePreview={false}
85
+ onClick={() => handleImageClick(imgIndex)}
86
+ />
87
+ ))}
88
+ </div>
89
+ )}
90
+ <AgentResponse
91
+ messageContent={message.messageContent}
92
+ senderType={message.senderType}
93
+ messageId={message.id}
94
+ onType={onType}
95
+ />
96
+ </div>
68
97
  </div>
69
98
  </div>
70
99
  );
@@ -93,111 +122,187 @@ const TypingIndicator = React.memo(({ firstHumanAgentIndex }: { firstHumanAgentI
93
122
 
94
123
  TypingIndicator.displayName = 'TypingIndicator';
95
124
 
96
- export const ChatWindow = React.memo(({ onSendMessage, messages, assistantStatus = 'loading' }: ChatWindowProps) => {
97
- const [inputMessage, setInputMessage] = useState('');
98
- const messagesEndRef = useRef<HTMLDivElement>(null);
99
- const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
100
- const lastMessageCountRef = useRef(messages.length);
101
-
102
- // Debounced scroll to bottom function
103
- const scrollToBottom = useCallback(() => {
104
- if (scrollTimeoutRef.current) {
105
- clearTimeout(scrollTimeoutRef.current);
106
- }
107
-
108
- scrollTimeoutRef.current = setTimeout(() => {
109
- messagesEndRef.current?.scrollIntoView({
110
- behavior: 'smooth',
111
- block: 'end',
112
- });
113
- }, 100);
114
- }, []);
115
-
116
- // Only scroll when new messages are added or status changes
117
- useEffect(() => {
118
- if (messages.length !== lastMessageCountRef.current || assistantStatus === 'typing') {
119
- lastMessageCountRef.current = messages.length;
120
- scrollToBottom();
121
- }
122
- }, [messages.length, assistantStatus, scrollToBottom]);
123
-
124
- // Cleanup timeout on unmount
125
- useEffect(() => {
126
- return () => {
125
+ export const ChatWindow = React.memo(
126
+ ({ onSendMessage, onEnsureSession, messages, assistantStatus = 'loading', needsAgent }: ChatWindowProps) => {
127
+ const { i18n } = useLocalTranslation();
128
+ const [inputMessage, setInputMessage] = useState('');
129
+ const messagesEndRef = useRef<HTMLDivElement>(null);
130
+ const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
131
+ const lastMessageCountRef = useRef(messages.length);
132
+ const [galleryState, setGalleryState] = useState<{
133
+ isOpen: boolean;
134
+ imageUrls: string[];
135
+ initialIndex: number;
136
+ }>({
137
+ isOpen: false,
138
+ imageUrls: [],
139
+ initialIndex: 0,
140
+ });
141
+
142
+ // Debounced scroll to bottom function
143
+ const scrollToBottom = useCallback(() => {
127
144
  if (scrollTimeoutRef.current) {
128
145
  clearTimeout(scrollTimeoutRef.current);
129
146
  }
130
- };
131
- }, []);
132
-
133
- const handleSendMessage = useCallback(() => {
134
- if (inputMessage.trim()) {
135
- onSendMessage(inputMessage);
136
- setInputMessage('');
137
- }
138
- }, [inputMessage, onSendMessage]);
139
-
140
- const handleKeyDown = useCallback(
141
- (e: React.KeyboardEvent) => {
142
- if (e.key === 'Enter' && !e.shiftKey) {
143
- e.preventDefault();
144
- if (inputMessage.trim() && assistantStatus !== 'typing') {
145
- onSendMessage(inputMessage);
147
+
148
+ scrollTimeoutRef.current = setTimeout(() => {
149
+ messagesEndRef.current?.scrollIntoView({
150
+ behavior: 'smooth',
151
+ block: 'end',
152
+ });
153
+ }, 100);
154
+ }, []);
155
+
156
+ // Only scroll when new messages are added or status changes
157
+ useEffect(() => {
158
+ if (messages.length !== lastMessageCountRef.current || assistantStatus === 'typing') {
159
+ lastMessageCountRef.current = messages.length;
160
+ scrollToBottom();
161
+ }
162
+ }, [messages.length, assistantStatus, scrollToBottom]);
163
+
164
+ // Cleanup timeout on unmount
165
+ useEffect(() => {
166
+ return () => {
167
+ if (scrollTimeoutRef.current) {
168
+ clearTimeout(scrollTimeoutRef.current);
169
+ }
170
+ };
171
+ }, []);
172
+
173
+ const handleSendMessage = useCallback(
174
+ (attachmentIds: string[]) => {
175
+ if (inputMessage.trim()) {
176
+ onSendMessage(inputMessage, attachmentIds);
146
177
  setInputMessage('');
147
178
  }
179
+ },
180
+ [inputMessage, onSendMessage]
181
+ );
182
+
183
+ // Memoize the first human agent index calculation
184
+ const firstHumanAgentIndex = useMemo(() => {
185
+ return messages.findIndex((message) => message.senderType === 2);
186
+ }, [messages]);
187
+
188
+ // Handle image gallery opening
189
+ const handleImageClick = useCallback(
190
+ async (attachmentIds: string[], clickedIndex: number) => {
191
+ if (!attachmentIds || attachmentIds.length === 0) {
192
+ return;
193
+ }
194
+
195
+ try {
196
+ // Fetch all image URLs with comprehensive error handling
197
+ const imageUrlPromises = attachmentIds.map((fileId) => {
198
+ if (!fileId || typeof fileId !== 'string') {
199
+ return Promise.resolve(null);
200
+ }
201
+
202
+ return presignDownload(fileId, i18n.language)
203
+ .then((response) => {
204
+ if (!response || !response.downloadUrl) {
205
+ return null;
206
+ }
207
+ return response.downloadUrl;
208
+ })
209
+ .catch(() => {
210
+ // Return null for failed downloads so we can filter them out
211
+ return null;
212
+ });
213
+ });
214
+
215
+ const imageUrls = (await Promise.all(imageUrlPromises)).filter(
216
+ (url): url is string => url !== null && url.length > 0
217
+ );
218
+
219
+ if (imageUrls.length === 0) {
220
+ return;
221
+ }
222
+
223
+ // Adjust the initial index if some images failed to load
224
+ let adjustedIndex = Math.max(0, Math.min(clickedIndex, imageUrls.length - 1));
225
+
226
+ setGalleryState({
227
+ isOpen: true,
228
+ imageUrls,
229
+ initialIndex: adjustedIndex,
230
+ });
231
+ } catch (error) {
232
+ // Handle unexpected errors silently
233
+ }
234
+ },
235
+ [i18n.language]
236
+ );
237
+
238
+ const handleCloseGallery = useCallback(() => {
239
+ setGalleryState({
240
+ isOpen: false,
241
+ imageUrls: [],
242
+ initialIndex: 0,
243
+ });
244
+ }, []);
245
+
246
+ // Memoize loading state check
247
+ // When a human agent has joined, don't disable based on assistantStatus
248
+ const hasHumanAgent = useMemo(() => {
249
+ return needsAgent || messages.some((msg) => msg.senderType === 2);
250
+ }, [needsAgent, messages]);
251
+
252
+ const isLoading = useMemo(() => {
253
+ // If human agent has joined, don't disable file uploads based on assistantStatus
254
+ if (hasHumanAgent) {
255
+ return false;
148
256
  }
149
- },
150
- [inputMessage, onSendMessage, assistantStatus]
151
- );
257
+ return assistantStatus === 'typing' || assistantStatus === 'loading' || assistantStatus === 'error';
258
+ }, [assistantStatus, hasHumanAgent]);
259
+
260
+ // Memoize the message list to prevent unnecessary re-renders
261
+ const messagesListWithGallery = useMemo(() => {
262
+ return messages.map((message, index) => (
263
+ <MessageComponent
264
+ key={`${message.id}-${index}`}
265
+ message={message}
266
+ index={index}
267
+ messages={messages}
268
+ firstHumanAgentIndex={firstHumanAgentIndex}
269
+ onType={scrollToBottom}
270
+ onImageClick={handleImageClick}
271
+ />
272
+ ));
273
+ }, [messages, firstHumanAgentIndex, scrollToBottom, handleImageClick]);
152
274
 
153
- // Memoize the first human agent index calculation
154
- const firstHumanAgentIndex = useMemo(() => {
155
- return messages.findIndex((message) => message.senderType === 2);
156
- }, [messages]);
157
-
158
- // Memoize the message list to prevent unnecessary re-renders
159
- const messagesList = useMemo(() => {
160
- return messages.map((message, index) => (
161
- <MessageComponent
162
- key={`${message.id}-${index}`}
163
- message={message}
164
- index={index}
165
- messages={messages}
166
- firstHumanAgentIndex={firstHumanAgentIndex}
167
- onType={scrollToBottom}
168
- />
169
- ));
170
- }, [messages, firstHumanAgentIndex, scrollToBottom]);
171
-
172
- // Memoize loading state check
173
- const isLoading = useMemo(() => {
174
275
  return (
175
- assistantStatus === 'typing' ||
176
- assistantStatus === 'loading' ||
177
- assistantStatus === 'error' ||
178
- inputMessage.trim() === ''
179
- );
180
- }, [assistantStatus, inputMessage]);
276
+ <>
277
+ <div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
278
+ {messagesListWithGallery}
181
279
 
182
- return (
183
- <>
184
- <div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
185
- {messagesList}
280
+ {assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
186
281
 
187
- {assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
282
+ <div ref={messagesEndRef} />
283
+ </div>
188
284
 
189
- <div ref={messagesEndRef} />
190
- </div>
285
+ <ChatWindowFooter
286
+ inputMessage={inputMessage}
287
+ handleSendMessage={handleSendMessage}
288
+ setInputMessage={setInputMessage}
289
+ isLoading={isLoading}
290
+ onEnsureSession={onEnsureSession}
291
+ />
191
292
 
192
- <ChatWindowFooter
193
- inputMessage={inputMessage}
194
- handleKeyDown={handleKeyDown}
195
- handleSendMessage={handleSendMessage}
196
- setInputMessage={setInputMessage}
197
- isLoading={isLoading}
198
- />
199
- </>
200
- );
201
- });
293
+ {/* Gallery Preview Dialog */}
294
+ {galleryState.isOpen && galleryState.imageUrls.length > 0 && (
295
+ <ImagePreviewDialog
296
+ imageUrls={galleryState.imageUrls}
297
+ initialIndex={galleryState.initialIndex}
298
+ isOpen={galleryState.isOpen}
299
+ onClose={handleCloseGallery}
300
+ alt='Image gallery preview'
301
+ />
302
+ )}
303
+ </>
304
+ );
305
+ }
306
+ );
202
307
 
203
308
  ChatWindow.displayName = 'ChatWindow';
@@ -38,7 +38,8 @@ const HelpCenterContent = ({
38
38
  primaryColor,
39
39
  secondaryColor,
40
40
  logoUrl,
41
- }: Omit<HelpCenterProps, 'language'>) => {
41
+ language,
42
+ }: HelpCenterProps) => {
42
43
  const { t } = useLocalTranslation();
43
44
  const [isOpen, setIsOpen] = useState(false);
44
45
  const [showArrowAnimation, setShowArrowAnimation] = useState(showArrow);
@@ -54,7 +55,6 @@ const HelpCenterContent = ({
54
55
  const [messages, setMessages] = useState<Message[]>([]);
55
56
  const [needsAgent, setNeedsAgent] = useState(false);
56
57
  const [assistantStatus, setAssistantStatus] = useState('idle');
57
-
58
58
  const [isReviewDialogOpen, setIsReviewDialogOpen] = useState(false);
59
59
 
60
60
  const handleTogglePopup = () => {
@@ -66,18 +66,24 @@ const HelpCenterContent = ({
66
66
  setShowArrowAnimation(false);
67
67
  };
68
68
 
69
- const handleReceiveMessage = (message: string, senderType: number, needsAgent: boolean) => {
69
+ const handleReceiveMessage = (
70
+ message: string,
71
+ senderType: number,
72
+ needsAgent: boolean,
73
+ attachments: string[] = []
74
+ ) => {
70
75
  if (needsAgent) {
71
76
  setNeedsAgent(true);
72
77
  }
73
78
 
74
79
  setMessages((prevMessages) => {
75
- const newMessage = {
80
+ const newMessage: Message = {
76
81
  id: Date.now(),
77
82
  senderType: senderType,
78
83
  messageContent: message,
79
84
  sentAt: new Date(),
80
85
  isSeen: true,
86
+ ...(attachments.length > 0 && { attachmentIds: attachments }),
81
87
  };
82
88
 
83
89
  return [...prevMessages, newMessage];
@@ -94,7 +100,9 @@ const HelpCenterContent = ({
94
100
  setIsAblyConnected(false);
95
101
  setAssistantStatus('idle');
96
102
 
97
- const response = await apiRequest(`Client/ClientChatSession/${sessionId}/close`, 'POST');
103
+ const response = await apiRequest(`Client/ClientChatSession/${sessionId}/close`, 'POST', null, {
104
+ language: language,
105
+ });
98
106
  if (!response.ok) throw new Error('Failed to close chat session');
99
107
 
100
108
  // Store sessionId for review before clearing the main sessionId
@@ -107,7 +115,6 @@ const HelpCenterContent = ({
107
115
 
108
116
  setIsReviewDialogOpen(true);
109
117
  } catch (error) {
110
- console.error('Error ending chat:', error);
111
118
  setError('Failed to end chat session');
112
119
  setAssistantStatus('idle');
113
120
  // Even if there's an error, clear the session state to prevent stuck state
@@ -123,12 +130,13 @@ const HelpCenterContent = ({
123
130
  const payload = { rating, comment };
124
131
 
125
132
  try {
126
- const response = await apiRequest(`Client/ClientChatSession/${reviewSessionId}/review`, 'POST', payload);
133
+ const response = await apiRequest(`Client/ClientChatSession/${reviewSessionId}/review`, 'POST', payload, {
134
+ language,
135
+ });
127
136
  if (!response.ok) throw new Error('Failed to send chat review');
128
137
 
129
138
  handleCloseChatReview();
130
139
  } catch (error) {
131
- console.error('Error sending chat review:', error);
132
140
  setError('Failed to send chat review');
133
141
  }
134
142
  };
@@ -169,7 +177,9 @@ const HelpCenterContent = ({
169
177
  }),
170
178
  };
171
179
 
172
- const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto);
180
+ const response = await apiRequest('Client/ClientChatSession/create-session', 'POST', chatSessionCreateDto, {
181
+ language,
182
+ });
173
183
 
174
184
  if (!response.ok) {
175
185
  throw new Error('Failed to create chat session');
@@ -204,17 +214,33 @@ const HelpCenterContent = ({
204
214
  }
205
215
  };
206
216
 
207
- const handleSendMessage = async (message: string) => {
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[] = []) => {
208
233
  if (message.trim() !== '') {
209
234
  try {
210
235
  setAssistantStatus('typing');
211
236
 
212
- const userMessage = {
237
+ const userMessage: Message = {
213
238
  id: Date.now(),
214
239
  senderType: 1,
215
240
  messageContent: message,
216
241
  sentAt: new Date(),
217
242
  isSeen: false,
243
+ attachmentIds: attachmentIds.length > 0 ? attachmentIds : undefined,
218
244
  };
219
245
 
220
246
  setMessages((prevMessages) => [...prevMessages, userMessage]);
@@ -230,11 +256,16 @@ const HelpCenterContent = ({
230
256
  throw new Error('No active session available');
231
257
  }
232
258
 
233
- const messageDto = { messageContent: message };
259
+ const messageDto = {
260
+ messageContent: message,
261
+ ...(attachmentIds.length > 0 && { attachmentIds }),
262
+ };
263
+
234
264
  const response = await apiRequest(
235
265
  `Client/ClientChatSession/${currentSessionId}/send-message`,
236
266
  'POST',
237
- messageDto
267
+ messageDto,
268
+ { language }
238
269
  );
239
270
 
240
271
  if (!response.ok) {
@@ -245,10 +276,9 @@ const HelpCenterContent = ({
245
276
  return prevMessages.map((msg) => (msg.senderType === 1 && !msg.isSeen ? { ...msg, isSeen: true } : msg));
246
277
  });
247
278
  } catch (error) {
248
- console.error('Error in handleSendMessage:', error);
249
279
  setAssistantStatus('idle');
250
280
 
251
- const errorMessage = {
281
+ const errorMessage: Message = {
252
282
  id: Date.now(),
253
283
  senderType: 3,
254
284
  messageContent:
@@ -266,7 +296,9 @@ const HelpCenterContent = ({
266
296
  if (isOpen && helpScreenId) {
267
297
  setStatus('loading');
268
298
 
269
- apiRequest(`client/clientHelpScreen/${helpScreenId}`)
299
+ apiRequest(`client/clientHelpScreen/${helpScreenId}`, 'GET', null, {
300
+ language,
301
+ })
270
302
  .then((res) => res.json())
271
303
  .then((data) => {
272
304
  setHelpScreenData(data);
@@ -300,6 +332,7 @@ const HelpCenterContent = ({
300
332
  user={user}
301
333
  onStartChat={handleStartChat}
302
334
  onSendMessage={handleSendMessage}
335
+ onEnsureSession={handleEnsureSession}
303
336
  onEndChat={handleEndChat}
304
337
  messages={messages}
305
338
  needsAgent={needsAgent}
@@ -318,7 +351,7 @@ const HelpCenterContent = ({
318
351
  )}
319
352
  </div>
320
353
  );
321
- }
354
+ };
322
355
 
323
356
  // Main HelpCenter component that provides the language context
324
357
  const HelpCenter = ({
@@ -335,6 +368,7 @@ const HelpCenter = ({
335
368
  return (
336
369
  <LanguageProvider language={language}>
337
370
  <HelpCenterContent
371
+ language={language}
338
372
  helpScreenId={helpScreenId}
339
373
  user={user}
340
374
  showArrow={showArrow}
@@ -346,6 +380,6 @@ const HelpCenter = ({
346
380
  />
347
381
  </LanguageProvider>
348
382
  );
349
- }
383
+ };
350
384
 
351
385
  export default HelpCenter;
@@ -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;