react-native-srschat 0.1.7 → 0.1.8
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/lib/commonjs/assets/heritage.png +0 -0
- package/lib/commonjs/components/header.js +105 -0
- package/lib/commonjs/components/header.js.map +1 -0
- package/lib/commonjs/components/testing.js +58 -0
- package/lib/commonjs/components/testing.js.map +1 -0
- package/lib/commonjs/contexts/AppContext.js +99 -0
- package/lib/commonjs/contexts/AppContext.js.map +1 -0
- package/lib/commonjs/hooks/Stream.js +202 -0
- package/lib/commonjs/hooks/Stream.js.map +1 -0
- package/lib/commonjs/index.js +13 -262
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/layout/chatIcon.js +53 -0
- package/lib/commonjs/layout/chatIcon.js.map +1 -0
- package/lib/commonjs/layout/chatWindow.js +208 -0
- package/lib/commonjs/layout/chatWindow.js.map +1 -0
- package/lib/commonjs/layout/layout.js +35 -0
- package/lib/commonjs/layout/layout.js.map +1 -0
- package/lib/module/assets/heritage.png +0 -0
- package/lib/module/components/header.js +96 -0
- package/lib/module/components/header.js.map +1 -0
- package/lib/module/components/testing.js +50 -0
- package/lib/module/components/testing.js.map +1 -0
- package/lib/module/contexts/AppContext.js +90 -0
- package/lib/module/contexts/AppContext.js.map +1 -0
- package/lib/module/hooks/Stream.js +194 -0
- package/lib/module/hooks/Stream.js.map +1 -0
- package/lib/module/index.js +11 -261
- package/lib/module/index.js.map +1 -1
- package/lib/module/layout/chatIcon.js +44 -0
- package/lib/module/layout/chatIcon.js.map +1 -0
- package/lib/module/layout/chatWindow.js +199 -0
- package/lib/module/layout/chatWindow.js.map +1 -0
- package/lib/module/layout/layout.js +26 -0
- package/lib/module/layout/layout.js.map +1 -0
- package/lib/typescript/components/header.d.ts +3 -0
- package/lib/typescript/components/header.d.ts.map +1 -0
- package/lib/typescript/components/testing.d.ts +6 -0
- package/lib/typescript/components/testing.d.ts.map +1 -0
- package/lib/typescript/contexts/AppContext.d.ts +6 -0
- package/lib/typescript/contexts/AppContext.d.ts.map +1 -0
- package/lib/typescript/hooks/Stream.d.ts +2 -0
- package/lib/typescript/hooks/Stream.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +5 -12
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/layout/chatIcon.d.ts +3 -0
- package/lib/typescript/layout/chatIcon.d.ts.map +1 -0
- package/lib/typescript/layout/chatWindow.d.ts +6 -0
- package/lib/typescript/layout/chatWindow.d.ts.map +1 -0
- package/lib/typescript/layout/layout.d.ts +6 -0
- package/lib/typescript/layout/layout.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/assets/heritage.png +0 -0
- package/src/components/header.js +89 -0
- package/src/components/testing.js +47 -0
- package/src/contexts/AppContext.js +83 -0
- package/src/hooks/Stream.js +198 -0
- package/src/index.js +18 -0
- package/src/layout/chatIcon.js +38 -0
- package/src/layout/chatWindow.js +200 -0
- package/src/layout/layout.js +23 -0
- package/src/index.tsx +0 -323
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":"AAOO;;;;sBAON;kBAd4C,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatIcon.d.ts","sourceRoot":"","sources":["../../../src/layout/chatIcon.js"],"names":[],"mappings":"AAKO,8CAUN;kBAfiC,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatWindow.d.ts","sourceRoot":"","sources":["../../../src/layout/chatWindow.js"],"names":[],"mappings":"AAeO;;;sBA0FN;kBAzGwD,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/layout/layout.js"],"names":[],"mappings":"AAQO;;;sBAQN;kBAhBwD,OAAO"}
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { View, Text, TouchableOpacity, StyleSheet, Image } from 'react-native';
|
|
3
|
+
import { Ionicons as Icon } from '@expo/vector-icons';
|
|
4
|
+
import { AppContext } from '../contexts/AppContext';
|
|
5
|
+
|
|
6
|
+
export const Header = () => {
|
|
7
|
+
const { setShowModal } = useContext(AppContext);
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<View style={styles.header}>
|
|
11
|
+
{/* Logo on the left */}
|
|
12
|
+
<View style={styles.section}>
|
|
13
|
+
<Image source={require('../assets/heritage.png')} style={styles.logo} />
|
|
14
|
+
</View>
|
|
15
|
+
|
|
16
|
+
{/* Title in the center */}
|
|
17
|
+
<View style={[styles.section, styles.titleContainer]}>
|
|
18
|
+
<View style={styles.titleWrapper}>
|
|
19
|
+
<Text style={styles.title}>
|
|
20
|
+
Poseidon
|
|
21
|
+
</Text>
|
|
22
|
+
<Text style={styles.betaText}><Icon style={styles.icon} name="sparkles-outline" size={10} color="#007AFF" />beta</Text>
|
|
23
|
+
</View>
|
|
24
|
+
</View>
|
|
25
|
+
|
|
26
|
+
{/* Close button on the right */}
|
|
27
|
+
<View style={styles.iconsSection}>
|
|
28
|
+
<TouchableOpacity onPress={() => setShowModal("Icon")}>
|
|
29
|
+
<Icon name="trash" size={24} color="gray" />
|
|
30
|
+
</TouchableOpacity>
|
|
31
|
+
<TouchableOpacity onPress={() => setShowModal("Icon")}>
|
|
32
|
+
<Icon name="chevron-down" size={24} color="gray" />
|
|
33
|
+
</TouchableOpacity>
|
|
34
|
+
</View>
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const styles = StyleSheet.create({
|
|
40
|
+
header: {
|
|
41
|
+
flexDirection: 'row',
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
backgroundColor: '#f6f6f6',
|
|
44
|
+
padding: 16,
|
|
45
|
+
borderBottomWidth: 1,
|
|
46
|
+
borderBottomColor: '#ddd',
|
|
47
|
+
},
|
|
48
|
+
section: {
|
|
49
|
+
flex: 1,
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
},
|
|
52
|
+
iconsSection: {
|
|
53
|
+
flex: 1,
|
|
54
|
+
display: 'flex',
|
|
55
|
+
flexDirection: 'row',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
justifyContent: 'flex-end'
|
|
58
|
+
},
|
|
59
|
+
logo: {
|
|
60
|
+
width: 100,
|
|
61
|
+
height: 40,
|
|
62
|
+
resizeMode: 'contain',
|
|
63
|
+
},
|
|
64
|
+
icon: {
|
|
65
|
+
paddingLeft: 2,
|
|
66
|
+
paddingRight: 2
|
|
67
|
+
},
|
|
68
|
+
titleContainer: {
|
|
69
|
+
flex: 2, // Slightly larger space for the title
|
|
70
|
+
},
|
|
71
|
+
titleWrapper: {
|
|
72
|
+
alignItems: 'center',
|
|
73
|
+
justifyContent: 'center',
|
|
74
|
+
},
|
|
75
|
+
title: {
|
|
76
|
+
fontSize: 20,
|
|
77
|
+
fontWeight: 'medium',
|
|
78
|
+
color: '#000',
|
|
79
|
+
textAlign: 'center',
|
|
80
|
+
flexDirection: 'row',
|
|
81
|
+
},
|
|
82
|
+
betaText: {
|
|
83
|
+
fontSize: 12,
|
|
84
|
+
color: 'gray',
|
|
85
|
+
position: 'absolute',
|
|
86
|
+
top: -10,
|
|
87
|
+
right: -35,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Button, StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export const Testing = ({ onProductCardClick, onAddToCartClick }) => {
|
|
5
|
+
|
|
6
|
+
const product = {
|
|
7
|
+
"part_number": "AEQO177",
|
|
8
|
+
"inventory_info": {
|
|
9
|
+
"default_uom": "EA",
|
|
10
|
+
"is_valid": true,
|
|
11
|
+
"info_by_uom": {
|
|
12
|
+
"EA": {
|
|
13
|
+
"gross_price": 7.83,
|
|
14
|
+
"net_price": 7.83,
|
|
15
|
+
"is_on_sale": false,
|
|
16
|
+
"quantity_available": 0,
|
|
17
|
+
"discounts": null
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"product_details": {
|
|
22
|
+
"product_name": "Aladdin Hayward SPX1600S SuperPump Lid Gasket | O-177-2",
|
|
23
|
+
"part_number": "AEQO177",
|
|
24
|
+
"manufacturer_id": "O-177-2",
|
|
25
|
+
"heritage_link": "https://www.heritagepoolplus.com/aeqo177-aladdin-o-ring-o-177-o-177-2-o-177-2",
|
|
26
|
+
"image_url": "https://media.heritageplus.com/image/upload/v1668157956/image/AEQO177_0.jpg"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View style={styles.container}>
|
|
32
|
+
<Button title="Product Card Click" onPress={() => onProductCardClick(product)} />
|
|
33
|
+
<Button title="Add to Cart" onPress={() => onAddToCartClick(product)} />
|
|
34
|
+
</View>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const styles = StyleSheet.create({
|
|
39
|
+
container: {
|
|
40
|
+
flexDirection: 'row',
|
|
41
|
+
justifyContent: 'space-evenly',
|
|
42
|
+
marginVertical: 10,
|
|
43
|
+
paddingHorizontal: 16,
|
|
44
|
+
borderTopWidth: 1,
|
|
45
|
+
borderTopColor: '#DDD',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React, {createContext, useContext, useState, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
export const AppContext = createContext();
|
|
4
|
+
|
|
5
|
+
export const AppProvider = ({ children }) => {
|
|
6
|
+
|
|
7
|
+
const [showModal, setShowModal] = useState("Icon");
|
|
8
|
+
|
|
9
|
+
const [input, setInput] = useState('');
|
|
10
|
+
const [messages, setMessages] = useState([
|
|
11
|
+
{type: "ai", 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?"},
|
|
12
|
+
{type: "user", text: "Do you carry Hayward super pumps?"},
|
|
13
|
+
{type: "ai", text: "Could you provide more details on the specific model or horsepower you are interested in for the Hayward Super Pump? We have various models with different features, such as variable speed settings and different horsepower ratings. Alternatively, I can offer you some recommendations right away to help you decide."},
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
const handleSend = async () => {
|
|
17
|
+
if (!input.trim()) return;
|
|
18
|
+
|
|
19
|
+
const userMessage = input;
|
|
20
|
+
setInput('');
|
|
21
|
+
|
|
22
|
+
// Add user message to the list
|
|
23
|
+
setMessages((prev) => [...prev, { type: "user", text: userMessage }]);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Add placeholder for AI message
|
|
27
|
+
setMessages((prev) => [...prev, { type: "ai", text: '' }]);
|
|
28
|
+
|
|
29
|
+
// Simulate response with streaming
|
|
30
|
+
const response = await onSendMessage(userMessage, (chunk) => {
|
|
31
|
+
setMessages((prev) => {
|
|
32
|
+
const newMessages = [...prev];
|
|
33
|
+
const lastMessage = newMessages[newMessages.length - 1];
|
|
34
|
+
if (lastMessage && lastMessage.type === "ai") {
|
|
35
|
+
lastMessage.text += chunk;
|
|
36
|
+
}
|
|
37
|
+
return newMessages;
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Finalize AI response
|
|
42
|
+
setMessages((prev) => {
|
|
43
|
+
const newMessages = [...prev];
|
|
44
|
+
const lastMessage = newMessages[newMessages.length - 1];
|
|
45
|
+
if (lastMessage && lastMessage.type === "ai" && lastMessage.text !== response) {
|
|
46
|
+
lastMessage.text = response;
|
|
47
|
+
}
|
|
48
|
+
return newMessages;
|
|
49
|
+
});
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('Error sending message:', error);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const onSendMessage = async (message, onStream) => {
|
|
56
|
+
try {
|
|
57
|
+
if (onStream) {
|
|
58
|
+
const words = `You said: ${message}`.split(' ');
|
|
59
|
+
for (const word of words) {
|
|
60
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
61
|
+
onStream(word + ' ');
|
|
62
|
+
}
|
|
63
|
+
return `You said: ${message}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
67
|
+
return `You said: ${message}`;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Error handling message:', error);
|
|
70
|
+
return 'Error processing message';
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<AppContext.Provider
|
|
77
|
+
value={{ showModal, setShowModal, messages, setMessages, handleSend, onSendMessage, input, setInput
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</AppContext.Provider>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useContext } from 'react';
|
|
2
|
+
import { AppContext } from "../contexts/AppContext";
|
|
3
|
+
|
|
4
|
+
export function useWebSocketMessage() {
|
|
5
|
+
const { setIsComplete, startStreaming, setMessages, messages, setGhostMessage, isMobile,
|
|
6
|
+
setTypingIndicator, setStartStreaming, lastUserMessage, stopActivated, custEmail, custName, data,
|
|
7
|
+
setGhostCard, BASE_URL, setStopActivated, setLastMessageId } = useContext(AppContext);
|
|
8
|
+
|
|
9
|
+
const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
|
10
|
+
const wsUrl = BASE_URL.replace(/^http(s)?:\/\//, '');
|
|
11
|
+
const ENDPOINT = '/send/event';
|
|
12
|
+
|
|
13
|
+
const payload = {
|
|
14
|
+
...data,
|
|
15
|
+
user_query: lastUserMessage,
|
|
16
|
+
customer_name: data.customer_name
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const wsRef = useRef(null);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (startStreaming) {
|
|
23
|
+
console.log(payload)
|
|
24
|
+
const socketUrl = `${wsProtocol}${wsUrl}${ENDPOINT}`;
|
|
25
|
+
const ws = new WebSocket(socketUrl);
|
|
26
|
+
wsRef.current = ws;
|
|
27
|
+
|
|
28
|
+
ws.onopen = () => {
|
|
29
|
+
console.log("WebSocket connection established.");
|
|
30
|
+
ws.send(JSON.stringify(payload));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
ws.onmessage = (event) => {
|
|
34
|
+
const response = JSON.parse(event.data);
|
|
35
|
+
console.log(response)
|
|
36
|
+
switch (response.type) {
|
|
37
|
+
case 'middle_message':
|
|
38
|
+
const middleMessage = {
|
|
39
|
+
type: "middle",
|
|
40
|
+
text: response.message,
|
|
41
|
+
products: [],
|
|
42
|
+
product_cards: "False",
|
|
43
|
+
}
|
|
44
|
+
setMessages([...messages, middleMessage])
|
|
45
|
+
break;
|
|
46
|
+
case 'message':
|
|
47
|
+
if (response.product_cards == "False" || response.product_cards == false ) {
|
|
48
|
+
setGhostMessage(false);
|
|
49
|
+
setTypingIndicator(false)
|
|
50
|
+
} else {
|
|
51
|
+
setGhostMessage(false)
|
|
52
|
+
setGhostCard(true)
|
|
53
|
+
}
|
|
54
|
+
const newMessage = {
|
|
55
|
+
type: "ai",
|
|
56
|
+
message_id: response.message_id || '',
|
|
57
|
+
text: [response.message],
|
|
58
|
+
feedback: "True",
|
|
59
|
+
products: [],
|
|
60
|
+
product_cards: response.product_cards || "False",
|
|
61
|
+
resource: response?.resource_details?.[0]?.link ?? "",
|
|
62
|
+
resource_type: response?.resource_details?.[0]?.type ?? ""
|
|
63
|
+
};
|
|
64
|
+
setMessages((prevMessages) => [...prevMessages, newMessage]);
|
|
65
|
+
setLastMessageId(response.message_id)
|
|
66
|
+
break;
|
|
67
|
+
case 'chunk':
|
|
68
|
+
const newContent = response.chunk;
|
|
69
|
+
const newMessageId = response.message_id;
|
|
70
|
+
setMessages(prevMessages => {
|
|
71
|
+
const lastMessageIndex = prevMessages.length - 1;
|
|
72
|
+
if (prevMessages[lastMessageIndex] && prevMessages[lastMessageIndex].type === "ai") {
|
|
73
|
+
const updatedLastMessage = {
|
|
74
|
+
...prevMessages[lastMessageIndex],
|
|
75
|
+
text: [prevMessages[lastMessageIndex].text[0] + newContent],
|
|
76
|
+
message_id: newMessageId || prevMessages[lastMessageIndex].message_id,
|
|
77
|
+
feedback: "True"
|
|
78
|
+
};
|
|
79
|
+
return [
|
|
80
|
+
...prevMessages.slice(0, lastMessageIndex),
|
|
81
|
+
updatedLastMessage
|
|
82
|
+
];
|
|
83
|
+
} else {
|
|
84
|
+
setGhostMessage(false);
|
|
85
|
+
return [...prevMessages, {
|
|
86
|
+
type: "ai",
|
|
87
|
+
text: [newContent],
|
|
88
|
+
message_id: newMessageId,
|
|
89
|
+
feedback: "True"
|
|
90
|
+
}];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (newMessageId) {
|
|
94
|
+
setLastMessageId(newMessageId);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case 'product_cards':
|
|
98
|
+
setMessages(prevMessages => {
|
|
99
|
+
const lastMessageIndex = prevMessages.length - 1;
|
|
100
|
+
if (prevMessages[lastMessageIndex] && prevMessages[lastMessageIndex].type === "ai") {
|
|
101
|
+
const updatedLastMessage = {
|
|
102
|
+
...prevMessages[lastMessageIndex],
|
|
103
|
+
products: response.products || [],
|
|
104
|
+
product_cards: "True"
|
|
105
|
+
};
|
|
106
|
+
return [
|
|
107
|
+
...prevMessages.slice(0, lastMessageIndex),
|
|
108
|
+
updatedLastMessage
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
setGhostMessage(false);
|
|
113
|
+
setTypingIndicator(false)
|
|
114
|
+
setGhostCard(false)
|
|
115
|
+
break;
|
|
116
|
+
case 'product_document':
|
|
117
|
+
setMessages(prevMessages => {
|
|
118
|
+
const lastMessageIndex = prevMessages.length - 1;
|
|
119
|
+
if (prevMessages[lastMessageIndex] && prevMessages[lastMessageIndex].type === "ai") {
|
|
120
|
+
const updatedLastMessage = {
|
|
121
|
+
...prevMessages[lastMessageIndex],
|
|
122
|
+
resource: response?.resource_details?.[0]?.link ?? "",
|
|
123
|
+
resource_type: response?.resource_details?.[0]?.type ?? ""
|
|
124
|
+
};
|
|
125
|
+
return [
|
|
126
|
+
...prevMessages.slice(0, lastMessageIndex),
|
|
127
|
+
updatedLastMessage
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
setGhostMessage(false);
|
|
132
|
+
setTypingIndicator(false)
|
|
133
|
+
setGhostCard(false)
|
|
134
|
+
break;
|
|
135
|
+
case 'suggested_questions':
|
|
136
|
+
/* const questions = {
|
|
137
|
+
type: "questions",
|
|
138
|
+
message_id: response.message_id || '',
|
|
139
|
+
suggested_questions: response.suggested_questions || [],
|
|
140
|
+
}; */
|
|
141
|
+
setMessages(prevMessages => {
|
|
142
|
+
const lastMessageIndex = prevMessages.length - 1;
|
|
143
|
+
if (prevMessages[lastMessageIndex] && prevMessages[lastMessageIndex].type === "ai") {
|
|
144
|
+
const updatedLastMessage = {
|
|
145
|
+
...prevMessages[lastMessageIndex],
|
|
146
|
+
suggested_questions: true,
|
|
147
|
+
questions: response.suggested_questions
|
|
148
|
+
};
|
|
149
|
+
return [
|
|
150
|
+
...prevMessages.slice(0, lastMessageIndex),
|
|
151
|
+
updatedLastMessage
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
//setMessages((prevMessages) => [...prevMessages, questions]);
|
|
156
|
+
break;
|
|
157
|
+
case 'setComplete':
|
|
158
|
+
setIsComplete(true);
|
|
159
|
+
setTypingIndicator(false);
|
|
160
|
+
setStartStreaming(false)
|
|
161
|
+
setGhostCard(false)
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
ws.onerror = (error) => {
|
|
167
|
+
setStartStreaming(false)
|
|
168
|
+
setGhostMessage(false);
|
|
169
|
+
setTypingIndicator(false)
|
|
170
|
+
setGhostCard(false)
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
ws.onclose = (event) => {
|
|
174
|
+
console.log("WebSocket connection closed:", event.reason);
|
|
175
|
+
setStartStreaming(false)
|
|
176
|
+
setGhostMessage(false);
|
|
177
|
+
setTypingIndicator(false)
|
|
178
|
+
setGhostCard(false)
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
return () => {
|
|
182
|
+
ws.close();
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
}, [startStreaming]);
|
|
186
|
+
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
|
189
|
+
wsRef.current.close();
|
|
190
|
+
setStartStreaming(false);
|
|
191
|
+
setGhostMessage(false)
|
|
192
|
+
setGhostCard(false)
|
|
193
|
+
setTypingIndicator(false)
|
|
194
|
+
setStopActivated(false)
|
|
195
|
+
}
|
|
196
|
+
}, [stopActivated, setStartStreaming]);
|
|
197
|
+
|
|
198
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { SafeAreaView, Text, StyleSheet, View, TextInput, ScrollView, KeyboardAvoidingView,
|
|
3
|
+
Platform, TouchableOpacity, RefreshControl, } from 'react-native';
|
|
4
|
+
import { Ionicons as Icon } from '@expo/vector-icons';
|
|
5
|
+
import { AppProvider } from './contexts/AppContext';
|
|
6
|
+
import { Layout } from './layout/layout'
|
|
7
|
+
|
|
8
|
+
export const Chat = ({data, onProductCardClick, onAddToCartClick }) => {
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<AppProvider>
|
|
12
|
+
<Layout onProductCardClick={onProductCardClick} onAddToCartClick={onAddToCartClick}/>
|
|
13
|
+
</AppProvider>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const styles = StyleSheet.create({
|
|
18
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { TouchableOpacity, View, StyleSheet } from 'react-native';
|
|
3
|
+
import { Ionicons as Icon } from '@expo/vector-icons';
|
|
4
|
+
import { AppContext } from '../contexts/AppContext';
|
|
5
|
+
|
|
6
|
+
export const ChatIcon = () => {
|
|
7
|
+
const { setShowModal } = useContext(AppContext);
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TouchableOpacity style={styles.iconContainer} onPress={() => setShowModal("ChatWindow")}>
|
|
11
|
+
<View style={styles.icon}>
|
|
12
|
+
<Icon name="chatbubble-ellipses" size={28} color="white" />
|
|
13
|
+
</View>
|
|
14
|
+
</TouchableOpacity>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const styles = StyleSheet.create({
|
|
19
|
+
iconContainer: {
|
|
20
|
+
position: 'absolute',
|
|
21
|
+
bottom: 80,
|
|
22
|
+
right: 20,
|
|
23
|
+
zIndex: 10,
|
|
24
|
+
},
|
|
25
|
+
icon: {
|
|
26
|
+
backgroundColor: '#FFA500',
|
|
27
|
+
width: 60,
|
|
28
|
+
height: 60,
|
|
29
|
+
borderRadius: 30,
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
justifyContent: 'center',
|
|
32
|
+
shadowColor: '#000',
|
|
33
|
+
shadowOffset: { width: 0, height: 2 },
|
|
34
|
+
shadowOpacity: 0.2,
|
|
35
|
+
shadowRadius: 3,
|
|
36
|
+
elevation: 5,
|
|
37
|
+
},
|
|
38
|
+
});
|