@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.
- package/dist/index.esm.js +41 -219
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +41 -219
- package/dist/index.js.map +1 -1
- package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +1 -0
- package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +2 -1
- package/dist/ui/help-popup.d.ts +1 -1
- package/package.json +1 -1
- package/src/lib/config.ts +0 -6
- package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +21 -20
- package/src/ui/chatbot-popup/chat-window-screen/index.tsx +100 -96
- package/src/ui/help-center.tsx +38 -238
- package/src/ui/help-popup.tsx +3 -1
|
@@ -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 {};
|
package/dist/ui/help-popup.d.ts
CHANGED
|
@@ -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
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=
|
|
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=
|
|
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=
|
|
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=
|
|
28
|
-
size=
|
|
28
|
+
variant='default'
|
|
29
|
+
size='icon'
|
|
29
30
|
onClick={props.handleSendMessage}
|
|
30
|
-
disabled={props?.isLoading}
|
|
31
|
-
className=
|
|
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(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
174
|
+
return (
|
|
175
|
+
<>
|
|
176
|
+
<div className='babylai-flex-1 babylai-overflow-y-auto babylai-p-4 babylai-h-full'>
|
|
177
|
+
{messagesList}
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
</div>
|
|
179
|
+
{assistantStatus === 'typing' && <TypingIndicator firstHumanAgentIndex={firstHumanAgentIndex} />}
|
|
181
180
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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';
|