@aslaluroba/help-center-react 2.1.2 → 3.0.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.
Files changed (31) hide show
  1. package/dist/core/AblyService.d.ts +12 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.esm.js +10431 -374
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +10413 -357
  6. package/dist/index.js.map +1 -1
  7. package/dist/lib/config.d.ts +0 -1
  8. package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +1 -1
  9. package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +2 -2
  10. package/dist/ui/confirmation-modal/index.d.ts +9 -0
  11. package/dist/ui/help-popup.d.ts +2 -8
  12. package/package.json +8 -4
  13. package/src/.DS_Store +0 -0
  14. package/src/assets/icons/threeDots.svg +1 -1
  15. package/src/assets/logo_ai.svg +6 -6
  16. package/src/components/ui/agent-response/agent-response.tsx +2 -2
  17. package/src/core/AblyService.ts +137 -0
  18. package/src/index.ts +13 -13
  19. package/src/lib/config.ts +0 -7
  20. package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +4 -4
  21. package/src/ui/chatbot-popup/chat-window-screen/header.tsx +8 -8
  22. package/src/ui/chatbot-popup/chat-window-screen/index.tsx +10 -10
  23. package/src/ui/chatbot-popup/loading-screen/index.tsx +2 -2
  24. package/src/ui/chatbot-popup/options-list-screen/expanded-option.tsx +1 -1
  25. package/src/ui/chatbot-popup/options-list-screen/header.tsx +1 -1
  26. package/src/ui/chatbot-popup/options-list-screen/index.tsx +4 -2
  27. package/src/ui/chatbot-popup/options-list-screen/option-card.tsx +1 -1
  28. package/src/ui/confirmation-modal/index.tsx +44 -0
  29. package/src/ui/help-center.tsx +42 -36
  30. package/src/ui/help-popup.tsx +10 -52
  31. package/src/ui/review-dialog/index.tsx +7 -7
@@ -0,0 +1,44 @@
1
+ import { Button } from "@/components";
2
+ import { useLocalTranslation } from "@/useLocalTranslation";
3
+ import React from "react";
4
+
5
+ interface ConfirmationModalProps {
6
+ title: string;
7
+ message: string;
8
+ onCancel: () => void;
9
+ onConfirm: () => void;
10
+ }
11
+
12
+ const ConfirmationModal = ({ title, message, onCancel, onConfirm, }: ConfirmationModalProps) => {
13
+ const { t } = useLocalTranslation();
14
+
15
+ return (
16
+ <div className='babylai-absolute babylai-inset-0 babylai-z-50 babylai-flex babylai-items-center babylai-justify-center babylai-rounded-3xl babylai-overflow-hidden'>
17
+ <div className='babylai-absolute babylai-inset-0 babylai-bg-black/60' onClick={onCancel}></div>
18
+ <div className='babylai-bg-black-white-100 dark:babylai-bg-storm-dust-900 babylai-rounded-3xl babylai-p-4 babylai-w-[220px] babylai-z-50 babylai-shadow-lg'>
19
+ <h3 className='babylai-text-black-white-900 babylai-font-bold babylai-mb-2 babylai-text-center dark:babylai-text-white'>{title}</h3>
20
+ <p className='babylai-text-black-white-700 babylai-text-xs babylai-mb-4 dark:babylai-text-white'>{message}</p>
21
+ <div className='babylai-flex babylai-justify-end babylai-gap-2 babylai-w-full'>
22
+ <Button
23
+ variant='default'
24
+ size='sm'
25
+ onClick={onConfirm}
26
+ className='babylai-text-sm babylai-w-full !babylai-font-bold'
27
+ >
28
+ {t('homeSdk.ConfirmationModal.confirmation_button')}
29
+ </Button>
30
+ <Button
31
+ variant='outline'
32
+ size='sm'
33
+ onClick={onCancel}
34
+ className='babylai-text-sm babylai-w-full babylai-text-primary-500 !babylai-font-bold'
35
+ >
36
+ {t('homeSdk.ConfirmationModal.cancel_button')}
37
+ </Button>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ );
42
+ };
43
+
44
+ export default ConfirmationModal;
@@ -1,8 +1,7 @@
1
1
  import ReviewDialog from '@/ui/review-dialog';
