@aslaluroba/help-center-react 2.0.5 → 2.0.7

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.
@@ -5,6 +5,7 @@ interface ChatWindowFooterProps {
5
5
  handleKeyDown: (e: React.KeyboardEvent) => void;
6
6
  handleSendMessage: () => void;
7
7
  isLoading: boolean;
8
+ isSignalRConnected: boolean;
8
9
  }
9
10
  declare const ChatWindowFooter: React.FC<ChatWindowFooterProps>;
10
11
  export default ChatWindowFooter;
@@ -5,6 +5,7 @@ interface ChatWindowProps {
5
5
  messages: Message[];
6
6
  assistantStatus: string;
7
7
  needsAgent: boolean;
8
+ isSignalRConnected: boolean;
8
9
  }
9
- export declare const ChatWindow: React.MemoExoticComponent<({ onSendMessage, messages, assistantStatus }: ChatWindowProps) => React.JSX.Element>;
10
+ export declare const ChatWindow: React.MemoExoticComponent<({ onSendMessage, messages, assistantStatus, isSignalRConnected }: ChatWindowProps) => React.JSX.Element>;
10
11
  export {};
@@ -26,5 +26,5 @@ export declare const ConfirmationModal: ({ title, message, onCancel, onConfirm,
26
26
  onCancel: () => void;
27
27
  onConfirm: () => void;
28
28
  }) => React.JSX.Element;
29
- export declare function HelpPopup({ onClose, helpScreen, status, error, onStartChat, onSendMessage, onEndChat, messages, assistantStatus, needsAgent, sessionId, selectedOption, setSelectedOption, showHelpScreen, }: HelpPopupProps): React.JSX.Element;
29
+ export declare function HelpPopup({ onClose, helpScreen, status, error, onStartChat, onSendMessage, onEndChat, messages, assistantStatus, needsAgent, sessionId, selectedOption, setSelectedOption, showHelpScreen, isSignalRConnected, }: HelpPopupProps): React.JSX.Element;
30
30
  export {};
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "main": "dist/index.js",
4
4
  "module": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
- "version": "2.0.5",
6
+ "version": "2.0.7",
7
7
  "description": "BabylAI Help Center Widget for React and Next.js",
8
8
  "private": false,
9
9
  "exports": {
package/src/lib/config.ts CHANGED
@@ -24,8 +24,6 @@ class ConfigService {
24
24
  }
25
25
 
26
26
  initialize(config: Config) {
27
- console.log('🔧 Initializing config with:', config);
28
-
29
27
  this.config = {
30
28
  baseUrl: config.baseUrl || 'https://babylai.net/api',
31
29
  hubUrl: config.hubUrl || config.baseUrl || 'https://babylai.net/api',
@@ -34,19 +32,15 @@ class ConfigService {
34
32
  getToken: config.getToken,
35
33
  };
36
34
 
37
- console.log('📋 Final config:', this.config);
38
-
39
35
  // Initialize API with the getToken function directly
40
36
  if (!this.config.getToken) {
41
37
  throw new Error('getToken function is required in configuration');
42
38
  }
43
39
 
44
- console.log('🌐 Initializing API with baseUrl:', this.config.baseUrl);
45
40
  initializeAPI(this.config.baseUrl || 'https://babylai.net/api', this.config.getToken);
46
41
 
47
42
  // Initialize SignalR
48
43
  const hubUrl = this.config.hubUrl || this.config.baseUrl || 'https://babylai.net/api';
49
- console.log('🔌 Initializing SignalR with hubUrl:', hubUrl);
50
44
  ClientSignalRService.initialize(hubUrl);
51
45
  }
52
46
 
@@ -1,39 +1,40 @@
1
- import { Button } from '@/components'
2
- import React from 'react'
3
- import EnvelopeIcon from './../../../assets/icons/envelope.svg'
4
- import { useLocalTranslation } from '../../../useLocalTranslation'
1
+ import { Button } from '@/components';
2
+ import React from 'react';
3
+ import EnvelopeIcon from './../../../assets/icons/envelope.svg';
4
+ import { useLocalTranslation } from '../../../useLocalTranslation';
5
5
 
6
6
  interface ChatWindowFooterProps {
7
- inputMessage: string
8
- setInputMessage: (e: string) => void
9
- handleKeyDown: (e: React.KeyboardEvent) => void
10
- handleSendMessage: () => void
11
- isLoading: boolean
7
+ inputMessage: string;
8
+ setInputMessage: (e: string) => void;
9
+ handleKeyDown: (e: React.KeyboardEvent) => void;
10
+ handleSendMessage: () => void;
11
+ isLoading: boolean;
12
+ isSignalRConnected: boolean;
12
13
  }
13
14
 
14
15
  const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
15
- const { t, dir } = useLocalTranslation()
16
+ const { t, dir } = useLocalTranslation();
16
17
  return (
17
- <footer className="babylai-flex babylai-items-center babylai-gap-2 babylai-relative babylai-rounded-full babylai-bg-white babylai-m-4 md:babylai-m-6 md:babylai-py-3 md:babylai-px-4">
18
+ <footer className='babylai-flex babylai-items-center babylai-gap-2 babylai-relative babylai-rounded-full babylai-bg-white babylai-m-4 md:babylai-m-6 md:babylai-py-3 md:babylai-px-4'>
18
19
  <input
19
- type="text"
20
+ type='text'
20
21
  value={props.inputMessage}
21
22
  onChange={(e) => props.setInputMessage(e.target.value)}
22
23
  onKeyDown={props.handleKeyDown}
23
24
  placeholder={t('homeSdk.placeholder')}
24
- className="babylai-flex-1 babylai-py-2 babylai-px-4 babylai-bg-transparent babylai-outline-none babylai-text-sm"
25
+ className='babylai-flex-1 babylai-py-2 babylai-px-4 babylai-bg-transparent babylai-outline-none babylai-text-sm'
25
26
  />
26
27
  <Button
27
- variant="default"
28
- size="icon"
28
+ variant='default'
29
+ size='icon'
29
30
  onClick={props.handleSendMessage}
30
- disabled={props?.isLoading}
31
- className="babylai-rounded-full babylai-bg-purple-500 babylai-hover:babylai-bg-purple-600 babylai-w-8 babylai-h-8 babylai-disabled:babylai-opacity-50"
31
+ disabled={props?.isLoading || !props.isSignalRConnected}
32
+ className='babylai-rounded-full babylai-bg-purple-500 babylai-hover:babylai-bg-purple-600 babylai-w-8 babylai-h-8 babylai-disabled:babylai-opacity-50'
32
33
  >
33
34
  <EnvelopeIcon className={`babylai-w-4 babylai-h-4 ${dir === 'rtl' ? 'babylai-rotate-270' : ''}`} />
34
35
  </Button>
35
36
  </footer>
36
- )
37
- }
37
+ );
38
+ };
38
39
 
