@uselingu/react-native-sdk 0.1.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.
- package/README.md +279 -0
- package/lib/commonjs/components/LinguChat.js +283 -0
- package/lib/commonjs/components/LinguChat.js.map +1 -0
- package/lib/commonjs/components/LinguWebView.js +203 -0
- package/lib/commonjs/components/LinguWebView.js.map +1 -0
- package/lib/commonjs/components/MessageBubble.js +91 -0
- package/lib/commonjs/components/MessageBubble.js.map +1 -0
- package/lib/commonjs/components/NativeChatUI.js +192 -0
- package/lib/commonjs/components/NativeChatUI.js.map +1 -0
- package/lib/commonjs/components/TypingIndicator.js +92 -0
- package/lib/commonjs/components/TypingIndicator.js.map +1 -0
- package/lib/commonjs/context/LinguProvider.js +47 -0
- package/lib/commonjs/context/LinguProvider.js.map +1 -0
- package/lib/commonjs/context/index.js +17 -0
- package/lib/commonjs/context/index.js.map +1 -0
- package/lib/commonjs/hooks/useLinguChat.js +295 -0
- package/lib/commonjs/hooks/useLinguChat.js.map +1 -0
- package/lib/commonjs/index.js +129 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/services/LinguAPI.js +196 -0
- package/lib/commonjs/services/LinguAPI.js.map +1 -0
- package/lib/commonjs/services/SessionManager.js +131 -0
- package/lib/commonjs/services/SessionManager.js.map +1 -0
- package/lib/commonjs/services/StorageManager.js +116 -0
- package/lib/commonjs/services/StorageManager.js.map +1 -0
- package/lib/commonjs/theme/ThemeProvider.js +49 -0
- package/lib/commonjs/theme/ThemeProvider.js.map +1 -0
- package/lib/commonjs/theme/index.js +28 -0
- package/lib/commonjs/theme/index.js.map +1 -0
- package/lib/commonjs/theme/theme.js +150 -0
- package/lib/commonjs/theme/theme.js.map +1 -0
- package/lib/commonjs/types/index.js +2 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/utils/animations.js +118 -0
- package/lib/commonjs/utils/animations.js.map +1 -0
- package/lib/commonjs/utils/formatters.js +89 -0
- package/lib/commonjs/utils/formatters.js.map +1 -0
- package/lib/commonjs/utils/index.js +28 -0
- package/lib/commonjs/utils/index.js.map +1 -0
- package/lib/module/components/LinguChat.js +277 -0
- package/lib/module/components/LinguChat.js.map +1 -0
- package/lib/module/components/LinguWebView.js +195 -0
- package/lib/module/components/LinguWebView.js.map +1 -0
- package/lib/module/components/MessageBubble.js +83 -0
- package/lib/module/components/MessageBubble.js.map +1 -0
- package/lib/module/components/NativeChatUI.js +184 -0
- package/lib/module/components/NativeChatUI.js.map +1 -0
- package/lib/module/components/TypingIndicator.js +84 -0
- package/lib/module/components/TypingIndicator.js.map +1 -0
- package/lib/module/context/LinguProvider.js +38 -0
- package/lib/module/context/LinguProvider.js.map +1 -0
- package/lib/module/context/index.js +6 -0
- package/lib/module/context/index.js.map +1 -0
- package/lib/module/hooks/useLinguChat.js +288 -0
- package/lib/module/hooks/useLinguChat.js.map +1 -0
- package/lib/module/index.js +30 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/services/LinguAPI.js +190 -0
- package/lib/module/services/LinguAPI.js.map +1 -0
- package/lib/module/services/SessionManager.js +124 -0
- package/lib/module/services/SessionManager.js.map +1 -0
- package/lib/module/services/StorageManager.js +108 -0
- package/lib/module/services/StorageManager.js.map +1 -0
- package/lib/module/theme/ThemeProvider.js +40 -0
- package/lib/module/theme/ThemeProvider.js.map +1 -0
- package/lib/module/theme/index.js +7 -0
- package/lib/module/theme/index.js.map +1 -0
- package/lib/module/theme/theme.js +142 -0
- package/lib/module/theme/theme.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/utils/animations.js +106 -0
- package/lib/module/utils/animations.js.map +1 -0
- package/lib/module/utils/formatters.js +78 -0
- package/lib/module/utils/formatters.js.map +1 -0
- package/lib/module/utils/index.js +7 -0
- package/lib/module/utils/index.js.map +1 -0
- package/lib/typescript/components/LinguChat.d.ts +18 -0
- package/lib/typescript/components/LinguChat.d.ts.map +1 -0
- package/lib/typescript/components/LinguWebView.d.ts +16 -0
- package/lib/typescript/components/LinguWebView.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble.d.ts +13 -0
- package/lib/typescript/components/MessageBubble.d.ts.map +1 -0
- package/lib/typescript/components/NativeChatUI.d.ts +16 -0
- package/lib/typescript/components/NativeChatUI.d.ts.map +1 -0
- package/lib/typescript/components/TypingIndicator.d.ts +7 -0
- package/lib/typescript/components/TypingIndicator.d.ts.map +1 -0
- package/lib/typescript/context/LinguProvider.d.ts +32 -0
- package/lib/typescript/context/LinguProvider.d.ts.map +1 -0
- package/lib/typescript/context/index.d.ts +5 -0
- package/lib/typescript/context/index.d.ts.map +1 -0
- package/lib/typescript/hooks/useLinguChat.d.ts +18 -0
- package/lib/typescript/hooks/useLinguChat.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +19 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/services/LinguAPI.d.ts +39 -0
- package/lib/typescript/services/LinguAPI.d.ts.map +1 -0
- package/lib/typescript/services/SessionManager.d.ts +46 -0
- package/lib/typescript/services/SessionManager.d.ts.map +1 -0
- package/lib/typescript/services/StorageManager.d.ts +36 -0
- package/lib/typescript/services/StorageManager.d.ts.map +1 -0
- package/lib/typescript/theme/ThemeProvider.d.ts +23 -0
- package/lib/typescript/theme/ThemeProvider.d.ts.map +1 -0
- package/lib/typescript/theme/index.d.ts +6 -0
- package/lib/typescript/theme/index.d.ts.map +1 -0
- package/lib/typescript/theme/theme.d.ts +130 -0
- package/lib/typescript/theme/theme.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +50 -0
- package/lib/typescript/types/index.d.ts.map +1 -0
- package/lib/typescript/utils/animations.d.ts +34 -0
- package/lib/typescript/utils/animations.d.ts.map +1 -0
- package/lib/typescript/utils/formatters.d.ts +25 -0
- package/lib/typescript/utils/formatters.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +6 -0
- package/lib/typescript/utils/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/src/components/LinguChat.tsx +309 -0
- package/src/components/LinguWebView.tsx +216 -0
- package/src/components/MessageBubble.tsx +120 -0
- package/src/components/NativeChatUI.tsx +247 -0
- package/src/components/TypingIndicator.tsx +84 -0
- package/src/context/LinguProvider.tsx +53 -0
- package/src/context/index.ts +5 -0
- package/src/hooks/useLinguChat.ts +314 -0
- package/src/index.ts +43 -0
- package/src/services/LinguAPI.ts +214 -0
- package/src/services/SessionManager.ts +131 -0
- package/src/services/StorageManager.ts +111 -0
- package/src/theme/ThemeProvider.tsx +58 -0
- package/src/theme/index.ts +6 -0
- package/src/theme/theme.ts +254 -0
- package/src/types/index.ts +59 -0
- package/src/utils/animations.ts +141 -0
- package/src/utils/formatters.ts +80 -0
- package/src/utils/index.ts +6 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Chat UI Component
|
|
3
|
+
* Pure React Native implementation without WebView
|
|
4
|
+
* Now with theme support and enhanced styling
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
8
|
+
import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet, KeyboardAvoidingView, Platform } from 'react-native';
|
|
9
|
+
import { useTheme } from '../theme';
|
|
10
|
+
import { MessageBubble } from './MessageBubble';
|
|
11
|
+
import { TypingIndicator } from './TypingIndicator';
|
|
12
|
+
const LOG_PREFIX = '[NativeChatUI]';
|
|
13
|
+
export const NativeChatUI = ({
|
|
14
|
+
config,
|
|
15
|
+
messages,
|
|
16
|
+
isLoading,
|
|
17
|
+
onSendMessage
|
|
18
|
+
}) => {
|
|
19
|
+
const {
|
|
20
|
+
theme
|
|
21
|
+
} = useTheme();
|
|
22
|
+
const [inputText, setInputText] = useState('');
|
|
23
|
+
const flatListRef = useRef(null);
|
|
24
|
+
console.log(`${LOG_PREFIX} Rendering with ${messages.length} messages`);
|
|
25
|
+
|
|
26
|
+
// Auto-scroll to bottom when new messages arrive
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (messages.length > 0 && flatListRef.current) {
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
var _flatListRef$current;
|
|
31
|
+
(_flatListRef$current = flatListRef.current) === null || _flatListRef$current === void 0 || _flatListRef$current.scrollToEnd({
|
|
32
|
+
animated: true
|
|
33
|
+
});
|
|
34
|
+
}, 100);
|
|
35
|
+
}
|
|
36
|
+
}, [messages]);
|
|
37
|
+
const handleSend = () => {
|
|
38
|
+
if (inputText.trim()) {
|
|
39
|
+
console.log(`${LOG_PREFIX} Sending message:`, inputText);
|
|
40
|
+
onSendMessage(inputText.trim());
|
|
41
|
+
setInputText('');
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const renderMessage = ({
|
|
45
|
+
item
|
|
46
|
+
}) => {
|
|
47
|
+
return /*#__PURE__*/React.createElement(MessageBubble, {
|
|
48
|
+
message: item,
|
|
49
|
+
showTimestamp: false
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const renderEmpty = () => /*#__PURE__*/React.createElement(View, {
|
|
53
|
+
style: styles.emptyContainer
|
|
54
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
55
|
+
style: [styles.greetingText, {
|
|
56
|
+
color: theme.colors.gray500,
|
|
57
|
+
fontSize: theme.typography.fontSizes.base
|
|
58
|
+
}]
|
|
59
|
+
}, (config === null || config === void 0 ? void 0 : config.greetingMessage) || 'Hello! How can I help you today?'));
|
|
60
|
+
const renderFooter = () => {
|
|
61
|
+
if (isLoading) {
|
|
62
|
+
return /*#__PURE__*/React.createElement(TypingIndicator, null);
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
};
|
|
66
|
+
const charCount = inputText.length;
|
|
67
|
+
const maxChars = 5000;
|
|
68
|
+
const showCharCount = charCount > maxChars * 0.8;
|
|
69
|
+
return /*#__PURE__*/React.createElement(KeyboardAvoidingView, {
|
|
70
|
+
style: [styles.container, {
|
|
71
|
+
backgroundColor: theme.colors.background
|
|
72
|
+
}],
|
|
73
|
+
behavior: Platform.OS === 'ios' ? 'padding' : undefined,
|
|
74
|
+
keyboardVerticalOffset: Platform.OS === 'ios' ? 90 : 0
|
|
75
|
+
}, /*#__PURE__*/React.createElement(FlatList, {
|
|
76
|
+
ref: flatListRef,
|
|
77
|
+
data: messages,
|
|
78
|
+
renderItem: renderMessage,
|
|
79
|
+
keyExtractor: item => item.id,
|
|
80
|
+
contentContainerStyle: [styles.messagesList, {
|
|
81
|
+
padding: theme.spacing.lg
|
|
82
|
+
}],
|
|
83
|
+
ListEmptyComponent: renderEmpty,
|
|
84
|
+
ListFooterComponent: renderFooter,
|
|
85
|
+
showsVerticalScrollIndicator: false
|
|
86
|
+
}), /*#__PURE__*/React.createElement(View, {
|
|
87
|
+
style: [styles.inputContainer, {
|
|
88
|
+
backgroundColor: theme.colors.background,
|
|
89
|
+
borderTopColor: theme.colors.inputBorder,
|
|
90
|
+
padding: theme.spacing.lg
|
|
91
|
+
}]
|
|
92
|
+
}, /*#__PURE__*/React.createElement(TextInput, {
|
|
93
|
+
style: [styles.input, {
|
|
94
|
+
backgroundColor: theme.colors.inputBackground,
|
|
95
|
+
borderColor: theme.colors.inputBorder,
|
|
96
|
+
color: theme.colors.inputText,
|
|
97
|
+
fontSize: theme.typography.fontSizes.base,
|
|
98
|
+
borderRadius: theme.borderRadius.xl,
|
|
99
|
+
paddingHorizontal: theme.spacing.lg,
|
|
100
|
+
paddingVertical: theme.spacing.sm + 2,
|
|
101
|
+
marginRight: theme.spacing.sm
|
|
102
|
+
}],
|
|
103
|
+
value: inputText,
|
|
104
|
+
onChangeText: setInputText,
|
|
105
|
+
placeholder: "Type a message...",
|
|
106
|
+
placeholderTextColor: theme.colors.gray400,
|
|
107
|
+
multiline: true,
|
|
108
|
+
maxLength: maxChars,
|
|
109
|
+
onSubmitEditing: handleSend,
|
|
110
|
+
returnKeyType: "send",
|
|
111
|
+
blurOnSubmit: false
|
|
112
|
+
}), /*#__PURE__*/React.createElement(TouchableOpacity, {
|
|
113
|
+
style: [styles.sendButton, {
|
|
114
|
+
backgroundColor: theme.colors.primary,
|
|
115
|
+
borderRadius: theme.borderRadius.xl,
|
|
116
|
+
paddingHorizontal: theme.spacing.lg,
|
|
117
|
+
paddingVertical: theme.spacing.sm + 2
|
|
118
|
+
}, !inputText.trim() && styles.sendButtonDisabled],
|
|
119
|
+
onPress: handleSend,
|
|
120
|
+
disabled: !inputText.trim() || isLoading
|
|
121
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
122
|
+
style: [styles.sendButtonText, {
|
|
123
|
+
fontSize: theme.typography.fontSizes.base,
|
|
124
|
+
fontWeight: theme.typography.fontWeights.semibold
|
|
125
|
+
}]
|
|
126
|
+
}, "Send"))), showCharCount && /*#__PURE__*/React.createElement(View, {
|
|
127
|
+
style: [styles.charCountContainer, {
|
|
128
|
+
paddingHorizontal: theme.spacing.lg
|
|
129
|
+
}]
|
|
130
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
131
|
+
style: [styles.charCount, {
|
|
132
|
+
color: charCount >= maxChars ? theme.colors.errorText : theme.colors.gray500,
|
|
133
|
+
fontSize: theme.typography.fontSizes.xs
|
|
134
|
+
}]
|
|
135
|
+
}, charCount, "/", maxChars)));
|
|
136
|
+
};
|
|
137
|
+
const styles = StyleSheet.create({
|
|
138
|
+
container: {
|
|
139
|
+
flex: 1
|
|
140
|
+
},
|
|
141
|
+
messagesList: {
|
|
142
|
+
flexGrow: 1
|
|
143
|
+
},
|
|
144
|
+
emptyContainer: {
|
|
145
|
+
flex: 1,
|
|
146
|
+
justifyContent: 'center',
|
|
147
|
+
alignItems: 'center',
|
|
148
|
+
padding: 32
|
|
149
|
+
},
|
|
150
|
+
greetingText: {
|
|
151
|
+
textAlign: 'center'
|
|
152
|
+
},
|
|
153
|
+
inputContainer: {
|
|
154
|
+
flexDirection: 'row',
|
|
155
|
+
borderTopWidth: 1,
|
|
156
|
+
alignItems: 'flex-end'
|
|
157
|
+
},
|
|
158
|
+
input: {
|
|
159
|
+
flex: 1,
|
|
160
|
+
minHeight: 40,
|
|
161
|
+
maxHeight: 100,
|
|
162
|
+
borderWidth: 1
|
|
163
|
+
},
|
|
164
|
+
sendButton: {
|
|
165
|
+
justifyContent: 'center',
|
|
166
|
+
alignItems: 'center',
|
|
167
|
+
minWidth: 70
|
|
168
|
+
},
|
|
169
|
+
sendButtonDisabled: {
|
|
170
|
+
opacity: 0.5
|
|
171
|
+
},
|
|
172
|
+
sendButtonText: {
|
|
173
|
+
color: '#ffffff'
|
|
174
|
+
},
|
|
175
|
+
charCountContainer: {
|
|
176
|
+
position: 'absolute',
|
|
177
|
+
bottom: 70,
|
|
178
|
+
right: 0
|
|
179
|
+
},
|
|
180
|
+
charCount: {
|
|
181
|
+
textAlign: 'right'
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=NativeChatUI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useState","useRef","useEffect","View","Text","TextInput","TouchableOpacity","FlatList","StyleSheet","KeyboardAvoidingView","Platform","useTheme","MessageBubble","TypingIndicator","LOG_PREFIX","NativeChatUI","config","messages","isLoading","onSendMessage","theme","inputText","setInputText","flatListRef","console","log","length","current","setTimeout","_flatListRef$current","scrollToEnd","animated","handleSend","trim","renderMessage","item","createElement","message","showTimestamp","renderEmpty","style","styles","emptyContainer","greetingText","color","colors","gray500","fontSize","typography","fontSizes","base","greetingMessage","renderFooter","charCount","maxChars","showCharCount","container","backgroundColor","background","behavior","OS","undefined","keyboardVerticalOffset","ref","data","renderItem","keyExtractor","id","contentContainerStyle","messagesList","padding","spacing","lg","ListEmptyComponent","ListFooterComponent","showsVerticalScrollIndicator","inputContainer","borderTopColor","inputBorder","input","inputBackground","borderColor","borderRadius","xl","paddingHorizontal","paddingVertical","sm","marginRight","value","onChangeText","placeholder","placeholderTextColor","gray400","multiline","maxLength","onSubmitEditing","returnKeyType","blurOnSubmit","sendButton","primary","sendButtonDisabled","onPress","disabled","sendButtonText","fontWeight","fontWeights","semibold","charCountContainer","errorText","xs","create","flex","flexGrow","justifyContent","alignItems","textAlign","flexDirection","borderTopWidth","minHeight","maxHeight","borderWidth","minWidth","opacity","position","bottom","right"],"sources":["NativeChatUI.tsx"],"sourcesContent":["/**\n * Native Chat UI Component\n * Pure React Native implementation without WebView\n * Now with theme support and enhanced styling\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport {\n View,\n Text,\n TextInput,\n TouchableOpacity,\n FlatList,\n StyleSheet,\n KeyboardAvoidingView,\n Platform,\n} from 'react-native';\nimport { useTheme } from '../theme';\nimport { MessageBubble } from './MessageBubble';\nimport { TypingIndicator } from './TypingIndicator';\nimport type { Message, WidgetConfig } from '../types';\n\nconst LOG_PREFIX = '[NativeChatUI]';\n\ninterface NativeChatUIProps {\n config: WidgetConfig | null;\n messages: Message[];\n isLoading: boolean;\n onSendMessage: (message: string) => void;\n}\n\nexport const NativeChatUI: React.FC<NativeChatUIProps> = ({\n config,\n messages,\n isLoading,\n onSendMessage,\n}) => {\n const { theme } = useTheme();\n const [inputText, setInputText] = useState('');\n const flatListRef = useRef<FlatList>(null);\n\n console.log(`${LOG_PREFIX} Rendering with ${messages.length} messages`);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (messages.length > 0 && flatListRef.current) {\n setTimeout(() => {\n flatListRef.current?.scrollToEnd({ animated: true });\n }, 100);\n }\n }, [messages]);\n\n const handleSend = () => {\n if (inputText.trim()) {\n console.log(`${LOG_PREFIX} Sending message:`, inputText);\n onSendMessage(inputText.trim());\n setInputText('');\n }\n };\n\n const renderMessage = ({ item }: { item: Message }) => {\n return <MessageBubble message={item} showTimestamp={false} />;\n };\n\n const renderEmpty = () => (\n <View style={styles.emptyContainer}>\n <Text\n style={[\n styles.greetingText,\n {\n color: theme.colors.gray500,\n fontSize: theme.typography.fontSizes.base,\n },\n ]}\n >\n {config?.greetingMessage || 'Hello! How can I help you today?'}\n </Text>\n </View>\n );\n\n const renderFooter = () => {\n if (isLoading) {\n return <TypingIndicator />;\n }\n return null;\n };\n\n const charCount = inputText.length;\n const maxChars = 5000;\n const showCharCount = charCount > maxChars * 0.8;\n\n return (\n <KeyboardAvoidingView\n style={[styles.container, { backgroundColor: theme.colors.background }]}\n behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n keyboardVerticalOffset={Platform.OS === 'ios' ? 90 : 0}\n >\n {/* Messages List */}\n <FlatList\n ref={flatListRef}\n data={messages}\n renderItem={renderMessage}\n keyExtractor={(item) => item.id}\n contentContainerStyle={[\n styles.messagesList,\n { padding: theme.spacing.lg },\n ]}\n ListEmptyComponent={renderEmpty}\n ListFooterComponent={renderFooter}\n showsVerticalScrollIndicator={false}\n />\n\n {/* Input Area */}\n <View\n style={[\n styles.inputContainer,\n {\n backgroundColor: theme.colors.background,\n borderTopColor: theme.colors.inputBorder,\n padding: theme.spacing.lg,\n },\n ]}\n >\n <TextInput\n style={[\n styles.input,\n {\n backgroundColor: theme.colors.inputBackground,\n borderColor: theme.colors.inputBorder,\n color: theme.colors.inputText,\n fontSize: theme.typography.fontSizes.base,\n borderRadius: theme.borderRadius.xl,\n paddingHorizontal: theme.spacing.lg,\n paddingVertical: theme.spacing.sm + 2,\n marginRight: theme.spacing.sm,\n },\n ]}\n value={inputText}\n onChangeText={setInputText}\n placeholder=\"Type a message...\"\n placeholderTextColor={theme.colors.gray400}\n multiline\n maxLength={maxChars}\n onSubmitEditing={handleSend}\n returnKeyType=\"send\"\n blurOnSubmit={false}\n />\n <TouchableOpacity\n style={[\n styles.sendButton,\n {\n backgroundColor: theme.colors.primary,\n borderRadius: theme.borderRadius.xl,\n paddingHorizontal: theme.spacing.lg,\n paddingVertical: theme.spacing.sm + 2,\n },\n !inputText.trim() && styles.sendButtonDisabled,\n ]}\n onPress={handleSend}\n disabled={!inputText.trim() || isLoading}\n >\n <Text\n style={[\n styles.sendButtonText,\n {\n fontSize: theme.typography.fontSizes.base,\n fontWeight: theme.typography.fontWeights.semibold,\n },\n ]}\n >\n Send\n </Text>\n </TouchableOpacity>\n </View>\n\n {/* Character count */}\n {showCharCount && (\n <View\n style={[\n styles.charCountContainer,\n { paddingHorizontal: theme.spacing.lg },\n ]}\n >\n <Text\n style={[\n styles.charCount,\n {\n color: charCount >= maxChars ? theme.colors.errorText : theme.colors.gray500,\n fontSize: theme.typography.fontSizes.xs,\n },\n ]}\n >\n {charCount}/{maxChars}\n </Text>\n </View>\n )}\n </KeyboardAvoidingView>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n messagesList: {\n flexGrow: 1,\n },\n emptyContainer: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n padding: 32,\n },\n greetingText: {\n textAlign: 'center',\n },\n inputContainer: {\n flexDirection: 'row',\n borderTopWidth: 1,\n alignItems: 'flex-end',\n },\n input: {\n flex: 1,\n minHeight: 40,\n maxHeight: 100,\n borderWidth: 1,\n },\n sendButton: {\n justifyContent: 'center',\n alignItems: 'center',\n minWidth: 70,\n },\n sendButtonDisabled: {\n opacity: 0.5,\n },\n sendButtonText: {\n color: '#ffffff',\n },\n charCountContainer: {\n position: 'absolute',\n bottom: 70,\n right: 0,\n },\n charCount: {\n textAlign: 'right',\n },\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typing Indicator Component
|
|
3
|
+
* Animated dots to show bot is typing
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useEffect, useRef } from 'react';
|
|
7
|
+
import { View, Animated, StyleSheet } from 'react-native';
|
|
8
|
+
import { useTheme } from '../theme';
|
|
9
|
+
import { typingDotAnimation } from '../utils/animations';
|
|
10
|
+
export const TypingIndicator = () => {
|
|
11
|
+
const {
|
|
12
|
+
theme
|
|
13
|
+
} = useTheme();
|
|
14
|
+
const dot1 = useRef(new Animated.Value(0)).current;
|
|
15
|
+
const dot2 = useRef(new Animated.Value(0)).current;
|
|
16
|
+
const dot3 = useRef(new Animated.Value(0)).current;
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
// Start animations with staggered delays
|
|
19
|
+
const anim1 = typingDotAnimation(dot1, 0);
|
|
20
|
+
const anim2 = typingDotAnimation(dot2, 150);
|
|
21
|
+
const anim3 = typingDotAnimation(dot3, 300);
|
|
22
|
+
anim1.start();
|
|
23
|
+
anim2.start();
|
|
24
|
+
anim3.start();
|
|
25
|
+
return () => {
|
|
26
|
+
anim1.stop();
|
|
27
|
+
anim2.stop();
|
|
28
|
+
anim3.stop();
|
|
29
|
+
};
|
|
30
|
+
}, []);
|
|
31
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
32
|
+
style: [styles.container, {
|
|
33
|
+
backgroundColor: theme.colors.botBubble
|
|
34
|
+
}]
|
|
35
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
36
|
+
style: styles.dotsContainer
|
|
37
|
+
}, /*#__PURE__*/React.createElement(Animated.View, {
|
|
38
|
+
style: [styles.dot, {
|
|
39
|
+
backgroundColor: theme.colors.gray400
|
|
40
|
+
}, {
|
|
41
|
+
transform: [{
|
|
42
|
+
translateY: dot1
|
|
43
|
+
}]
|
|
44
|
+
}]
|
|
45
|
+
}), /*#__PURE__*/React.createElement(Animated.View, {
|
|
46
|
+
style: [styles.dot, {
|
|
47
|
+
backgroundColor: theme.colors.gray400
|
|
48
|
+
}, {
|
|
49
|
+
transform: [{
|
|
50
|
+
translateY: dot2
|
|
51
|
+
}]
|
|
52
|
+
}]
|
|
53
|
+
}), /*#__PURE__*/React.createElement(Animated.View, {
|
|
54
|
+
style: [styles.dot, {
|
|
55
|
+
backgroundColor: theme.colors.gray400
|
|
56
|
+
}, {
|
|
57
|
+
transform: [{
|
|
58
|
+
translateY: dot3
|
|
59
|
+
}]
|
|
60
|
+
}]
|
|
61
|
+
})));
|
|
62
|
+
};
|
|
63
|
+
const styles = StyleSheet.create({
|
|
64
|
+
container: {
|
|
65
|
+
maxWidth: '75%',
|
|
66
|
+
padding: 12,
|
|
67
|
+
borderRadius: 16,
|
|
68
|
+
borderBottomLeftRadius: 4,
|
|
69
|
+
marginBottom: 12
|
|
70
|
+
},
|
|
71
|
+
dotsContainer: {
|
|
72
|
+
flexDirection: 'row',
|
|
73
|
+
alignItems: 'center',
|
|
74
|
+
justifyContent: 'center',
|
|
75
|
+
height: 20
|
|
76
|
+
},
|
|
77
|
+
dot: {
|
|
78
|
+
width: 8,
|
|
79
|
+
height: 8,
|
|
80
|
+
borderRadius: 4,
|
|
81
|
+
marginHorizontal: 3
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=TypingIndicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useEffect","useRef","View","Animated","StyleSheet","useTheme","typingDotAnimation","TypingIndicator","theme","dot1","Value","current","dot2","dot3","anim1","anim2","anim3","start","stop","createElement","style","styles","container","backgroundColor","colors","botBubble","dotsContainer","dot","gray400","transform","translateY","create","maxWidth","padding","borderRadius","borderBottomLeftRadius","marginBottom","flexDirection","alignItems","justifyContent","height","width","marginHorizontal"],"sources":["TypingIndicator.tsx"],"sourcesContent":["/**\n * Typing Indicator Component\n * Animated dots to show bot is typing\n */\n\nimport React, { useEffect, useRef } from 'react';\nimport { View, Animated, StyleSheet } from 'react-native';\nimport { useTheme } from '../theme';\nimport { typingDotAnimation } from '../utils/animations';\n\nexport const TypingIndicator: React.FC = () => {\n const { theme } = useTheme();\n\n const dot1 = useRef(new Animated.Value(0)).current;\n const dot2 = useRef(new Animated.Value(0)).current;\n const dot3 = useRef(new Animated.Value(0)).current;\n\n useEffect(() => {\n // Start animations with staggered delays\n const anim1 = typingDotAnimation(dot1, 0);\n const anim2 = typingDotAnimation(dot2, 150);\n const anim3 = typingDotAnimation(dot3, 300);\n\n anim1.start();\n anim2.start();\n anim3.start();\n\n return () => {\n anim1.stop();\n anim2.stop();\n anim3.stop();\n };\n }, []);\n\n return (\n <View style={[styles.container, { backgroundColor: theme.colors.botBubble }]}>\n <View style={styles.dotsContainer}>\n <Animated.View\n style={[\n styles.dot,\n { backgroundColor: theme.colors.gray400 },\n { transform: [{ translateY: dot1 }] },\n ]}\n />\n <Animated.View\n style={[\n styles.dot,\n { backgroundColor: theme.colors.gray400 },\n { transform: [{ translateY: dot2 }] },\n ]}\n />\n <Animated.View\n style={[\n styles.dot,\n { backgroundColor: theme.colors.gray400 },\n { transform: [{ translateY: dot3 }] },\n ]}\n />\n </View>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n maxWidth: '75%',\n padding: 12,\n borderRadius: 16,\n borderBottomLeftRadius: 4,\n marginBottom: 12,\n },\n dotsContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n height: 20,\n },\n dot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginHorizontal: 3,\n },\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lingu SDK Context Provider
|
|
3
|
+
* Provides standalone state management for the SDK
|
|
4
|
+
* Completely isolated from host application state
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { createContext, useContext } from 'react';
|
|
8
|
+
import { useLinguChat } from '../hooks/useLinguChat';
|
|
9
|
+
import { ThemeProvider } from '../theme';
|
|
10
|
+
const LinguContext = /*#__PURE__*/createContext(undefined);
|
|
11
|
+
/**
|
|
12
|
+
* LinguProvider - Wraps the SDK with standalone state management
|
|
13
|
+
* This ensures the SDK state is completely isolated from the host app
|
|
14
|
+
*/
|
|
15
|
+
export const LinguProvider = ({
|
|
16
|
+
children,
|
|
17
|
+
...linguConfig
|
|
18
|
+
}) => {
|
|
19
|
+
const chatState = useLinguChat(linguConfig);
|
|
20
|
+
return /*#__PURE__*/React.createElement(LinguContext.Provider, {
|
|
21
|
+
value: chatState
|
|
22
|
+
}, /*#__PURE__*/React.createElement(ThemeProvider, {
|
|
23
|
+
config: chatState.config
|
|
24
|
+
}, children));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Hook to access Lingu SDK context
|
|
29
|
+
* Must be used within a LinguProvider
|
|
30
|
+
*/
|
|
31
|
+
export const useLinguContext = () => {
|
|
32
|
+
const context = useContext(LinguContext);
|
|
33
|
+
if (context === undefined) {
|
|
34
|
+
throw new Error('useLinguContext must be used within a LinguProvider');
|
|
35
|
+
}
|
|
36
|
+
return context;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=LinguProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","createContext","useContext","useLinguChat","ThemeProvider","LinguContext","undefined","LinguProvider","children","linguConfig","chatState","createElement","Provider","value","config","useLinguContext","context","Error"],"sources":["LinguProvider.tsx"],"sourcesContent":["/**\n * Lingu SDK Context Provider\n * Provides standalone state management for the SDK\n * Completely isolated from host application state\n */\n\nimport React, { createContext, useContext, ReactNode } from 'react';\nimport { useLinguChat } from '../hooks/useLinguChat';\nimport { ThemeProvider } from '../theme';\nimport type { Message, WidgetConfig, LinguConfig } from '../types';\n\ninterface LinguContextValue {\n messages: Message[];\n isLoading: boolean;\n config: WidgetConfig | null;\n sendMessage: (text: string) => Promise<void>;\n startSession: () => Promise<void>;\n endSession: () => Promise<void>;\n isSessionActive: boolean;\n clearHistory: () => Promise<void>;\n}\n\nconst LinguContext = createContext<LinguContextValue | undefined>(undefined);\n\ninterface LinguProviderProps extends LinguConfig {\n children: ReactNode;\n}\n\n/**\n * LinguProvider - Wraps the SDK with standalone state management\n * This ensures the SDK state is completely isolated from the host app\n */\nexport const LinguProvider: React.FC<LinguProviderProps> = ({ children, ...linguConfig }) => {\n const chatState = useLinguChat(linguConfig);\n\n return (\n <LinguContext.Provider value={chatState}>\n <ThemeProvider config={chatState.config}>{children}</ThemeProvider>\n </LinguContext.Provider>\n );\n};\n\n/**\n * Hook to access Lingu SDK context\n * Must be used within a LinguProvider\n */\nexport const useLinguContext = (): LinguContextValue => {\n const context = useContext(LinguContext);\n if (context === undefined) {\n throw new Error('useLinguContext must be used within a LinguProvider');\n }\n return context;\n};\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,KAAK,IAAIC,aAAa,EAAEC,UAAU,QAAmB,OAAO;AACnE,SAASC,YAAY,QAAQ,uBAAuB;AACpD,SAASC,aAAa,QAAQ,UAAU;AAcxC,MAAMC,YAAY,gBAAGJ,aAAa,CAAgCK,SAAS,CAAC;AAM5E;AACA;AACA;AACA;AACA,OAAO,MAAMC,aAA2C,GAAGA,CAAC;EAAEC,QAAQ;EAAE,GAAGC;AAAY,CAAC,KAAK;EAC1F,MAAMC,SAAS,GAAGP,YAAY,CAACM,WAAW,CAAC;EAE3C,oBACGT,KAAA,CAAAW,aAAA,CAACN,YAAY,CAACO,QAAQ;IAACC,KAAK,EAAEH;EAAU,gBACrCV,KAAA,CAAAW,aAAA,CAACP,aAAa;IAACU,MAAM,EAAEJ,SAAS,CAACI;EAAO,GAAEN,QAAwB,CAC9C,CAAC;AAE9B,CAAC;;AAED;AACA;AACA;AACA;AACA,OAAO,MAAMO,eAAe,GAAGA,CAAA,KAAyB;EACrD,MAAMC,OAAO,GAAGd,UAAU,CAACG,YAAY,CAAC;EACxC,IAAIW,OAAO,KAAKV,SAAS,EAAE;IACxB,MAAM,IAAIW,KAAK,CAAC,qDAAqD,CAAC;EACzE;EACA,OAAOD,OAAO;AACjB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["/**\n * Context exports\n */\n\nexport * from './LinguProvider';\n"],"mappings":"AAAA;AACA;AACA;;AAEA,cAAc,iBAAiB","ignoreList":[]}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom hook for managing Lingu chat state and operations
|
|
3
|
+
* Now with message persistence and comprehensive logging
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
7
|
+
import { LinguAPI } from '../services/LinguAPI';
|
|
8
|
+
import { SessionManager } from '../services/SessionManager';
|
|
9
|
+
import { StorageManager } from '../services/StorageManager';
|
|
10
|
+
const LOG_PREFIX = '[useLinguChat]';
|
|
11
|
+
export const useLinguChat = linguConfig => {
|
|
12
|
+
var _linguConfig$apiKey;
|
|
13
|
+
console.log(`${LOG_PREFIX} Initializing hook with config:`, {
|
|
14
|
+
apiKey: ((_linguConfig$apiKey = linguConfig.apiKey) === null || _linguConfig$apiKey === void 0 ? void 0 : _linguConfig$apiKey.substring(0, 20)) + '...',
|
|
15
|
+
baseURL: linguConfig.baseURL,
|
|
16
|
+
autoOpen: linguConfig.autoOpen
|
|
17
|
+
});
|
|
18
|
+
const [messages, setMessages] = useState([]);
|
|
19
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
20
|
+
const [config, setConfig] = useState(null);
|
|
21
|
+
const [isSessionActive, setIsSessionActive] = useState(false);
|
|
22
|
+
const apiRef = useRef(null);
|
|
23
|
+
const sessionManagerRef = useRef(null);
|
|
24
|
+
const currentSessionIdRef = useRef(null);
|
|
25
|
+
|
|
26
|
+
// Initialize API client and session manager
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
console.log(`${LOG_PREFIX} Setting up API client and session manager`);
|
|
29
|
+
const baseURL = linguConfig.baseURL || 'https://api.uselingu.app/api';
|
|
30
|
+
console.log(`${LOG_PREFIX} API Base URL:`, baseURL);
|
|
31
|
+
const api = new LinguAPI(linguConfig.apiKey, baseURL);
|
|
32
|
+
apiRef.current = api;
|
|
33
|
+
const sessionManager = new SessionManager(api, {
|
|
34
|
+
onSessionStart: async sessionId => {
|
|
35
|
+
var _linguConfig$onSessio;
|
|
36
|
+
console.log(`${LOG_PREFIX} ✅ Session started:`, sessionId);
|
|
37
|
+
currentSessionIdRef.current = sessionId;
|
|
38
|
+
setIsSessionActive(true);
|
|
39
|
+
|
|
40
|
+
// Save session ID
|
|
41
|
+
await StorageManager.saveCurrentSessionId(sessionId);
|
|
42
|
+
console.log(`${LOG_PREFIX} Session ID saved to storage`);
|
|
43
|
+
|
|
44
|
+
// Try to load previous messages for this session
|
|
45
|
+
const savedMessages = await StorageManager.loadMessages(sessionId);
|
|
46
|
+
if (savedMessages.length > 0) {
|
|
47
|
+
console.log(`${LOG_PREFIX} Loaded ${savedMessages.length} messages from storage`);
|
|
48
|
+
setMessages(savedMessages);
|
|
49
|
+
} else {
|
|
50
|
+
console.log(`${LOG_PREFIX} No previous messages found for this session`);
|
|
51
|
+
}
|
|
52
|
+
(_linguConfig$onSessio = linguConfig.onSessionStart) === null || _linguConfig$onSessio === void 0 || _linguConfig$onSessio.call(linguConfig, sessionId);
|
|
53
|
+
},
|
|
54
|
+
onSessionEnd: async sessionId => {
|
|
55
|
+
var _linguConfig$onSessio2;
|
|
56
|
+
console.log(`${LOG_PREFIX} Session ending:`, sessionId);
|
|
57
|
+
|
|
58
|
+
// Save messages before ending
|
|
59
|
+
if (messages.length > 0) {
|
|
60
|
+
console.log(`${LOG_PREFIX} Saving ${messages.length} messages before session end`);
|
|
61
|
+
await StorageManager.saveMessages(sessionId, messages);
|
|
62
|
+
}
|
|
63
|
+
currentSessionIdRef.current = null;
|
|
64
|
+
setIsSessionActive(false);
|
|
65
|
+
console.log(`${LOG_PREFIX} ✅ Session ended successfully`);
|
|
66
|
+
(_linguConfig$onSessio2 = linguConfig.onSessionEnd) === null || _linguConfig$onSessio2 === void 0 || _linguConfig$onSessio2.call(linguConfig, sessionId);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
sessionManagerRef.current = sessionManager;
|
|
70
|
+
|
|
71
|
+
// Load widget configuration
|
|
72
|
+
console.log(`${LOG_PREFIX} Fetching widget configuration...`);
|
|
73
|
+
api.getConfig().then(fetchedConfig => {
|
|
74
|
+
var _fetchedConfig$greeti;
|
|
75
|
+
console.log(`${LOG_PREFIX} ✅ Widget config loaded:`, {
|
|
76
|
+
theme: fetchedConfig.theme,
|
|
77
|
+
primaryColor: fetchedConfig.primaryColor,
|
|
78
|
+
brandName: fetchedConfig.brandName,
|
|
79
|
+
greetingMessage: (_fetchedConfig$greeti = fetchedConfig.greetingMessage) === null || _fetchedConfig$greeti === void 0 ? void 0 : _fetchedConfig$greeti.substring(0, 50)
|
|
80
|
+
});
|
|
81
|
+
setConfig(fetchedConfig);
|
|
82
|
+
}).catch(error => {
|
|
83
|
+
console.error(`${LOG_PREFIX} ❌ Failed to load config:`, error);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Try to restore previous session
|
|
87
|
+
console.log(`${LOG_PREFIX} Attempting to restore previous session...`);
|
|
88
|
+
restorePreviousSession();
|
|
89
|
+
|
|
90
|
+
// Cleanup on unmount
|
|
91
|
+
return () => {
|
|
92
|
+
var _sessionManagerRef$cu;
|
|
93
|
+
console.log(`${LOG_PREFIX} Component unmounting, cleaning up...`);
|
|
94
|
+
// Save messages before cleanup
|
|
95
|
+
if (currentSessionIdRef.current && messages.length > 0) {
|
|
96
|
+
console.log(`${LOG_PREFIX} Saving messages on unmount`);
|
|
97
|
+
StorageManager.saveMessages(currentSessionIdRef.current, messages);
|
|
98
|
+
}
|
|
99
|
+
(_sessionManagerRef$cu = sessionManagerRef.current) === null || _sessionManagerRef$cu === void 0 || _sessionManagerRef$cu.cleanup();
|
|
100
|
+
console.log(`${LOG_PREFIX} Cleanup complete`);
|
|
101
|
+
};
|
|
102
|
+
}, [linguConfig.apiKey, linguConfig.baseURL]);
|
|
103
|
+
|
|
104
|
+
// Save messages whenever they change
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (currentSessionIdRef.current && messages.length > 0) {
|
|
107
|
+
console.log(`${LOG_PREFIX} Auto-saving ${messages.length} messages`);
|
|
108
|
+
StorageManager.saveMessages(currentSessionIdRef.current, messages);
|
|
109
|
+
}
|
|
110
|
+
}, [messages]);
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Try to restore previous session
|
|
114
|
+
*/
|
|
115
|
+
const restorePreviousSession = async () => {
|
|
116
|
+
try {
|
|
117
|
+
const previousSessionId = await StorageManager.getCurrentSessionId();
|
|
118
|
+
if (previousSessionId) {
|
|
119
|
+
console.log(`${LOG_PREFIX} Found previous session:`, previousSessionId);
|
|
120
|
+
const savedMessages = await StorageManager.loadMessages(previousSessionId);
|
|
121
|
+
if (savedMessages.length > 0) {
|
|
122
|
+
console.log(`${LOG_PREFIX} ✅ Restored ${savedMessages.length} messages from previous session`);
|
|
123
|
+
setMessages(savedMessages);
|
|
124
|
+
currentSessionIdRef.current = previousSessionId;
|
|
125
|
+
} else {
|
|
126
|
+
console.log(`${LOG_PREFIX} Previous session had no messages`);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`${LOG_PREFIX} No previous session found`);
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error(`${LOG_PREFIX} ❌ Failed to restore previous session:`, error);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Start a new chat session
|
|
138
|
+
*/
|
|
139
|
+
const startSession = useCallback(async () => {
|
|
140
|
+
if (!sessionManagerRef.current) {
|
|
141
|
+
console.error(`${LOG_PREFIX} ❌ Session manager not initialized`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
console.log(`${LOG_PREFIX} Starting new session...`);
|
|
146
|
+
await sessionManagerRef.current.start();
|
|
147
|
+
|
|
148
|
+
// Add greeting message if configured and no previous messages
|
|
149
|
+
if (config !== null && config !== void 0 && config.greetingMessage && messages.length === 0) {
|
|
150
|
+
console.log(`${LOG_PREFIX} Adding greeting message`);
|
|
151
|
+
const greetingMsg = {
|
|
152
|
+
id: `greeting-${Date.now()}`,
|
|
153
|
+
text: config.greetingMessage,
|
|
154
|
+
sender: 'bot',
|
|
155
|
+
timestamp: new Date()
|
|
156
|
+
};
|
|
157
|
+
setMessages([greetingMsg]);
|
|
158
|
+
}
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(`${LOG_PREFIX} ❌ Failed to start session:`, error);
|
|
161
|
+
}
|
|
162
|
+
}, [config, messages.length]);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* End the current chat session
|
|
166
|
+
*/
|
|
167
|
+
const endSession = useCallback(async () => {
|
|
168
|
+
if (!sessionManagerRef.current) {
|
|
169
|
+
console.error(`${LOG_PREFIX} ❌ Session manager not initialized`);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
console.log(`${LOG_PREFIX} Ending session...`);
|
|
174
|
+
await sessionManagerRef.current.end();
|
|
175
|
+
// Don't clear messages - they're saved in storage
|
|
176
|
+
console.log(`${LOG_PREFIX} ✅ Session ended, messages preserved`);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error(`${LOG_PREFIX} ❌ Failed to end session:`, error);
|
|
179
|
+
}
|
|
180
|
+
}, []);
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Clear chat history
|
|
184
|
+
*/
|
|
185
|
+
const clearHistory = useCallback(async () => {
|
|
186
|
+
console.log(`${LOG_PREFIX} Clearing chat history...`);
|
|
187
|
+
if (currentSessionIdRef.current) {
|
|
188
|
+
await StorageManager.clearMessages(currentSessionIdRef.current);
|
|
189
|
+
console.log(`${LOG_PREFIX} ✅ Storage cleared for session:`, currentSessionIdRef.current);
|
|
190
|
+
}
|
|
191
|
+
setMessages([]);
|
|
192
|
+
console.log(`${LOG_PREFIX} ✅ Messages cleared from state`);
|
|
193
|
+
}, []);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Send a message to the AI
|
|
197
|
+
*/
|
|
198
|
+
const sendMessage = useCallback(async text => {
|
|
199
|
+
var _linguConfig$onMessag;
|
|
200
|
+
if (!apiRef.current || !sessionManagerRef.current) {
|
|
201
|
+
console.error(`${LOG_PREFIX} ❌ API or session manager not initialized`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const sessionId = sessionManagerRef.current.getSessionId();
|
|
205
|
+
if (!sessionId) {
|
|
206
|
+
console.error(`${LOG_PREFIX} ❌ No active session`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
console.log(`${LOG_PREFIX} Sending message:`, {
|
|
210
|
+
sessionId,
|
|
211
|
+
messageLength: text.length,
|
|
212
|
+
preview: text.substring(0, 50)
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Add user message
|
|
216
|
+
const userMessage = {
|
|
217
|
+
id: `user-${Date.now()}`,
|
|
218
|
+
text,
|
|
219
|
+
sender: 'user',
|
|
220
|
+
timestamp: new Date()
|
|
221
|
+
};
|
|
222
|
+
setMessages(prev => {
|
|
223
|
+
console.log(`${LOG_PREFIX} Adding user message to state (total: ${prev.length + 1})`);
|
|
224
|
+
return [...prev, userMessage];
|
|
225
|
+
});
|
|
226
|
+
(_linguConfig$onMessag = linguConfig.onMessageSent) === null || _linguConfig$onMessag === void 0 || _linguConfig$onMessag.call(linguConfig, text);
|
|
227
|
+
|
|
228
|
+
// Send to API
|
|
229
|
+
setIsLoading(true);
|
|
230
|
+
console.log(`${LOG_PREFIX} Waiting for AI response...`);
|
|
231
|
+
try {
|
|
232
|
+
var _linguConfig$onMessag2;
|
|
233
|
+
const startTime = Date.now();
|
|
234
|
+
const response = await apiRef.current.sendMessage(text, sessionId);
|
|
235
|
+
const duration = Date.now() - startTime;
|
|
236
|
+
console.log(`${LOG_PREFIX} ✅ Received AI response in ${duration}ms:`, {
|
|
237
|
+
responseLength: response.length,
|
|
238
|
+
preview: response.substring(0, 50)
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Add bot response
|
|
242
|
+
const botMessage = {
|
|
243
|
+
id: `bot-${Date.now()}`,
|
|
244
|
+
text: response,
|
|
245
|
+
sender: 'bot',
|
|
246
|
+
timestamp: new Date()
|
|
247
|
+
};
|
|
248
|
+
setMessages(prev => {
|
|
249
|
+
console.log(`${LOG_PREFIX} Adding bot message to state (total: ${prev.length + 1})`);
|
|
250
|
+
return [...prev, botMessage];
|
|
251
|
+
});
|
|
252
|
+
(_linguConfig$onMessag2 = linguConfig.onMessageReceived) === null || _linguConfig$onMessag2 === void 0 || _linguConfig$onMessag2.call(linguConfig, response);
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error(`${LOG_PREFIX} ❌ Failed to send message:`, error);
|
|
255
|
+
|
|
256
|
+
// Add error message
|
|
257
|
+
const errorMessage = {
|
|
258
|
+
id: `error-${Date.now()}`,
|
|
259
|
+
text: 'Sorry, I encountered an error. Please try again.',
|
|
260
|
+
sender: 'bot',
|
|
261
|
+
timestamp: new Date()
|
|
262
|
+
};
|
|
263
|
+
setMessages(prev => [...prev, errorMessage]);
|
|
264
|
+
console.log(`${LOG_PREFIX} Added error message to state`);
|
|
265
|
+
} finally {
|
|
266
|
+
setIsLoading(false);
|
|
267
|
+
console.log(`${LOG_PREFIX} Message send complete`);
|
|
268
|
+
}
|
|
269
|
+
}, [linguConfig]);
|
|
270
|
+
console.log(`${LOG_PREFIX} Current state:`, {
|
|
271
|
+
messagesCount: messages.length,
|
|
272
|
+
isLoading,
|
|
273
|
+
hasConfig: !!config,
|
|
274
|
+
isSessionActive,
|
|
275
|
+
currentSessionId: currentSessionIdRef.current
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
messages,
|
|
279
|
+
isLoading,
|
|
280
|
+
config,
|
|
281
|
+
sendMessage,
|
|
282
|
+
startSession,
|
|
283
|
+
endSession,
|
|
284
|
+
isSessionActive,
|
|
285
|
+
clearHistory
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
//# sourceMappingURL=useLinguChat.js.map
|