react-native-srschat 0.1.45 → 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.
Files changed (40) hide show
  1. package/README.md +6 -2
  2. package/lib/commonjs/components/input.js +1 -2
  3. package/lib/commonjs/components/input.js.map +1 -1
  4. package/lib/commonjs/components/productCard.js +5 -3
  5. package/lib/commonjs/components/productCard.js.map +1 -1
  6. package/lib/commonjs/contexts/AppContext.js +8 -2
  7. package/lib/commonjs/contexts/AppContext.js.map +1 -1
  8. package/lib/commonjs/layout/ex.js +252 -270
  9. package/lib/commonjs/layout/ex.js.map +1 -1
  10. package/lib/commonjs/layout/window.js +48 -14
  11. package/lib/commonjs/layout/window.js.map +1 -1
  12. package/lib/commonjs/utils/storage.js +2 -1
  13. package/lib/commonjs/utils/storage.js.map +1 -1
  14. package/lib/module/components/input.js +1 -2
  15. package/lib/module/components/input.js.map +1 -1
  16. package/lib/module/components/productCard.js +5 -3
  17. package/lib/module/components/productCard.js.map +1 -1
  18. package/lib/module/contexts/AppContext.js +8 -2
  19. package/lib/module/contexts/AppContext.js.map +1 -1
  20. package/lib/module/layout/ex.js +252 -261
  21. package/lib/module/layout/ex.js.map +1 -1
  22. package/lib/module/layout/window.js +48 -14
  23. package/lib/module/layout/window.js.map +1 -1
  24. package/lib/module/utils/storage.js +2 -1
  25. package/lib/module/utils/storage.js.map +1 -1
  26. package/lib/typescript/components/productCard.d.ts +2 -1
  27. package/lib/typescript/components/productCard.d.ts.map +1 -1
  28. package/lib/typescript/contexts/AppContext.d.ts.map +1 -1
  29. package/lib/typescript/layout/ex.d.ts +0 -2
  30. package/lib/typescript/layout/ex.d.ts.map +1 -1
  31. package/lib/typescript/layout/window.d.ts.map +1 -1
  32. package/lib/typescript/utils/storage.d.ts +1 -0
  33. package/lib/typescript/utils/storage.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/components/input.js +0 -1
  36. package/src/components/productCard.js +4 -3
  37. package/src/contexts/AppContext.js +10 -2
  38. package/src/layout/ex.js +250 -249
  39. package/src/layout/window.js +41 -8
  40. package/src/utils/storage.ts +3 -1
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,17 +15,23 @@ 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) {
26
- setTimeout(() => {
27
- scrollViewRef.current.scrollToEnd({ animated: false });
28
+ const timeoutId = setTimeout(() => {
29
+ if (scrollViewRef.current) {
30
+ scrollViewRef.current.scrollToEnd({ animated: false });
31
+ }
28
32
  }, 100);
33
+
34
+ return () => clearTimeout(timeoutId);
29
35
  }
30
36
  }, []);
31
37
 
@@ -57,19 +63,45 @@ export const ChatWindow = ({ panHandlers }) => {
57
63
  ref={scrollViewRef}
58
64
  contentContainerStyle={styles.messagesContent}
59
65
  enableOnAndroid
66
+ enableOnIOS
60
67
  contentInsetAdjustmentBehavior="never"
61
68
  automaticallyAdjustContentInsets={false}
62
69
  contentInset={{ bottom: 0 }}
63
70
  keyboardShouldPersistTaps="handled"
64
71
  showsVerticalScrollIndicator={false}
65
- extraScrollHeight={0}
66
- onContentSizeChange={() => {
67
- 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
+ }
68
101
  }}
69
102
  keyboardDismissMode="none"
70
103
  bounces={false}
71
104
  enableResetScrollToCoords={false}
72
- extraHeight={0}
73
105
  keyboardOpeningTime={0}
74
106
  >
75
107
  {messages.map((msg, i) => (
@@ -98,7 +130,7 @@ export const ChatWindow = ({ panHandlers }) => {
98
130
  {msg.products && msg.products.length > 0 &&
99
131
  msg.products.map((prod, index) => (
100
132
  <View key={index} style={styles.productCardWrapper}>
101
- <ProductCard prod={prod} />
133
+ <ProductCard prod={prod} messageId={msg.message_id} />
102
134
  </View>
103
135
  ))}
104
136
 
@@ -167,6 +199,7 @@ const styles = StyleSheet.create({
167
199
  messagesContent: {
168
200
  padding: 16,
169
201
  justifyContent: 'flex-end',
202
+ paddingBottom: 300,
170
203
  },
171
204
  messageWrapper: {
172
205
  marginBottom: 0,
@@ -16,6 +16,7 @@ export interface ChatState {
16
16
  messages: ChatMessage[];
17
17
  showIcon: boolean;
18
18
  toggleChat: boolean;
19
+ showModal?: string;
19
20
  }
20
21
 
21
22
  // Module-level singleton to cache chat states by token
@@ -35,7 +36,8 @@ export const defaultState: ChatState = {
35
36
  text: "Hi there 👋 I'm Poseidon, your Heritage Pool+ AI Agent. I can help you during your online visit with Product and Account information. How can I help you today?"
36
37
  }],
37
38
  showIcon: true,
38
- toggleChat: false
39
+ toggleChat: false,
40
+ showModal: "Icon"
39
41
  };
40
42
 
41
43
  /**