39
- export default ChatWindowFooter
40
+ export default ChatWindowFooter;
@@ -11,6 +11,7 @@ interface ChatWindowProps {
11
11
  messages: Message[];
12
12
  assistantStatus: string;
13
13
  needsAgent: boolean;
14
+ isSignalRConnected: boolean;
14
15
  }
15
16
 
16
17
  // Memoize individual message component to prevent unnecessary re-renders
@@ -83,111 +84,114 @@ const TypingIndicator = React.memo(({ firstHumanAgentIndex }: { firstHumanAgentI
83
84
 
84
85
  TypingIndicator.displayName = 'TypingIndicator';
85
86
 
86
- export const ChatWindow = React.memo(({ onSendMessage, messages, assistantStatus = 'loading' }: ChatWindowProps) => {
87
- const [inputMessage, setInputMessage] = useState('');
88
- const messagesEndRef = useRef<HTMLDivElement>(null);
89
- const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
90
- const lastMessageCountRef = useRef(messages.length);
91
-
92
- // Debounced scroll to bottom function
93
- const scrollToBottom = useCallback(() => {
94
- if (scrollTimeoutRef.current) {
95
- clearTimeout(scrollTimeoutRef.current);
96
- }
97
-
98
- scrollTimeoutRef.current = setTimeout(() => {
99
- messagesEndRef.current?.scrollIntoView({
100
- behavior: 'smooth',
101
- block: 'end',
102
- });
103
- }, 100);
104
- }, []);
105
-
106
- // Only scroll when new messages are added or status changes
107
- useEffect(() => {
108
- if (messages.length !== lastMessageCountRef.current || assistantStatus === 'typing') {
109
- lastMessageCountRef.current = messages.length;
110
- scrollToBottom();
111
- }
112
- }, [messages.length, assistantStatus, scrollToBottom]);
113
-
114
- // Cleanup timeout on unmount
115
- useEffect(() => {
116
- return () => {
87
+ export const ChatWindow = React.memo(
88
+ ({ onSendMessage, messages, assistantStatus = 'loading', isSignalRConnected }: ChatWindowProps) => {
89
+ const [inputMessage, setInputMessage] = useState('');
90
+ const messagesEndRef = useRef<HTMLDivElement>(null);
91
+ const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
92
+ const lastMessageCountRef = useRef(messages.length);
93
+
94
+ // Debounced scroll to bottom function
95
+ const scrollToBottom = useCallback(() => {
117
96
  if (scrollTimeoutRef.current) {
118
97
  clearTimeout(scrollTimeoutRef.current);
119
98
  }
120
- };
121
- }, []);
122
-
123
- const handleSendMessage = useCallback(() => {
124
- if (inputMessage.trim()) {
125
- onSendMessage(inputMessage);
126
- setInputMessage('');
127
- }
128
- }, [inputMessage, onSendMessage]);
129
-
130
- const handleKeyDown = useCallback(
131
- (e: React.KeyboardEvent) => {
132
- if (e.key === 'Enter' && !e.shiftKey) {
133
- e.preventDefault();
134
- if (inputMessage.trim() && assistantStatus !== 'typing') {
135
- onSendMessage(inputMessage);
136
- setInputMessage('');
137
- }
99
+
100
+ scrollTimeoutRef.current = setTimeout(() => {
101
+ messagesEndRef.current?.scrollIntoView({
102
+ behavior: 'smooth',
103
+ block: 'end',
104
+ });
105
+ }, 100);
106
+ }, []);
107
+
108
+ // Only scroll when new messages are added or status changes
109
+ useEffect(() => {
110
+ if (messages.length !== lastMessageCountRef.current || assistantStatus === 'typing') {
111
+ lastMessageCountRef.current = messages.length;
112
+ scrollToBottom();
138
113
  }
139
- },
140
- [inputMessage, onSendMessage, assistantStatus]
141
- );
114
+ }, [messages.length, assistantStatus, scrollToBottom]);
142
115
 
143
- // Memoize the first human agent index calculation
144
- const firstHumanAgentIndex = useMemo(() => {
145
- return messages.findIndex((message) => message.senderType === 2);
146
- }, [messages]);
147
-
148
- // Memoize the message list to prevent unnecessary re-renders
149
- const messagesList = useMemo(() => {
150
- return messages.map((message, index) => (
151
- <MessageComponent
152
- key={`${message.id}-${index}`}
153
- message={message}
154
- index={index}
155
- messages={messages}
156
- firstHumanAgentIndex={firstHumanAgentIndex}
157
- onType={scrollToBottom}
158
- />
159
- ));
160
- }, [messages, firstHumanAgentIndex, scrollToBottom]);
161
-
162
- // Memoize loading state check
163
- const isLoading = useMemo(() => {
164
- return (
165
- assistantStatus === 'typing' ||
166
- assistantStatus === 'loading' ||
167
- assistantStatus === 'error' ||
168
- inputMessage.trim() === ''
116
+ // Cleanup timeout on unmount
117
+ useEffect(() => {
118
+ return () => {
119
+ if (scrollTimeoutRef.current) {
120
+ clearTimeout(scrollTimeoutRef.current);
121
+ }
122
+ };
123
+ }, []);
124
+
125
+ const handleSendMessage = useCallback(() => {
126
+ if (inputMessage.trim()) {
127
+ onSendMessage(inputMessage);
128
+ setInputMessage('');
129
+ }
130
+ }, [inputMessage, onSendMessage]);
131
+
132
+ const handleKeyDown = useCallback(
133
+ (e: React.KeyboardEvent) => {
134
+ if (e.key === 'Enter' && !e.shiftKey && isSignalRConnected) {
135
+ e.preventDefault();
136
+ if (inputMessage.trim() && assistantStatus !== 'typing') {
137
+ onSendMessage(inputMessage);
138
+ setInputMessage('');
139
+ }
140
+ }
141
+ },
142
+ [inputMessage, onSendMessage, assistantStatus, isSignalRConnected]
169
143
  );
170
- }, [assistantStatus, inputMessage]);
171
144
 
172
- return (
173
- <>
174
- <div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
175
- {messagesList}
145
+ // Memoize the first human agent index calculation
146
+ const firstHumanAgentIndex = useMemo(() => {
147
+ return messages.findIndex((message) => message.senderType === 2);
148
+ }, [messages]);
149
+
150
+ // Memoize the message list to prevent unnecessary re-renders
151
+ const messagesList = useMemo(() => {
152
+ return messages.map((message, index) => (
153
+ <MessageComponent
154
+ key={`${message.id}-${index}`}
155
+ message={message}
156
+ index={index}
157
+ messages={messages}
158
+ firstHumanAgentIndex={firstHumanAgentIndex}
159
+ onType={scrollToBottom}
160
+ />
161
+ ));
162
+ }, [messages, firstHumanAgentIndex, scrollToBottom]);
163
+
164
+ // Memoize loading state check
165
+ const isLoading = useMemo(() => {
166
+ return (
167
+ assistantStatus === 'typing' ||
168
+ assistantStatus === 'loading' ||
169
+ assistantStatus === 'error' ||
170
+ inputMessage.trim() === ''
171
+ );
172
+ }, [assistantStatus, inputMessage]);
176
173
 
177
- {assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
174
+ return (
175
+ <>
176
+ <div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
177
+ {messagesList}
178
178
 
179
- <div ref={messagesEndRef} />
180
- </div>
179
+ {assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
181
180
 
182
- <ChatWindowFooter
183
- inputMessage={inputMessage}
184
- handleKeyDown={handleKeyDown}
185
- handleSendMessage={handleSendMessage}
186
- setInputMessage={setInputMessage}
187
- isLoading={isLoading}
188
- />
189
- </>
190
- );
191
- });
181
+ <div ref={messagesEndRef} />
182
+ </div>
183
+
184
+ <ChatWindowFooter
185
+ inputMessage={inputMessage}
186
+ handleKeyDown={handleKeyDown}
187
+ handleSendMessage={handleSendMessage}
188
+ setInputMessage={setInputMessage}
189
+ isLoading={isLoading}
190
+ isSignalRConnected={isSignalRConnected}
191
+ />
192
+ </>
193
+ );
194
+ }
195
+ );
192
196
 
193
197
  ChatWindow.displayName = 'ChatWindow';