2
2
  import React, { useEffect, useState } from 'react';
3
3
  import { apiRequest } from '../core/api';
4
- import { ClientSignalRService } from '../core/SignalRService';
5
- import { configService } from '../lib/config';
4
+ import { ClientAblyService } from '../core/AblyService';
6
5
  import { useLocalTranslation } from '../useLocalTranslation';
7
6
  import '../globals.css';
8
7
  import { HelpScreenData, Message, Option, ReviewProps } from '../lib/types';
@@ -42,7 +41,7 @@ export function HelpCenter({
42
41
 
43
42
  const [sessionId, setSessionId] = useState<string | null>(null);
44
43
  const [reviewSessionId, setReviewSessionId] = useState<string | null>(null);
45
- const [isSignalRConnected, setIsSignalRConnected] = useState(false);
44
+ const [isAblyConnected, setIsAblyConnected] = useState(false);
46
45
  const [isChatClosed, setIsChatClosed] = useState(false);
47
46
  const [messages, setMessages] = useState<Message[]>([]);
48
47
  const [needsAgent, setNeedsAgent] = useState(false);
@@ -73,9 +72,7 @@ export function HelpCenter({
73
72
  isSeen: true,
74
73
  };
75
74
 
76
- const updatedMessages = [...prevMessages, newMessage];
77
-
78
- return updatedMessages;
75
+ return [...prevMessages, newMessage];
79
76
  });
80
77
 
81
78
  setAssistantStatus('idle');
@@ -85,8 +82,8 @@ export function HelpCenter({
85
82
  if (!sessionId || !selectedOption) return;
86
83
 
87
84
  try {
88
- await ClientSignalRService.stopConnection();
89
- setIsSignalRConnected(false);
85
+ await ClientAblyService.stopConnection();
86
+ setIsAblyConnected(false);
90
87
  setAssistantStatus('idle');
91
88
 
92
89
  const response = await apiRequest(`Client/ClientChatSession/${sessionId}/close`, 'POST');
@@ -109,7 +106,7 @@ export function HelpCenter({
109
106
  setError('Failed to end chat session');
110
107
  setAssistantStatus('idle');
111
108
  // Even if there's an error, clear the session state to prevent stuck state
112
- setReviewSessionId(sessionId); // Store for review even if there's an error
109
+ setReviewSessionId(sessionId);
113
110
  setSessionId(null);
114
111
  setSelectedOption(null);
115
112
  }
@@ -125,7 +122,7 @@ export function HelpCenter({
125
122
  if (!response.ok) throw new Error('Failed to send chat review');
126
123
 
127
124
  setIsReviewDialogOpen(false);
128
- setReviewSessionId(null); // Clear review session ID after review is sent
125
+ setReviewSessionId(null);
129
126
  } catch (error) {
130
127
  console.error('Error sending chat review:', error);
131
128
  setError('Failed to send chat review');
@@ -134,7 +131,7 @@ export function HelpCenter({
134
131
 
135
132
  const handleCloseChatReview = () => {
136
133
  setIsReviewDialogOpen(false);
137
- setReviewSessionId(null); // Clear review session ID when review is closed
134
+ setReviewSessionId(null);
138
135
  };
139
136
 
140
137
  const handleStartChat = async (option: Option) => {
@@ -142,16 +139,15 @@ export function HelpCenter({
142
139
  };
143
140
 
144
141
  const startNewChatSession = async (option: Option) => {
145
- if (isSignalRConnected || sessionId) {
142
+ if (isAblyConnected || sessionId) {
146
143
  handleEndChat();
147
144
  }
145
+
148
146
  try {
149
147
  setStatus('loading');
150
148
  setError('');
151
149
  setMessages([]);
152
150
 
153
- const tokenResponse = await configService.getToken();
154
-
155
151
  const chatSessionCreateDto = {
156
152
  helpScreenId: helpScreenId,
157
153
  optionId: option.id,
@@ -170,16 +166,15 @@ export function HelpCenter({
170
166
  throw new Error('Failed to create chat session');
171
167
  }
172
168
 
173
- const createdSession = await response.json();
174
-
175
- setSessionId(createdSession.id);
169
+ const responseData = await response.json();
170
+ setSessionId(responseData.chatSession.id);
176
171
 
177
- if (option.assistant?.greeting) {
172
+ if (responseData.chatSession.assistant?.greeting) {
178
173
  setMessages([
179
174
  {
180
175
  id: Date.now(),
181
176
  senderType: 3,
182
- messageContent: option.assistant.greeting,
177
+ messageContent: responseData.chatSession.assistant.greeting,
183
178
  sentAt: new Date(),
184
179
  isSeen: true,
185
180
  },
@@ -196,14 +191,19 @@ export function HelpCenter({
196
191
  ]);
197
192
  }
198
193
 
199
- await ClientSignalRService.startConnection(createdSession.id, tokenResponse, handleReceiveMessage);
194
+ await ClientAblyService.startConnection(
195
+ responseData.chatSession.id,
196
+ responseData.ablyToken,
197
+ handleReceiveMessage,
198
+ responseData.chatSession.tenantId
199
+ );
200
200
 
201
201
  // Verify the connection is actually active
202
- if (!ClientSignalRService.isConnectionActive()) {
203
- throw new Error('SignalR connection failed to establish properly');
202
+ if (!ClientAblyService.isConnectionActive()) {
203
+ throw new Error('Ably connection failed to establish properly');
204
204
  }
205
205
 
206
- setIsSignalRConnected(true);
206
+ setIsAblyConnected(true);
207
207
  setIsChatClosed(false);
208
208
  setStatus('succeeded');
209
209
  } catch (error) {
@@ -213,8 +213,8 @@ export function HelpCenter({
213
213
  };
214
214
 
215
215
  const handleSendMessage = async (message: string) => {
216
- // Only send message if SignalR is connected
217
- if (!isSignalRConnected) {
216
+ // Only send message if Ably is connected
217
+ if (!isAblyConnected) {
218
218
  setError('Connection lost. Please try again.');
219
219
  return;
220
220
  }
@@ -252,17 +252,21 @@ export function HelpCenter({
252
252
  throw new Error('Failed to create chat session');
253
253
  }
254
254
 
255
- const createdSession = await response.json();
256
- setSessionId(createdSession.id);
257
- currentSessionId = createdSession.id;
255
+ const responseData = await response.json();
256
+ setSessionId(responseData.chatSession.id);
257
+ currentSessionId = responseData.chatSession.id;
258
258
 
259
- const tokenResponse = await configService.getToken();
260
- await ClientSignalRService.startConnection(createdSession.id, tokenResponse, handleReceiveMessage);
261
- setIsSignalRConnected(true);
259
+ await ClientAblyService.startConnection(
260
+ responseData.chatSession.id,
261
+ responseData.ablyToken,
262
+ handleReceiveMessage,
263
+ responseData.chatSession.tenantId
264
+ );
265
+
266
+ setIsAblyConnected(true);
262
267
  }
263
268
 
264
269
  const messageDto = { messageContent: message };
265
-
266
270
  const response = await apiRequest(
267
271
  `Client/ClientChatSession/${currentSessionId}/send-message`,
268
272
  'POST',
@@ -273,11 +277,13 @@ export function HelpCenter({
273
277
  throw new Error('Failed to send message');
274
278
  }
275
279
 
276
- setMessages((prevMessages) =>
277
- prevMessages.map((msg) => (msg.senderType === 1 && !msg.isSeen ? { ...msg, isSeen: true } : msg))
278
- );
280
+ setMessages((prevMessages) => {
281
+ return prevMessages.map((msg) => (msg.senderType === 1 && !msg.isSeen ? { ...msg, isSeen: true } : msg));
282
+ });
279
283
  } catch (error) {
284
+ console.error('Error in handleSendMessage:', error);
280
285
  setAssistantStatus('idle');
286
+
281
287
  const errorMessage = {
282
288
  id: Date.now(),
283
289
  senderType: 3,
@@ -334,7 +340,7 @@ export function HelpCenter({
334
340
  assistantStatus={assistantStatus}
335
341
  sessionId={sessionId}
336
342
  isChatClosed={isChatClosed}
337
- isSignalRConnected={isSignalRConnected}
343
+ isAblyConnected={isAblyConnected}
338
344
  selectedOption={selectedOption}
339
345
  setSelectedOption={setSelectedOption}
340
346
  showHelpScreen={showHelpScreen}
@@ -10,6 +10,7 @@ import ChatIcon from '../assets/icons/chat.svg';
10
10
  import { Button } from '@/components';
11
11
  import { HelpScreenData, Message, Option } from '@/lib/types';
12
12
  import { useLocalTranslation } from '../useLocalTranslation';
13
+ import ConfirmationModal from './confirmation-modal';
13
14
 
14
15
  type HelpPopupProps = {
15
16
  isOpen: boolean;
@@ -26,55 +27,12 @@ type HelpPopupProps = {
26
27
  assistantStatus: string;
27
28
  sessionId: string | null;
28
29
  isChatClosed: boolean;
29
- isSignalRConnected: boolean;
30
+ isAblyConnected: boolean;
30
31
  selectedOption: Option | null;
31
32
  setSelectedOption: (option: Option | null) => void;
32
33
  showHelpScreen: boolean;
33
34
  };
34
35
 
35
- // Confirmation Modal Component
36
- export const ConfirmationModal = ({
37
- title,
38
- message,
39
- onCancel,
40
- onConfirm,
41
- }: {
42
- title: string;
43
- message: string;
44
- onCancel: () => void;
45
- onConfirm: () => void;
46
- }) => {
47
- const { t } = useLocalTranslation();
48
-
49
- return (
50
- <div className='babylai-absolute babylai-inset-0 babylai-z-50 babylai-flex babylai-items-center babylai-justify-center babylai-rounded-3xl babylai-overflow-hidden'>
51
- <div className='babylai-absolute babylai-inset-0 babylai-bg-black/60' onClick={onCancel}></div>
52
- <div className='babylai-bg-black-white-100 babylai-rounded-3xl babylai-p-4 babylai-w-[220px] babylai-z-50 babylai-shadow-lg'>
53
- <h3 className='babylai-text-black-white-900 babylai-font-bold babylai-mb-2 babylai-text-center'>{title}</h3>
54
- <p className='babylai-text-black-white-700 babylai-text-xs babylai-mb-4'>{message}</p>
55
- <div className='babylai-flex babylai-justify-end babylai-gap-2 babylai-w-full'>
56
- <Button
57
- variant='default'
58
- size='sm'
59
- onClick={onConfirm}
60
- className='babylai-text-sm babylai-w-full !babylai-font-bold'
61
- >
62
- {t('homeSdk.ConfirmationModal.confirmation_button')}
63
- </Button>
64
- <Button
65
- variant='outline'
66
- size='sm'
67
- onClick={onCancel}
68
- className='babylai-text-sm babylai-w-full babylai-text-primary-500 !babylai-font-bold'
69
- >
70
- {t('homeSdk.ConfirmationModal.cancel_button')}
71
- </Button>
72
- </div>
73
- </div>
74
- </div>
75
- );
76
- };
77
-
78
36
  export function HelpPopup({
79
37
  onClose,
80
38
  helpScreen,
@@ -90,7 +48,7 @@ export function HelpPopup({
90
48
  selectedOption,
91
49
  setSelectedOption,
92
50
  showHelpScreen,
93
- isSignalRConnected,
51
+ isAblyConnected,
94
52
  }: HelpPopupProps) {
95
53
  // ALL HOOKS MUST BE CALLED FIRST - BEFORE ANY EARLY RETURNS
96
54
  const [showChat, setShowChat] = useState(false);
@@ -152,11 +110,11 @@ export function HelpPopup({
152
110
 
153
111
  const handleSendMessage = useCallback(
154
112
  (message: string) => {
155
- if (message.trim() && isSignalRConnected) {
113
+ if (message.trim() && isAblyConnected) {
156
114
  onSendMessage(message.trim());
157
115
  }
158
116
  },
159
- [onSendMessage]
117
+ [onSendMessage, isAblyConnected]
160
118
  );
161
119
 
162
120
  const hideEndChatConfirmation = useCallback(() => {
@@ -241,7 +199,7 @@ export function HelpPopup({
241
199
  messages={memoizedMessages}
242
200
  assistantStatus={assistantStatus}
243
201
  needsAgent={needsAgent}
244
- isSignalRConnected={isSignalRConnected}
202
+ isAblyConnected={isAblyConnected}
245
203
  />
246
204
  </>
247
205
  );
@@ -322,7 +280,7 @@ export function HelpPopup({
322
280
  if (status === 'loading' && !helpScreen) {
323
281
  return (
324
282
  <div
325
- className='babylai-fixed babylai-inset-0 md:babylai-inset-auto md:babylai-max-w-sm md:babylai-min-w-sm md:babylai-h-[calc(100vh-240px)]
283
+ className='babylai-fixed babylai-inset-0 md:babylai-inset-auto md:babylai-max-w-sm md:babylai-min-w-sm md:babylai-h-[calc(100vh-240px) babylai-max-h-[800px]]
326
284
  babylai-overflow-auto babylai-w-full babylai-bg-black-white-50 md:babylai-mb-4
327
285
  md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-rounded-3xl babylai-shadow-lg babylai-z-50 babylai-flex babylai-flex-col'
328
286
  >
@@ -334,7 +292,7 @@ md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-roun
334
292
  if (error) {
335
293
  return (
336
294
  <div
337
- className='babylai-fixed babylai-inset-0 md:babylai-inset-auto md:babylai-max-w-sm md:babylai-min-w-sm md:babylai-h-[calc(100vh-240px)]
295
+ className='babylai-fixed babylai-inset-0 md:babylai-inset-auto md:babylai-max-w-sm md:babylai-min-w-sm md:babylai-h-[calc(100vh-240px) babylai-max-h-[800px]]
338
296
  babylai-overflow-auto babylai-w-full babylai-bg-black-white-50 md:babylai-mb-4
339
297
  md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-rounded-3xl babylai-shadow-lg babylai-z-50 babylai-flex babylai-flex-col'
340
298
  >
@@ -345,7 +303,7 @@ md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-roun
345
303
 
346
304
  return (
347
305
  <div
348
- className='babylai-fixed babylai-inset-0 md:babylai-inset-auto md:babylai-max-w-sm md:babylai-min-w-sm md:babylai-h-[calc(100vh-240px)]
306
+ className='babylai-fixed babylai-inset-0 md:babylai-inset-auto md:babylai-max-w-sm md:babylai-min-w-sm md:babylai-h-[calc(100vh-240px)] babylai-max-h-[800px]
349
307
  babylai-overflow-auto babylai-w-full babylai-bg-black-white-50 md:babylai-mb-4
350
308
  md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-rounded-3xl babylai-shadow-lg babylai-z-50 babylai-flex babylai-flex-col'
351
309
  >
@@ -354,7 +312,7 @@ md:babylai-bottom-[6rem] md:babylai-right-4 babylai-rounded-none md:babylai-roun
354
312
  'babylai-h-full babylai-rounded-none md:babylai-rounded-3xl babylai-flex babylai-flex-col babylai-relative',
355
313
  {
356
314
  'babylai-bg-gradient-to-b babylai-from-primary-500 babylai-to-primary-500/60': !isShowList,
357
- 'babylai-bg-black-white-100': isShowList,
315
+ 'babylai-bg-black-white-100 dark:babylai-bg-storm-dust-950': isShowList,
358
316
  }
359
317
  )}
360
318
  >
@@ -51,18 +51,18 @@ const ReviewDialog: React.FC<ReviewDialogProps> = (props) => {
51
51
  }
52
52
 
53
53
  return (
54
- <section className="babylai-p-6 babylai-gap-6 babylai-max-w-sm babylai-max-h-[calc(100vh-90px)] babylai-overflow-auto babylai-w-full babylai-bg-black-white-50 babylai-fixed babylai-bottom-20 babylai-right-0 md:babylai-right-4 babylai-rounded-3xl babylai-shadow-lg babylai-z-50 babylai-flex babylai-flex-col">
54
+ <section className="babylai-p-6 babylai-gap-6 babylai-max-w-sm babylai-max-h-[calc(100vh-90px)] babylai-overflow-auto babylai-w-full babylai-bg-black-white-50 dark:babylai-bg-storm-dust-950 babylai-fixed babylai-bottom-20 babylai-right-0 md:babylai-right-4 babylai-rounded-3xl babylai-shadow-lg babylai-z-50 babylai-flex babylai-flex-col">
55
55
  <header className='border-b pb-4 babylai-flex babylai-items-center babylai-justify-between babylai-gap-4'>
56
- <h2 className="babylai-text-lg babylai-font-semibold">{t('homeSdk.ReviewDialog.title')}</h2>
57
- <CloseCircle className="babylai-w-6 babylai-h-6 babylai-cursor-pointer" onClick={props.onClose} />
56
+ <h2 className="babylai-text-lg babylai-font-semibold dark:babylai-text-white">{t('homeSdk.ReviewDialog.title')}</h2>
57
+ <CloseCircle className="babylai-w-6 babylai-h-6 babylai-cursor-pointer dark:babylai-text-white" onClick={props.onClose} />
58
58
  </header>
59
59
  <div className="babylai-flex babylai-flex-col babylai-gap-2">
60
- <p className="babylai-text-sm babylai-text-gray-600 mb-3">
60
+ <p className="babylai-text-sm babylai-text-gray-600 mb-3 dark:babylai-text-white">
61
61
  {t('homeSdk.ReviewDialog.description')}
62
62
  </p>
63
63
 
64
64
  <div className="babylai-flex babylai-items-center babylai-gap-2">
65
- <span className="babylai-text-base babylai-font-medium">{t('homeSdk.ReviewDialog.rating_label')}</span>
65
+ <span className="babylai-text-base babylai-font-medium dark:babylai-text-white">{t('homeSdk.ReviewDialog.rating_label')}</span>
66
66
  <Rating value={rating} onChange={handleRatingChange} />
67
67
  <span className={`babylai-text-sm babylai-text-red-500 transition-opacity duration-300 ${error.rating ? 'opacity-100' : 'opacity-0'}`}>
68
68
  {error.rating}
@@ -70,10 +70,10 @@ const ReviewDialog: React.FC<ReviewDialogProps> = (props) => {
70
70
  </div>
71
71
 
72
72
  <div className="babylai-flex babylai-flex-col babylai-gap-2">
73
- <label htmlFor='comment' className="babylai-text-base babylai-font-medium">{t('homeSdk.ReviewDialog.comment_label')}</label>
73
+ <label htmlFor='comment' className="babylai-text-base babylai-font-medium dark:babylai-text-white">{t('homeSdk.ReviewDialog.comment_label')}</label>
74
74
  <textarea
75
75
  id='comment'
76
- className="babylai-bg-black-white-100 babylai-p-6 babylai-rounded-xl babylai-resize-none"
76
+ className="babylai-bg-black-white-100 babylai-p-6 babylai-rounded-xl babylai-resize-none dark:babylai-bg-storm-dust-900 dark:babylai-text-white"
77
77
  rows={4}
78
78
  placeholder="Write your comment here..."
79
79
  value={comment}