react-native-srschat 0.1.46 → 0.1.47

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/src/layout/ex.js CHANGED
@@ -1,251 +1,252 @@
1
- import React, { useState, useEffect, useContext, useRef } from 'react';
2
- import { Text, StyleSheet, View, TextInput, TouchableOpacity, Platform, KeyboardAvoidingView,
3
- Keyboard, Animated, PanResponder, Pressable } from 'react-native';
4
- import { Header } from '../components/header';
5
- import { AppContext } from '../contexts/AppContext';
6
- import Ionicons from 'react-native-vector-icons/Ionicons';
7
- import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
8
- import { Testing } from '../components/testing';
9
- import { ChatInput } from '../components/input';
10
- import { useWebSocketMessage } from '../hooks/Stream';
11
- import { ProductCard } from '../components/productCard'
12
- import Markdown from 'react-native-markdown-display';
13
-
14
- export const ChatWindow = () => {
15
- const { handleSend, messages, input, setInput, ghostMessage, handleButtonClick, setShowModal } = useContext(AppContext);
16
-
17
- const scrollViewRef = useRef(null);
18
- const fadeAnim = useRef(new Animated.Value(0.6)).current;
19
- const panY = useRef(new Animated.Value(0)).current;
20
- const isDragging = useRef(false);
21
-
22
- useEffect(() => {
23
- if (scrollViewRef.current) {
24
- setTimeout(() => {
25
- scrollViewRef.current.scrollToEnd({ animated: false });
26
- }, 100);
27
- }
28
- }, []);
29
-
30
- useEffect(() => {
31
- if (ghostMessage) {
32
- Animated.loop(
33
- Animated.sequence([
34
- Animated.timing(fadeAnim, { toValue: 1, duration: 500, useNativeDriver: false }),
35
- Animated.timing(fadeAnim, { toValue: 0.6, duration: 500, useNativeDriver: false }),
36
- ])
37
- ).start();
38
- }
39
- }, [ghostMessage]);
40
-
41
- useWebSocketMessage()
42
-
43
- const headerPanResponder = PanResponder.create({
44
- onStartShouldSetPanResponder: () => true,
45
- onMoveShouldSetPanResponder: () => true,
46
- onPanResponderGrant: () => {
47
- isDragging.current = true;
48
- },
49
- onPanResponderMove: (evt, gestureState) => {
50
- if (isDragging.current && gestureState.dy > 0) { // Downward swipe
51
- panY.setValue(gestureState.dy);
52
- }
53
- },
54
- onPanResponderRelease: (evt, gestureState) => {
55
- if (gestureState.dy > 100) { // Swiped down enough
56
- handleClick()
57
- } else {
58
- Animated.spring(panY, { toValue: 0, useNativeDriver: false }).start();
59
- }
60
- isDragging.current = false;
61
- },
62
- });
63
-
64
- const handleClick = () => {
65
- if ((uiConfig.showIcon ?? true) !== true) {
66
- setShowModal("Off");
67
- } else {
68
- setShowModal("Icon");
69
- }
70
- };
1
+ // import React, { useState, useEffect, useContext, useRef } from 'react';
2
+ // import { Text, StyleSheet, View, TextInput, TouchableOpacity, Platform, KeyboardAvoidingView,
3
+ // Keyboard, Animated, PanResponder, Pressable } from 'react-native';
4
+ // import { Header } from '../components/header';
5
+ // import { AppContext } from '../contexts/AppContext';
6
+ // import Ionicons from 'react-native-vector-icons/Ionicons';
7
+ // import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
8
+ // import { Testing } from '../components/testing';
9
+ // import { ChatInput } from '../components/input';
10
+ // import { useWebSocketMessage } from '../hooks/Stream';
11
+ // import { ProductCard } from '../components/productCard'
12
+ // import Markdown from 'react-native-markdown-display';
13
+
14
+ // export const ChatWindow = () => {
15
+ // const { handleSend, messages, input, setInput, ghostMessage, handleButtonClick, setShowModal } = useContext(AppContext);
16
+
17
+ // const scrollViewRef = useRef(null);
18
+ // const fadeAnim = useRef(new Animated.Value(0.6)).current;
19
+ // const panY = useRef(new Animated.Value(0)).current;
20
+ // const isDragging = useRef(false);
21
+
22
+ // useEffect(() => {
23
+ // if (scrollViewRef.current) {
24
+ // setTimeout(() => {
25
+ // scrollViewRef.current.scrollToEnd({ animated: false });
26
+ // }, 100);
27
+ // }
28
+ // }, []);
29
+
30
+ // useEffect(() => {
31
+ // if (ghostMessage) {
32
+ // Animated.loop(
33
+ // Animated.sequence([
34
+ // Animated.timing(fadeAnim, { toValue: 1, duration: 500, useNativeDriver: false }),
35
+ // Animated.timing(fadeAnim, { toValue: 0.6, duration: 500, useNativeDriver: false }),
36
+ // ])
37
+ // ).start();
38
+ // }
39
+ // }, [ghostMessage]);
40
+
41
+ // useWebSocketMessage()
42
+
43
+ // const headerPanResponder = PanResponder.create({
44
+ // onStartShouldSetPanResponder: () => true,
45
+ // onMoveShouldSetPanResponder: () => true,
46
+ // onPanResponderGrant: () => {
47
+ // isDragging.current = true;
48
+ // },
49
+ // onPanResponderMove: (evt, gestureState) => {
50
+ // if (isDragging.current && gestureState.dy > 0) { // Downward swipe
51
+ // panY.setValue(gestureState.dy);
52
+ // }
53
+ // },
54
+ // onPanResponderRelease: (evt, gestureState) => {
55
+ // if (gestureState.dy > 100) { // Swiped down enough
56
+ // handleClick()
57
+ // } else {
58
+ // Animated.spring(panY, { toValue: 0, useNativeDriver: false }).start();
59
+ // }
60
+ // isDragging.current = false;
61
+ // },
62
+ // });
63
+
64
+ // const handleClick = () => {
65
+ // if ((uiConfig.showIcon ?? true) !== true) {
66
+ // setShowModal("Off");
67
+ // } else {
68
+ // setShowModal("Icon");
69
+ // }
70
+ // };
71
71
 
72
- return (
73
- <View style={styles.overlay}>
74
- {/* Click outside chat to close */}
75
- <Pressable style={styles.outsideTouchable} onPress={() => handleClick()} />
76
-
77
- <Animated.View style={[styles.container, { transform: [{ translateY: panY }] }]}>
78
- {/* Header - Only this section triggers drag-to-close */}
79
- <View style={styles.headerContainer} {...headerPanResponder.panHandlers}>
80
- <Header />
81
- </View>
82
-
83
- {/* Messages area */}
84
- <KeyboardAwareScrollView
85
- ref={scrollViewRef}
86
- contentContainerStyle={styles.messagesContent}
87
- enableOnAndroid
88
- contentInsetAdjustmentBehavior="never"
89
- automaticallyAdjustContentInsets={false}
90
- contentInset={{ bottom: 0 }}
91
- keyboardShouldPersistTaps="always"
92
- showsVerticalScrollIndicator={false}
93
- extraScrollHeight={0}
94
- onContentSizeChange={() => {
95
- scrollViewRef.current?.scrollToEnd({ animated: true });
96
- }}
97
- >
98
- {messages.map((msg, i) => (
72
+ // return (
73
+ // <View style={styles.overlay}>
74
+ // {/* Click outside chat to close */}
75
+ // <Pressable style={styles.outsideTouchable} onPress={() => handleClick()} />
76
+
77
+ // <Animated.View style={[styles.container, { transform: [{ translateY: panY }] }]}>
78
+ // {/* Header - Only this section triggers drag-to-close */}
79
+ // <View style={styles.headerContainer} {...headerPanResponder.panHandlers}>
80
+ // <Header />
81
+ // </View>
82
+
83
+ // {/* Messages area */}
84
+ // <KeyboardAwareScrollView
85
+ // ref={scrollViewRef}
86
+ // contentContainerStyle={styles.messagesContent}
87
+ // enableOnAndroid
88
+ // contentInsetAdjustmentBehavior="never"
89
+ // automaticallyAdjustContentInsets={false}
90
+ // contentInset={{ bottom: 0 }}
91
+ // keyboardShouldPersistTaps="always"
92
+ // showsVerticalScrollIndicator={false}
93
+ // extraScrollHeight={0}
94
+ // onContentSizeChange={() => {
95
+ // scrollViewRef.current?.scrollToEnd({ animated: true });
96
+ // }}
97
+ // >
98
+ // {messages.map((msg, i) => (
99
99
 
100
- <View key={i} style={styles.messageWrapper}>
101
- {msg.type !== "middle" && (
102
- <View style={[ styles.messageBubble, msg.type === "user" ? styles.userMessage : styles.aiMessage,]}>
103
- <Markdown style={{ body: { color: msg.type === "user" ? "#ffffff" : "#161616",fontSize: 16, lineHeight: 22 }}}>
104
- {msg.text}
105
- </Markdown>
106
- </View>
107
- )}
108
-
109
- {msg.products && msg.products.length > 0 &&
110
- msg.products.map((prod, index) => (
111
- <View key={index} style={styles.productCardWrapper}>
112
- <ProductCard prod={prod} />
113
- </View>
114
- ))}
115
-
116
- {msg.suggested_questions && Array.isArray(msg.questions) && msg.questions.map((question, index) => (
117
- <TouchableOpacity key={index} style={styles.suggestedQuestionButton}
118
- onPress={() => handleButtonClick(question)}>
119
- <Text style={styles.suggestedQuestionText}>{question}</Text>
120
- </TouchableOpacity>
121
- ))}
122
-
123
- {ghostMessage && i === messages.length - 1 && (
124
- <View style={styles.ghostMessageContainer}>
125
- <Animated.View style={[styles.ghostBar, styles.ghostBarShort, { opacity: fadeAnim }]} />
126
- <Animated.View style={[styles.ghostBar, styles.ghostBarLong, { opacity: fadeAnim }]} />
127
- <Animated.View style={[styles.ghostBar, styles.ghostBarMedium, { opacity: fadeAnim }]} />
128
- </View>
129
- )}
130
- </View>
131
- ))}
132
- </KeyboardAwareScrollView>
133
-
134
- <KeyboardAvoidingView
135
- behavior={Platform.OS === 'ios' ? 'padding' : undefined}
136
- keyboardVerticalOffset={Platform.OS === 'ios' ? 120 : 60}
137
- >
138
- <ChatInput/>
139
- </KeyboardAvoidingView>
140
- </Animated.View>
141
- </View>
142
- );
143
- };
144
-
145
- const styles = StyleSheet.create({
146
- overlay: {
147
- flex: 1,
148
- position: 'absolute',
149
- left: 0,
150
- right: 0,
151
- top: 0,
152
- bottom: 0,
153
- backgroundColor: 'rgba(0, 0, 0, 0.3)',
154
- justifyContent: 'flex-end',
155
- },
156
- outsideTouchable: {
157
- flex: 1, // Takes up the space above the chat, allows clicking to close
158
- },
159
- container: {
160
- flex: 1,
161
- backgroundColor: '#f6f6f6',
162
- position: 'absolute',
163
- zIndex: 1000,
164
- left: 0,
165
- right: 0,
166
- bottom: 0,
167
- top: 140,
168
- pointerEvents: 'box-none',
169
- borderTopWidth: 1,
170
- borderTopColor: '#DDD',
171
- borderTopLeftRadius: 16,
172
- borderTopRightRadius: 16,
173
- overflow: 'hidden',
174
- },
175
- headerContainer: {
176
- alignItems: "center",
177
- backgroundColor: "#f6f6f6",
178
- borderTopLeftRadius: 16,
179
- borderTopRightRadius: 16,
180
- },
181
- messagesContent: {
182
- padding: 16,
183
- justifyContent: 'flex-end',
184
- },
185
- messageWrapper: {
186
- marginBottom: 0,
187
- },
188
- messageBubble: {
189
- padding: 6,
190
- paddingHorizontal: 16,
191
- borderRadius: 12,
192
- marginBottom: 5
193
- },
194
- userMessage: {
195
- alignSelf: 'flex-end',
196
- backgroundColor: "#003764",
197
- color: "#ffffff"
198
- },
199
- aiMessage: {
200
- alignSelf: 'flex-start',
201
- backgroundColor: '#FFFFFF',
202
- width: '100%',
203
- },
204
- productCardWrapper: {
205
- marginTop: 5,
206
- },
207
- suggestedQuestionButton: {
208
- backgroundColor: "white",
209
- borderWidth: 1,
210
- borderColor: "#004687",
211
- borderRadius: 18,
212
- paddingVertical: 10,
213
- paddingHorizontal: 16,
214
- marginBottom: 7,
215
- alignSelf: "flex-start",
216
- },
217
- suggestedQuestionText: {
218
- color: "#004687",
219
- fontSize: 13,
220
- textAlign: "left",
221
- },
222
- ghostMessageContainer: {
223
- alignSelf: 'flex-start',
224
- width: '100%',
225
- backgroundColor: "#FFFFFF",
226
- borderRadius: 10,
227
- borderTopLeftRadius: 0,
228
- padding: 14,
229
- marginVertical: 5,
230
- },
231
- ghostBar: {
232
- height: 20,
233
- borderRadius: 10,
234
- backgroundColor: "#ebebeb",
235
- marginVertical: 3,
236
- },
237
- ghostBarShort: {
238
- width: "50%",
239
- },
240
- ghostBarMedium: {
241
- width: "75%",
242
- },
243
- ghostBarLong: {
244
- width: "100%",
245
- },
246
- });
247
-
248
- {/* <Testing
249
- onProductCardClick={onProductCardClick}
250
- onAddToCartClick={onAddToCartClick}
251
- /> */}
100
+ // <View key={i} style={styles.messageWrapper}>
101
+ // {msg.type !== "middle" && (
102
+ // <View style={[ styles.messageBubble, msg.type === "user" ? styles.userMessage : styles.aiMessage,]}>
103
+ // <Markdown style={{ body: { color: msg.type === "user" ? "#ffffff" : "#161616",fontSize: 16, lineHeight: 22 }}}>
104
+ // {msg.text}
105
+ // </Markdown>
106
+ // </View>
107
+ // )}
108
+
109
+ // {msg.products && msg.products.length > 0 &&
110
+ // msg.products.map((prod, index) => (
111
+ // <View key={index} style={styles.productCardWrapper}>
112
+ // <ProductCard prod={prod} />
113
+ // </View>
114
+ // ))}
115
+
116
+ // {msg.suggested_questions && Array.isArray(msg.questions) && msg.questions.map((question, index) => (
117
+ // <TouchableOpacity key={index} style={styles.suggestedQuestionButton}
118
+ // onPress={() => handleButtonClick(question)}>
119
+ // <Text style={styles.suggestedQuestionText}>{question}</Text>
120
+ // </TouchableOpacity>
121
+ // ))}
122
+
123
+ // {ghostMessage && i === messages.length - 1 && (
124
+ // <View style={styles.ghostMessageContainer}>
125
+ // <Animated.View style={[styles.ghostBar, styles.ghostBarShort, { opacity: fadeAnim }]} />
126
+ // <Animated.View style={[styles.ghostBar, styles.ghostBarLong, { opacity: fadeAnim }]} />
127
+ // <Animated.View style={[styles.ghostBar, styles.ghostBarMedium, { opacity: fadeAnim }]} />
128
+ // </View>
129
+ // )}
130
+ // </View>
131
+ // ))}
132
+
133
+ // <KeyboardAvoidingView
134
+ // behavior={Platform.OS === 'ios' ? 'padding' : undefined}
135
+ // keyboardVerticalOffset={Platform.OS === 'ios' ? 120 : 60}
136
+ // >
137
+ // <ChatInput/>
138
+ // </KeyboardAvoidingView>
139
+ // </KeyboardAwareScrollView>
140
+
141
+ // </Animated.View>
142
+ // </View>
143
+ // );
144
+ // };
145
+
146
+ // const styles = StyleSheet.create({
147
+ // overlay: {
148
+ // flex: 1,
149
+ // position: 'absolute',
150
+ // left: 0,
151
+ // right: 0,
152
+ // top: 0,
153
+ // bottom: 0,
154
+ // backgroundColor: 'rgba(0, 0, 0, 0.3)',
155
+ // justifyContent: 'flex-end',
156
+ // },
157
+ // outsideTouchable: {
158
+ // flex: 1, // Takes up the space above the chat, allows clicking to close
159
+ // },
160
+ // container: {
161
+ // flex: 1,
162
+ // backgroundColor: '#f6f6f6',
163
+ // position: 'absolute',
164
+ // zIndex: 1000,
165
+ // left: 0,
166
+ // right: 0,
167
+ // bottom: 0,
168
+ // top: 140,
169
+ // pointerEvents: 'box-none',
170
+ // borderTopWidth: 1,
171
+ // borderTopColor: '#DDD',
172
+ // borderTopLeftRadius: 16,
173
+ // borderTopRightRadius: 16,
174
+ // overflow: 'hidden',
175
+ // },
176
+ // headerContainer: {
177
+ // alignItems: "center",
178
+ // backgroundColor: "#f6f6f6",
179
+ // borderTopLeftRadius: 16,
180
+ // borderTopRightRadius: 16,
181
+ // },
182
+ // messagesContent: {
183
+ // padding: 16,
184
+ // justifyContent: 'flex-end',
185
+ // },
186
+ // messageWrapper: {
187
+ // marginBottom: 0,
188
+ // },
189
+ // messageBubble: {
190
+ // padding: 6,
191
+ // paddingHorizontal: 16,
192
+ // borderRadius: 12,
193
+ // marginBottom: 5
194
+ // },
195
+ // userMessage: {
196
+ // alignSelf: 'flex-end',
197
+ // backgroundColor: "#003764",
198
+ // color: "#ffffff"
199
+ // },
200
+ // aiMessage: {
201
+ // alignSelf: 'flex-start',
202
+ // backgroundColor: '#FFFFFF',
203
+ // width: '100%',
204
+ // },
205
+ // productCardWrapper: {
206
+ // marginTop: 5,
207
+ // },
208
+ // suggestedQuestionButton: {
209
+ // backgroundColor: "white",
210
+ // borderWidth: 1,
211
+ // borderColor: "#004687",
212
+ // borderRadius: 18,
213
+ // paddingVertical: 10,
214
+ // paddingHorizontal: 16,
215
+ // marginBottom: 7,
216
+ // alignSelf: "flex-start",
217
+ // },
218
+ // suggestedQuestionText: {
219
+ // color: "#004687",
220
+ // fontSize: 13,
221
+ // textAlign: "left",
222
+ // },
223
+ // ghostMessageContainer: {
224
+ // alignSelf: 'flex-start',
225
+ // width: '100%',
226
+ // backgroundColor: "#FFFFFF",
227
+ // borderRadius: 10,
228
+ // borderTopLeftRadius: 0,
229
+ // padding: 14,
230
+ // marginVertical: 5,
231
+ // },
232
+ // ghostBar: {
233
+ // height: 20,
234
+ // borderRadius: 10,
235
+ // backgroundColor: "#ebebeb",
236
+ // marginVertical: 3,
237
+ // },
238
+ // ghostBarShort: {
239
+ // width: "50%",
240
+ // },
241
+ // ghostBarMedium: {
242
+ // width: "75%",
243
+ // },
244
+ // ghostBarLong: {
245
+ // width: "100%",
246
+ // },
247
+ // });
248
+
249
+ // {/* <Testing
250
+ // onProductCardClick={onProductCardClick}
251
+ // onAddToCartClick={onAddToCartClick}
252
+ // /> */}
@@ -15,11 +15,13 @@ import { ProgressCircle } from '../components/progressCircle';
15
15
 
