andy-widget-react 2.0.5
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/README.md +79 -0
- package/dist/index.cjs +4688 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +4658 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/types/AndyChat.d.ts +4 -0
- package/dist/types/components/ChatBubble.d.ts +9 -0
- package/dist/types/components/ChatWindow.d.ts +11 -0
- package/dist/types/components/FAQ.d.ts +8 -0
- package/dist/types/components/MessageInput.d.ts +8 -0
- package/dist/types/components/MessageList.d.ts +10 -0
- package/dist/types/components/UserInfoForm.d.ts +10 -0
- package/dist/types/components/WelcomePopup.d.ts +8 -0
- package/dist/types/hooks/index.d.ts +1 -0
- package/dist/types/hooks/useAndyChat.d.ts +2 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/types/index.d.ts +180 -0
- package/package.json +72 -0
- package/src/AndyChat.tsx +1091 -0
- package/src/components/ChatBubble.tsx +48 -0
- package/src/components/ChatWindow.tsx +53 -0
- package/src/components/FAQ.tsx +48 -0
- package/src/components/MessageInput.tsx +82 -0
- package/src/components/MessageList.tsx +122 -0
- package/src/components/UserInfoForm.tsx +186 -0
- package/src/components/WelcomePopup.tsx +70 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAndyChat.ts +281 -0
- package/src/index.ts +65 -0
- package/src/styles/main.css +14 -0
- package/src/types/index.ts +222 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { useState, useCallback, useRef } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
fetchChatbotConfig,
|
|
4
|
+
generateSessionId,
|
|
5
|
+
createGreetingMessage,
|
|
6
|
+
sendMessage as sendMessageToAPI,
|
|
7
|
+
submitUserInfo as submitUserInfoAPI,
|
|
8
|
+
initializeConfig,
|
|
9
|
+
validateChatbotConfig,
|
|
10
|
+
normalizeConfig,
|
|
11
|
+
CONFIG
|
|
12
|
+
} from 'andy-widget-core'
|
|
13
|
+
import type { ChatbotConfig, Message, UserInfo, UseAndyChatReturn } from '../types'
|
|
14
|
+
|
|
15
|
+
const { SESSION_STORAGE_KEY, FORM_DISPLAY_DELAY_MS, PERSIST_SESSION } = CONFIG
|
|
16
|
+
|
|
17
|
+
export const useAndyChat = (embedId: string): UseAndyChatReturn => {
|
|
18
|
+
initializeConfig('andy-widget-react')
|
|
19
|
+
|
|
20
|
+
const [config, setConfig] = useState<Partial<ChatbotConfig>>({})
|
|
21
|
+
const [isLoading, setIsLoading] = useState(true)
|
|
22
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
23
|
+
const [error, setError] = useState<string | null>(null)
|
|
24
|
+
|
|
25
|
+
const [messages, setMessages] = useState<Message[]>([])
|
|
26
|
+
const [showingFaq, setShowingFaq] = useState(false)
|
|
27
|
+
const [sessionId, setSessionId] = useState(() => generateSessionId())
|
|
28
|
+
|
|
29
|
+
const [userInfoCollected, setUserInfoCollected] = useState(false)
|
|
30
|
+
const [showingWelcomePopup, setShowingWelcomePopup] = useState(false)
|
|
31
|
+
const [showingUserInfoForm, setShowingUserInfoForm] = useState(false)
|
|
32
|
+
const [welcomePopupShown, setWelcomePopupShown] = useState(false)
|
|
33
|
+
|
|
34
|
+
const welcomeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
35
|
+
const userInfoTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
36
|
+
|
|
37
|
+
const initializeChatbot = useCallback(async () => {
|
|
38
|
+
if (!embedId) {
|
|
39
|
+
throw new Error('Embed ID is required')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
setIsLoading(true)
|
|
44
|
+
setError(null)
|
|
45
|
+
|
|
46
|
+
const rawConfig = await fetchChatbotConfig(embedId)
|
|
47
|
+
|
|
48
|
+
const validationResult = validateChatbotConfig(rawConfig)
|
|
49
|
+
if (!validationResult.isValid) {
|
|
50
|
+
throw new Error(`Invalid configuration: ${validationResult.errors.join(', ')}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const normalizedConfig = normalizeConfig(rawConfig as unknown as Record<string, unknown>) as unknown as ChatbotConfig
|
|
54
|
+
setConfig(normalizedConfig)
|
|
55
|
+
|
|
56
|
+
if (PERSIST_SESSION) {
|
|
57
|
+
const storedSessionId = localStorage.getItem(SESSION_STORAGE_KEY)
|
|
58
|
+
if (storedSessionId) {
|
|
59
|
+
setSessionId(storedSessionId)
|
|
60
|
+
} else {
|
|
61
|
+
setSessionId(currentSessionId => {
|
|
62
|
+
localStorage.setItem(SESSION_STORAGE_KEY, currentSessionId)
|
|
63
|
+
return currentSessionId
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (normalizedConfig.welcomeMessage) {
|
|
69
|
+
const greeting = createGreetingMessage(normalizedConfig)
|
|
70
|
+
if (greeting) {
|
|
71
|
+
const greetingMessage: Message = {
|
|
72
|
+
id: Date.now(),
|
|
73
|
+
content: greeting,
|
|
74
|
+
sender: 'bot',
|
|
75
|
+
timestamp: new Date().toISOString()
|
|
76
|
+
}
|
|
77
|
+
setMessages([greetingMessage])
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setIsLoading(false)
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error('Failed to initialize chatbot:', err)
|
|
84
|
+
setError(err instanceof Error ? err.message : 'Unknown error')
|
|
85
|
+
setIsLoading(false)
|
|
86
|
+
throw err
|
|
87
|
+
}
|
|
88
|
+
}, [embedId])
|
|
89
|
+
|
|
90
|
+
const toggleChat = useCallback(() => {
|
|
91
|
+
setIsOpen(prev => {
|
|
92
|
+
const newIsOpen = !prev
|
|
93
|
+
|
|
94
|
+
if (newIsOpen) {
|
|
95
|
+
setShowingFaq(false)
|
|
96
|
+
|
|
97
|
+
const typedConfig = config as ChatbotConfig
|
|
98
|
+
if (typedConfig?.showWelcomePopup?.enabled && !welcomePopupShown) {
|
|
99
|
+
setShowingWelcomePopup(true)
|
|
100
|
+
setWelcomePopupShown(true)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typedConfig?.collectUserInfo?.enabled && !userInfoCollected) {
|
|
104
|
+
if (userInfoTimeoutRef.current) {
|
|
105
|
+
clearTimeout(userInfoTimeoutRef.current)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
userInfoTimeoutRef.current = setTimeout(() => {
|
|
109
|
+
setShowingUserInfoForm(true)
|
|
110
|
+
}, FORM_DISPLAY_DELAY_MS)
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
setShowingWelcomePopup(false)
|
|
114
|
+
setShowingUserInfoForm(false)
|
|
115
|
+
|
|
116
|
+
if (welcomeTimeoutRef.current) {
|
|
117
|
+
clearTimeout(welcomeTimeoutRef.current)
|
|
118
|
+
}
|
|
119
|
+
if (userInfoTimeoutRef.current) {
|
|
120
|
+
clearTimeout(userInfoTimeoutRef.current)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return newIsOpen
|
|
125
|
+
})
|
|
126
|
+
}, [config, welcomePopupShown, userInfoCollected])
|
|
127
|
+
|
|
128
|
+
const sendMessage = useCallback(
|
|
129
|
+
async (messageText: string) => {
|
|
130
|
+
if (!messageText.trim() || !config || !sessionId) {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const userMessage: Message = {
|
|
135
|
+
id: Date.now(),
|
|
136
|
+
content: messageText,
|
|
137
|
+
sender: 'user',
|
|
138
|
+
timestamp: new Date().toISOString()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
setMessages(prev => [...prev, userMessage])
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const response = await sendMessageToAPI(embedId, sessionId, messageText)
|
|
145
|
+
|
|
146
|
+
const botMessage: Message = {
|
|
147
|
+
id: Date.now() + 1,
|
|
148
|
+
content: response || 'I apologize, but I encountered an error processing your request.',
|
|
149
|
+
sender: 'bot',
|
|
150
|
+
timestamp: new Date().toISOString()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
setMessages(prev => [...prev, botMessage])
|
|
154
|
+
|
|
155
|
+
return response
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.error('Error sending message:', err)
|
|
158
|
+
|
|
159
|
+
const errorMessage: Message = {
|
|
160
|
+
id: Date.now() + 1,
|
|
161
|
+
content: 'Sorry, I encountered an error. Please try again.',
|
|
162
|
+
sender: 'bot',
|
|
163
|
+
timestamp: new Date().toISOString(),
|
|
164
|
+
isError: true
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
setMessages(prev => [...prev, errorMessage])
|
|
168
|
+
throw err
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
[embedId, sessionId, config]
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
const showFaq = useCallback(() => {
|
|
175
|
+
setShowingFaq(true)
|
|
176
|
+
}, [])
|
|
177
|
+
|
|
178
|
+
const hideFaq = useCallback(() => {
|
|
179
|
+
setShowingFaq(false)
|
|
180
|
+
}, [])
|
|
181
|
+
|
|
182
|
+
const showWelcomePopup = useCallback(() => {
|
|
183
|
+
setShowingWelcomePopup(true)
|
|
184
|
+
}, [])
|
|
185
|
+
|
|
186
|
+
const hideWelcomePopup = useCallback(() => {
|
|
187
|
+
setShowingWelcomePopup(false)
|
|
188
|
+
}, [])
|
|
189
|
+
|
|
190
|
+
const showUserInfoForm = useCallback(() => {
|
|
191
|
+
setShowingUserInfoForm(true)
|
|
192
|
+
}, [])
|
|
193
|
+
|
|
194
|
+
const hideUserInfoForm = useCallback(() => {
|
|
195
|
+
setShowingUserInfoForm(false)
|
|
196
|
+
}, [])
|
|
197
|
+
|
|
198
|
+
const submitUserInfo = useCallback(
|
|
199
|
+
async (userInfo: UserInfo) => {
|
|
200
|
+
try {
|
|
201
|
+
await submitUserInfoAPI(embedId, sessionId, userInfo)
|
|
202
|
+
setUserInfoCollected(true)
|
|
203
|
+
setShowingUserInfoForm(false)
|
|
204
|
+
|
|
205
|
+
const confirmMessage: Message = {
|
|
206
|
+
id: Date.now(),
|
|
207
|
+
content: 'Thank you for providing your information! How can I help you today?',
|
|
208
|
+
sender: 'bot',
|
|
209
|
+
timestamp: new Date().toISOString()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
setMessages(prev => [...prev, confirmMessage])
|
|
213
|
+
} catch (err) {
|
|
214
|
+
console.error('Error submitting user info:', err)
|
|
215
|
+
throw err
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
[embedId, sessionId]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
const startNewSession = useCallback(() => {
|
|
222
|
+
const newSessionId = generateSessionId()
|
|
223
|
+
setSessionId(newSessionId)
|
|
224
|
+
|
|
225
|
+
if (PERSIST_SESSION) {
|
|
226
|
+
localStorage.setItem(SESSION_STORAGE_KEY, newSessionId)
|
|
227
|
+
} else {
|
|
228
|
+
localStorage.removeItem(SESSION_STORAGE_KEY)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
setMessages([])
|
|
232
|
+
setUserInfoCollected(false)
|
|
233
|
+
setShowingFaq(false)
|
|
234
|
+
setShowingUserInfoForm(false)
|
|
235
|
+
setWelcomePopupShown(false)
|
|
236
|
+
|
|
237
|
+
const typedConfig = config as ChatbotConfig
|
|
238
|
+
if (typedConfig?.welcomeMessage) {
|
|
239
|
+
const greeting = createGreetingMessage(typedConfig)
|
|
240
|
+
if (greeting) {
|
|
241
|
+
const greetingMessage: Message = {
|
|
242
|
+
id: Date.now(),
|
|
243
|
+
content: greeting,
|
|
244
|
+
sender: 'bot',
|
|
245
|
+
timestamp: new Date().toISOString()
|
|
246
|
+
}
|
|
247
|
+
setMessages([greetingMessage])
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}, [config])
|
|
251
|
+
|
|
252
|
+
const addMessage = useCallback((message: Message) => {
|
|
253
|
+
setMessages(prev => [...prev, message])
|
|
254
|
+
}, [])
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
config,
|
|
258
|
+
isLoading,
|
|
259
|
+
isOpen,
|
|
260
|
+
showingFaq,
|
|
261
|
+
showingWelcomePopup,
|
|
262
|
+
showingUserInfoForm,
|
|
263
|
+
messages,
|
|
264
|
+
userInfoCollected,
|
|
265
|
+
sessionId,
|
|
266
|
+
error,
|
|
267
|
+
|
|
268
|
+
initializeChatbot,
|
|
269
|
+
toggleChat,
|
|
270
|
+
sendMessage,
|
|
271
|
+
showFaq,
|
|
272
|
+
hideFaq,
|
|
273
|
+
showWelcomePopup,
|
|
274
|
+
hideWelcomePopup,
|
|
275
|
+
showUserInfoForm,
|
|
276
|
+
hideUserInfoForm,
|
|
277
|
+
submitUserInfo,
|
|
278
|
+
startNewSession,
|
|
279
|
+
addMessage
|
|
280
|
+
}
|
|
281
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Main export for AndyChat React package
|
|
2
|
+
export { default as AndyChat } from './AndyChat'
|
|
3
|
+
// Back-compat: older integrations import { Andy } from 'andy-widget-react'
|
|
4
|
+
export { default as Andy } from './AndyChat'
|
|
5
|
+
|
|
6
|
+
// Export the custom hook for advanced usage
|
|
7
|
+
export { useAndyChat } from './hooks/useAndyChat'
|
|
8
|
+
|
|
9
|
+
// Export individual components for advanced customization
|
|
10
|
+
export { default as ChatBubble } from './components/ChatBubble'
|
|
11
|
+
export { default as ChatWindow } from './components/ChatWindow'
|
|
12
|
+
export { default as MessageList } from './components/MessageList'
|
|
13
|
+
export { default as MessageInput } from './components/MessageInput'
|
|
14
|
+
export { default as FAQ } from './components/FAQ'
|
|
15
|
+
export { default as WelcomePopup } from './components/WelcomePopup'
|
|
16
|
+
export { default as UserInfoForm } from './components/UserInfoForm'
|
|
17
|
+
|
|
18
|
+
// Export types for consumers
|
|
19
|
+
export type {
|
|
20
|
+
AndyChatProps,
|
|
21
|
+
ChatbotConfig,
|
|
22
|
+
Message,
|
|
23
|
+
FAQItem,
|
|
24
|
+
PredefinedQuestion,
|
|
25
|
+
WelcomePopupConfig,
|
|
26
|
+
CollectUserInfoConfig,
|
|
27
|
+
UserInfo,
|
|
28
|
+
UseAndyChatReturn,
|
|
29
|
+
ChatBubbleProps,
|
|
30
|
+
ChatWindowProps,
|
|
31
|
+
MessageListProps,
|
|
32
|
+
MessageInputProps,
|
|
33
|
+
FAQProps,
|
|
34
|
+
WelcomePopupProps,
|
|
35
|
+
UserInfoFormProps,
|
|
36
|
+
FaqItemProps
|
|
37
|
+
} from './types'
|
|
38
|
+
|
|
39
|
+
// Re-export core utilities for React users who need them
|
|
40
|
+
export {
|
|
41
|
+
// Design tokens for custom styling
|
|
42
|
+
theme,
|
|
43
|
+
colors,
|
|
44
|
+
typography,
|
|
45
|
+
spacing,
|
|
46
|
+
borderRadius,
|
|
47
|
+
shadows,
|
|
48
|
+
zIndex,
|
|
49
|
+
animation,
|
|
50
|
+
chat,
|
|
51
|
+
|
|
52
|
+
// Utility functions
|
|
53
|
+
generateSessionId,
|
|
54
|
+
parseMarkdown,
|
|
55
|
+
sanitizeUrl,
|
|
56
|
+
|
|
57
|
+
// Configuration helpers
|
|
58
|
+
isValidEmbedId,
|
|
59
|
+
getEmbedId,
|
|
60
|
+
getApiBaseUrl,
|
|
61
|
+
setApiBaseUrl
|
|
62
|
+
} from 'andy-widget-core'
|
|
63
|
+
|
|
64
|
+
// Default export is the main AndyChat component
|
|
65
|
+
export { default } from './AndyChat'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* AndyChat React Styles */
|
|
2
|
+
/* Placeholder CSS file - can be expanded with custom styles */
|
|
3
|
+
|
|
4
|
+
.andychat-react-container {
|
|
5
|
+
/* Container styles */
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.andychat-bubble {
|
|
9
|
+
/* Chat bubble styles - handled inline for now */
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.andychat-window {
|
|
13
|
+
/* Chat window styles - handled inline for now */
|
|
14
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for andy-widget-react
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Welcome popup configuration
|
|
6
|
+
export interface WelcomePopupConfig {
|
|
7
|
+
enabled: boolean
|
|
8
|
+
seconds: number
|
|
9
|
+
message?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// User info collection configuration
|
|
13
|
+
export interface CollectUserInfoConfig {
|
|
14
|
+
enabled: boolean
|
|
15
|
+
message?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Predefined question
|
|
19
|
+
export interface PredefinedQuestion {
|
|
20
|
+
order: number
|
|
21
|
+
question: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// FAQ item
|
|
25
|
+
export interface FAQItem {
|
|
26
|
+
question: string
|
|
27
|
+
answer: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Core chatbot configuration (matches API response)
|
|
31
|
+
export interface ChatbotConfig {
|
|
32
|
+
id: string | null
|
|
33
|
+
name: string
|
|
34
|
+
theme: 'light' | 'dark' | 'auto'
|
|
35
|
+
logoUrl: string
|
|
36
|
+
headline: string
|
|
37
|
+
brandColor: string
|
|
38
|
+
description: string
|
|
39
|
+
orientation: 'left' | 'right'
|
|
40
|
+
bubbleStyle: 'icon' | 'pill'
|
|
41
|
+
bubbleLabel: string | null
|
|
42
|
+
useBrandColor: boolean
|
|
43
|
+
defaultLang: 'en' | 'es'
|
|
44
|
+
showBranding: boolean
|
|
45
|
+
welcomeMessage: string
|
|
46
|
+
showWelcomePopup: WelcomePopupConfig
|
|
47
|
+
collectUserInfo: CollectUserInfoConfig
|
|
48
|
+
predefinedQuestions: PredefinedQuestion[]
|
|
49
|
+
faqs: FAQItem[]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Message in the chat
|
|
53
|
+
export interface Message {
|
|
54
|
+
id: number
|
|
55
|
+
content: string
|
|
56
|
+
sender: 'user' | 'bot'
|
|
57
|
+
timestamp: string
|
|
58
|
+
isForm?: boolean
|
|
59
|
+
isLoading?: boolean
|
|
60
|
+
isError?: boolean
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// User info for form submission
|
|
64
|
+
export interface UserInfo {
|
|
65
|
+
name: string
|
|
66
|
+
email: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Main AndyChat component props
|
|
70
|
+
export interface AndyChatProps {
|
|
71
|
+
/** Required chatbot embed ID (not required if previewMode is true) */
|
|
72
|
+
embedId?: string
|
|
73
|
+
/** Optional tooltip text for the chat bubble */
|
|
74
|
+
tooltip?: string
|
|
75
|
+
/** Optional bot name (overrides API value) */
|
|
76
|
+
name?: string
|
|
77
|
+
/** Optional headline/subtitle (overrides API value) */
|
|
78
|
+
headline?: string
|
|
79
|
+
/** Optional description (overrides API value) */
|
|
80
|
+
description?: string
|
|
81
|
+
/** Optional welcome message (overrides API value) */
|
|
82
|
+
welcomeMessage?: string
|
|
83
|
+
/** Optional custom label for pill-style bubble (overrides default) */
|
|
84
|
+
bubbleLabel?: string
|
|
85
|
+
/** Optional theme ('light' | 'dark' | 'auto') */
|
|
86
|
+
theme?: 'light' | 'dark' | 'auto'
|
|
87
|
+
/** Optional position ('left' | 'right') */
|
|
88
|
+
orientation?: 'left' | 'right'
|
|
89
|
+
/** Optional brand color hex (e.g., '#3B82F6') */
|
|
90
|
+
brandColor?: string
|
|
91
|
+
/** Optional bubble style ('icon' | 'pill') */
|
|
92
|
+
bubbleStyle?: 'icon' | 'pill'
|
|
93
|
+
/** Optional whether to use brand color */
|
|
94
|
+
useBrandColor?: boolean
|
|
95
|
+
/** Optional logo URL */
|
|
96
|
+
logoUrl?: string
|
|
97
|
+
/** If true, skip API fetch and use props directly as config */
|
|
98
|
+
previewMode?: boolean
|
|
99
|
+
/** If true, start with chat window open */
|
|
100
|
+
initialOpen?: boolean
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// FAQ Item component props
|
|
104
|
+
export interface FaqItemProps {
|
|
105
|
+
question: string
|
|
106
|
+
answer: string
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Chat Bubble component props
|
|
110
|
+
export interface ChatBubbleProps {
|
|
111
|
+
isOpen: boolean
|
|
112
|
+
onClick: () => void
|
|
113
|
+
tooltip?: string
|
|
114
|
+
logoUrl?: string
|
|
115
|
+
bubbleStyle?: 'icon' | 'pill'
|
|
116
|
+
bubbleLabel?: string
|
|
117
|
+
theme?: 'light' | 'dark' | 'auto'
|
|
118
|
+
useBrandColor?: boolean
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Chat Window component props
|
|
122
|
+
export interface ChatWindowProps {
|
|
123
|
+
isOpen: boolean
|
|
124
|
+
config: ChatbotConfig | null
|
|
125
|
+
messages: Message[]
|
|
126
|
+
isLoading: boolean
|
|
127
|
+
showPredefinedQuestions: boolean
|
|
128
|
+
isCollectingUserInfo: boolean
|
|
129
|
+
onClose: () => void
|
|
130
|
+
onSendMessage: (message: string) => void
|
|
131
|
+
onPredefinedQuestion: (question: string) => void
|
|
132
|
+
onUserInfoSubmit: (e: React.FormEvent<HTMLFormElement>) => void
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Message List component props
|
|
136
|
+
export interface MessageListProps {
|
|
137
|
+
messages: Message[]
|
|
138
|
+
config: ChatbotConfig | null
|
|
139
|
+
isLoading: boolean
|
|
140
|
+
isCollectingUserInfo: boolean
|
|
141
|
+
onUserInfoSubmit: (e: React.FormEvent<HTMLFormElement>) => void
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Message Input component props
|
|
145
|
+
export interface MessageInputProps {
|
|
146
|
+
onSendMessage: (message: string) => void
|
|
147
|
+
disabled?: boolean
|
|
148
|
+
placeholder?: string
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// FAQ component props
|
|
152
|
+
export interface FAQProps {
|
|
153
|
+
faqs: FAQItem[]
|
|
154
|
+
onBack: () => void
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Welcome Popup component props
|
|
158
|
+
export interface WelcomePopupProps {
|
|
159
|
+
message: string
|
|
160
|
+
orientation?: 'left' | 'right'
|
|
161
|
+
onClose: () => void
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// User Info Form component props
|
|
165
|
+
export interface UserInfoFormProps {
|
|
166
|
+
message?: string
|
|
167
|
+
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// useAndyChat hook return type
|
|
171
|
+
export interface UseAndyChatReturn {
|
|
172
|
+
// State
|
|
173
|
+
config: Partial<ChatbotConfig>
|
|
174
|
+
isLoading: boolean
|
|
175
|
+
isOpen: boolean
|
|
176
|
+
showingFaq: boolean
|
|
177
|
+
showingWelcomePopup: boolean
|
|
178
|
+
showingUserInfoForm: boolean
|
|
179
|
+
messages: Message[]
|
|
180
|
+
userInfoCollected: boolean
|
|
181
|
+
sessionId: string
|
|
182
|
+
error: string | null
|
|
183
|
+
|
|
184
|
+
// Actions
|
|
185
|
+
initializeChatbot: () => Promise<void>
|
|
186
|
+
toggleChat: () => void
|
|
187
|
+
sendMessage: (messageText: string) => Promise<unknown>
|
|
188
|
+
showFaq: () => void
|
|
189
|
+
hideFaq: () => void
|
|
190
|
+
showWelcomePopup: () => void
|
|
191
|
+
hideWelcomePopup: () => void
|
|
192
|
+
showUserInfoForm: () => void
|
|
193
|
+
hideUserInfoForm: () => void
|
|
194
|
+
submitUserInfo: (userInfo: UserInfo) => Promise<void>
|
|
195
|
+
startNewSession: () => void
|
|
196
|
+
addMessage: (message: Message) => void
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Stylesheet options for getFullStylesheet
|
|
200
|
+
export interface StylesheetOptions {
|
|
201
|
+
color?: string
|
|
202
|
+
useBrandColor?: boolean
|
|
203
|
+
theme?: 'light' | 'dark' | 'auto'
|
|
204
|
+
orientation?: 'left' | 'right'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Host class options for getHostClasses
|
|
208
|
+
export interface HostClassOptions {
|
|
209
|
+
theme?: 'light' | 'dark' | 'auto'
|
|
210
|
+
orientation?: 'left' | 'right'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Keyboard detector listener callback
|
|
214
|
+
export interface KeyboardListenerCallback {
|
|
215
|
+
(state: { isOpen: boolean; height: number }): void
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Keyboard detector interface
|
|
219
|
+
export interface KeyboardDetector {
|
|
220
|
+
addListener: (callback: KeyboardListenerCallback) => void
|
|
221
|
+
removeListener: (callback: KeyboardListenerCallback) => void
|
|
222
|
+
}
|