16
16
  export const ChatWindow = ({ panHandlers }) => {
17
17
  const { handleSend, messages, input, setInput, ghostMessage, handleButtonClick,
18
- onProductCardClick, onAddToCartClick, uiConfig, ghostCard, typingIndicator
18
+ onProductCardClick, onAddToCartClick, uiConfig, ghostCard, typingIndicator, feedbackOpen, setFeedbackOpen
19
19
  } = useContext(AppContext);
20
20
 
21
21
  const scrollViewRef = useRef(null);
22
22
  const fadeAnim = useRef(new Animated.Value(0.6)).current;
23
+ const [messageCount, setMessageCount] = useState(0);
24
+
23
25
 
24
26
  useEffect(() => {
25
27
  if (scrollViewRef.current) {
@@ -61,19 +63,45 @@ export const ChatWindow = ({ panHandlers }) => {
61
63
  ref={scrollViewRef}
62
64
  contentContainerStyle={styles.messagesContent}
63
65
  enableOnAndroid
66
+ enableOnIOS
64
67
  contentInsetAdjustmentBehavior="never"
65
68
  automaticallyAdjustContentInsets={false}
66
69
  contentInset={{ bottom: 0 }}
67
70
  keyboardShouldPersistTaps="handled"
68
71
  showsVerticalScrollIndicator={false}
69
- extraScrollHeight={0}
70
- onContentSizeChange={() => {
71
- scrollViewRef.current?.scrollToEnd({ animated: true });
72
+ extraScrollHeight={200}
73
+ onContentSizeChange={(contentWidth, contentHeight) => {
74
+ const currentLength = messages.length;
75
+ // console.log("currentLength", currentLength);
76
+ // console.log("messageCount", messageCount);
77
+ if (currentLength > messageCount) {
78
+ // console.log("scrolling to end");
79
+ scrollViewRef.current?.scrollToEnd({ animated: true });
80
+
81
+ setMessageCount(currentLength);
82
+ } else if (currentLength == messageCount) {
83
+ // Check if *any* value in the feedbackOpen object is true
84
+ const isAnyFeedbackOpen = Object.values(feedbackOpen).some(isOpen => isOpen === true);
85
+
86
+ if (isAnyFeedbackOpen) {
87
+ // console.log("A feedback input is open, not scrolling to end.");
88
+ // Do nothing, prevent scrolling
89
+ } else {
90
+ // console.log("No feedback open, scrolling to end.");
91
+ if (typingIndicator) {
92
+ scrollViewRef.current?.scrollToEnd({ animated: true });
93
+ }
94
+ }
95
+ // You might still want to update messageCount regardless
96
+ setMessageCount(currentLength); // Decide if this should be inside the else or outside the if/else
97
+
98
+ } else if (currentLength < messageCount) {
99
+ setMessageCount(currentLength);
100
+ }
72
101
  }}
73
102
  keyboardDismissMode="none"
74
103
  bounces={false}
75
104
  enableResetScrollToCoords={false}
76
- extraHeight={0}
77
105
  keyboardOpeningTime={0}
78
106
  >
79
107
  {messages.map((msg, i) => (
@@ -102,7 +130,7 @@ export const ChatWindow = ({ panHandlers }) => {
102
130
  {msg.products && msg.products.length > 0 &&
103
131
  msg.products.map((prod, index) => (
104
132
  <View key={index} style={styles.productCardWrapper}>
105
- <ProductCard prod={prod} />
133
+ <ProductCard prod={prod} messageId={msg.message_id} />
106
134
  </View>
107
135
  ))}
108
136
 
@@ -171,6 +199,7 @@ const styles = StyleSheet.create({
171
199
  messagesContent: {
172
200
  padding: 16,
173
201
  justifyContent: 'flex-end',
202
+ paddingBottom: 300,
174
203
  },
175
204
  messageWrapper: {
176
205
  marginBottom: 0,