react-native-srschat 0.1.44 → 0.1.46
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/components/productCard.js +34 -5
- package/lib/commonjs/components/productCard.js.map +1 -1
- package/lib/commonjs/contexts/AppContext.js +84 -31
- package/lib/commonjs/contexts/AppContext.js.map +1 -1
- package/lib/commonjs/hooks/Stream.js +2 -2
- package/lib/commonjs/hooks/Stream.js.map +1 -1
- package/lib/commonjs/layout/window.js +7 -4
- package/lib/commonjs/layout/window.js.map +1 -1
- package/lib/commonjs/utils/storage.js +75 -0
- package/lib/commonjs/utils/storage.js.map +1 -0
- package/lib/module/components/productCard.js +34 -5
- package/lib/module/components/productCard.js.map +1 -1
- package/lib/module/contexts/AppContext.js +83 -31
- package/lib/module/contexts/AppContext.js.map +1 -1
- package/lib/module/hooks/Stream.js +2 -2
- package/lib/module/hooks/Stream.js.map +1 -1
- package/lib/module/layout/window.js +7 -4
- package/lib/module/layout/window.js.map +1 -1
- package/lib/module/utils/storage.js +66 -0
- package/lib/module/utils/storage.js.map +1 -0
- package/lib/typescript/components/productCard.d.ts.map +1 -1
- package/lib/typescript/contexts/AppContext.d.ts.map +1 -1
- package/lib/typescript/layout/window.d.ts.map +1 -1
- package/lib/typescript/utils/storage.d.ts +29 -0
- package/lib/typescript/utils/storage.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/productCard.js +34 -4
- package/src/contexts/AppContext.js +102 -35
- package/src/hooks/Stream.js +2 -2
- package/src/layout/window.js +6 -2
- package/src/utils/storage.ts +88 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
|
+
// Module-level singleton to cache chat states by token
|
|
3
|
+
const chatStore = {};
|
|
4
|
+
const getStorageKey = token => `srschat_${token}`;
|
|
5
|
+
export const defaultState = {
|
|
6
|
+
typingIndicator: false,
|
|
7
|
+
ghostMessage: false,
|
|
8
|
+
ghostCard: false,
|
|
9
|
+
stopActivated: false,
|
|
10
|
+
disclaimer: false,
|
|
11
|
+
startStreaming: false,
|
|
12
|
+
messages: [{
|
|
13
|
+
type: "ai",
|
|
14
|
+
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?"
|
|
15
|
+
}],
|
|
16
|
+
showIcon: true,
|
|
17
|
+
toggleChat: false,
|
|
18
|
+
showModal: "Icon"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Loads chat state for a specific customer token
|
|
23
|
+
* Returns cached state if available, otherwise loads from AsyncStorage
|
|
24
|
+
*/
|
|
25
|
+
export const loadChat = async token => {
|
|
26
|
+
// Return from in-memory cache if available
|
|
27
|
+
if (chatStore[token]) {
|
|
28
|
+
return chatStore[token];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Otherwise load from AsyncStorage
|
|
32
|
+
try {
|
|
33
|
+
const key = getStorageKey(token);
|
|
34
|
+
const storedData = await AsyncStorage.getItem(key);
|
|
35
|
+
if (storedData) {
|
|
36
|
+
const parsedData = JSON.parse(storedData);
|
|
37
|
+
// Cache in memory for future access
|
|
38
|
+
chatStore[token] = parsedData;
|
|
39
|
+
return parsedData;
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Error loading chat state:', error);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Return default state if nothing found
|
|
46
|
+
return defaultState;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Updates chat state for a specific customer token
|
|
51
|
+
* Updates both in-memory cache and persists to AsyncStorage
|
|
52
|
+
*/
|
|
53
|
+
export const updateChat = async (token, next) => {
|
|
54
|
+
try {
|
|
55
|
+
const key = getStorageKey(token);
|
|
56
|
+
|
|
57
|
+
// Update in-memory cache
|
|
58
|
+
chatStore[token] = next;
|
|
59
|
+
|
|
60
|
+
// Persist to AsyncStorage
|
|
61
|
+
await AsyncStorage.setItem(key, JSON.stringify(next));
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('Error updating chat state:', error);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["AsyncStorage","chatStore","getStorageKey","token","defaultState","typingIndicator","ghostMessage","ghostCard","stopActivated","disclaimer","startStreaming","messages","type","text","showIcon","toggleChat","showModal","loadChat","key","storedData","getItem","parsedData","JSON","parse","error","console","updateChat","next","setItem","stringify"],"sourceRoot":"../../../src","sources":["utils/storage.ts"],"mappings":"AAAA,OAAOA,YAAY,MAAM,2CAA2C;AAqBpE;AACA,MAAMC,SAAoC,GAAG,CAAC,CAAC;AAE/C,MAAMC,aAAa,GAAIC,KAAa,IAAK,WAAWA,KAAK,EAAE;AAE3D,OAAO,MAAMC,YAAuB,GAAG;EACrCC,eAAe,EAAE,KAAK;EACtBC,YAAY,EAAE,KAAK;EACnBC,SAAS,EAAE,KAAK;EAChBC,aAAa,EAAE,KAAK;EACpBC,UAAU,EAAE,KAAK;EACjBC,cAAc,EAAE,KAAK;EACrBC,QAAQ,EAAE,CAAC;IACTC,IAAI,EAAE,IAAI;IACVC,IAAI,EAAE;EACR,CAAC,CAAC;EACFC,QAAQ,EAAE,IAAI;EACdC,UAAU,EAAE,KAAK;EACjBC,SAAS,EAAE;AACb,CAAC;;AAED;AACA;AACA;AACA;AACA,OAAO,MAAMC,QAAQ,GAAG,MAAOd,KAAa,IAAyB;EACnE;EACA,IAAIF,SAAS,CAACE,KAAK,CAAC,EAAE;IACpB,OAAOF,SAAS,CAACE,KAAK,CAAC;EACzB;;EAEA;EACA,IAAI;IACF,MAAMe,GAAG,GAAGhB,aAAa,CAACC,KAAK,CAAC;IAChC,MAAMgB,UAAU,GAAG,MAAMnB,YAAY,CAACoB,OAAO,CAACF,GAAG,CAAC;IAElD,IAAIC,UAAU,EAAE;MACd,MAAME,UAAU,GAAGC,IAAI,CAACC,KAAK,CAACJ,UAAU,CAAc;MACtD;MACAlB,SAAS,CAACE,KAAK,CAAC,GAAGkB,UAAU;MAC7B,OAAOA,UAAU;IACnB;EACF,CAAC,CAAC,OAAOG,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,2BAA2B,EAAEA,KAAK,CAAC;EACnD;;EAEA;EACA,OAAOpB,YAAY;AACrB,CAAC;;AAED;AACA;AACA;AACA;AACA,OAAO,MAAMsB,UAAU,GAAG,MAAAA,CAAOvB,KAAa,EAAEwB,IAAe,KAAoB;EACjF,IAAI;IACF,MAAMT,GAAG,GAAGhB,aAAa,CAACC,KAAK,CAAC;;IAEhC;IACAF,SAAS,CAACE,KAAK,CAAC,GAAGwB,IAAI;;IAEvB;IACA,MAAM3B,YAAY,CAAC4B,OAAO,CAACV,GAAG,EAAEI,IAAI,CAACO,SAAS,CAACF,IAAI,CAAC,CAAC;EACvD,CAAC,CAAC,OAAOH,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,4BAA4B,EAAEA,KAAK,CAAC;EACpD;AACF,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"productCard.d.ts","sourceRoot":"","sources":["../../../src/components/productCard.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"productCard.d.ts","sourceRoot":"","sources":["../../../src/components/productCard.js"],"names":[],"mappings":"AAOO;;;sBAqSN;kBA5SsD,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppContext.d.ts","sourceRoot":"","sources":["../../../src/contexts/AppContext.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AppContext.d.ts","sourceRoot":"","sources":["../../../src/contexts/AppContext.js"],"names":[],"mappings":"AAMA,4CAA0C;AAEnC;;;;;;sBA8UN;kBAtV6E,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../../src/layout/window.js"],"names":[],"mappings":"AAeO;;
|
|
1
|
+
{"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../../src/layout/window.js"],"names":[],"mappings":"AAeO;;sBAqJN;kBApK8D,OAAO"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ChatMessage {
|
|
2
|
+
type: string;
|
|
3
|
+
text: string | string[];
|
|
4
|
+
form?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface ChatState {
|
|
7
|
+
typingIndicator: boolean;
|
|
8
|
+
ghostMessage: boolean;
|
|
9
|
+
ghostCard: boolean;
|
|
10
|
+
stopActivated: boolean;
|
|
11
|
+
disclaimer: boolean;
|
|
12
|
+
startStreaming: boolean;
|
|
13
|
+
messages: ChatMessage[];
|
|
14
|
+
showIcon: boolean;
|
|
15
|
+
toggleChat: boolean;
|
|
16
|
+
showModal?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const defaultState: ChatState;
|
|
19
|
+
/**
|
|
20
|
+
* Loads chat state for a specific customer token
|
|
21
|
+
* Returns cached state if available, otherwise loads from AsyncStorage
|
|
22
|
+
*/
|
|
23
|
+
export declare const loadChat: (token: string) => Promise<ChatState>;
|
|
24
|
+
/**
|
|
25
|
+
* Updates chat state for a specific customer token
|
|
26
|
+
* Updates both in-memory cache and persists to AsyncStorage
|
|
27
|
+
*/
|
|
28
|
+
export declare const updateChat: (token: string, next: ChatState) => Promise<void>;
|
|
29
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD,eAAO,MAAM,YAAY,EAAE,SAc1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,SAAS,CAuB/D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAU,OAAO,MAAM,EAAE,MAAM,SAAS,KAAG,OAAO,CAAC,IAAI,CAY7E,CAAC"}
|
package/package.json
CHANGED
|
@@ -2,9 +2,11 @@ import React, { useState, useContext, useEffect } from "react";
|
|
|
2
2
|
import { View, Text, Image, TouchableOpacity, TextInput, StyleSheet, Platform, Keyboard, ActionSheetIOS, Alert } from "react-native";
|
|
3
3
|
import { AppContext } from "../contexts/AppContext";
|
|
4
4
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
export const ProductCard = ({ prod, onFocusQuantityInput }) => {
|
|
7
|
-
const { onProductCardClick, onAddToCartClick } = useContext(AppContext);
|
|
9
|
+
const { onProductCardClick, onAddToCartClick, sessionId, data, ADD_TO_CART_URL } = useContext(AppContext);
|
|
8
10
|
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
|
9
11
|
|
|
10
12
|
const [selectedUom, setSelectedUom] = useState(() => {
|
|
@@ -24,7 +26,8 @@ export const ProductCard = ({ prod, onFocusQuantityInput }) => {
|
|
|
24
26
|
const grossPrice = uomInfo.gross_price || 0;
|
|
25
27
|
const netPrice = uomInfo.net_price || 0;
|
|
26
28
|
const isOnSale = uomInfo.is_on_sale || false;
|
|
27
|
-
const
|
|
29
|
+
const discountsArray = Array.isArray(uomInfo.discounts) ? uomInfo.discounts : [];
|
|
30
|
+
const discountsString = uomInfo.discounts ? uomInfo.discounts : "";
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
|
|
@@ -79,6 +82,30 @@ export const ProductCard = ({ prod, onFocusQuantityInput }) => {
|
|
|
79
82
|
};
|
|
80
83
|
|
|
81
84
|
const handleAddToCart = () => {
|
|
85
|
+
//call add to cart logging endpoint
|
|
86
|
+
try{
|
|
87
|
+
const discount = discountsString ? discountsString : discountsArray.join(", ");
|
|
88
|
+
payload = {
|
|
89
|
+
product_name: prod.product_details.product_name,
|
|
90
|
+
time_stamp: new Date().toISOString(),
|
|
91
|
+
user_id: data.user_id,
|
|
92
|
+
session_id: sessionId,
|
|
93
|
+
quantity: quantity,
|
|
94
|
+
uom: selectedUom,
|
|
95
|
+
is_sale: isOnSale,
|
|
96
|
+
discount_string: discount
|
|
97
|
+
}
|
|
98
|
+
console.log("add to cart payload", payload)
|
|
99
|
+
axios.post(ADD_TO_CART_URL, payload)
|
|
100
|
+
.then(response => {
|
|
101
|
+
console.log("log addToCart response", response)
|
|
102
|
+
})
|
|
103
|
+
.catch(error => {
|
|
104
|
+
console.log("log addToCart error", error)
|
|
105
|
+
})
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.log("log addToCart error", error)
|
|
108
|
+
}
|
|
82
109
|
onAddToCartClick({
|
|
83
110
|
selectedUom: selectedUom,
|
|
84
111
|
quantity: quantity,
|
|
@@ -183,13 +210,16 @@ export const ProductCard = ({ prod, onFocusQuantityInput }) => {
|
|
|
183
210
|
</Text>
|
|
184
211
|
|
|
185
212
|
{/* Display discounts if available */}
|
|
186
|
-
{
|
|
213
|
+
{discountsArray.length > 0 && (
|
|
187
214
|
<View style={styles.discountContainer}>
|
|
188
|
-
{
|
|
215
|
+
{discountsArray.map((discount, index) => (
|
|
189
216
|
<Text key={index} style={styles.discountText}>{discount}</Text>
|
|
190
217
|
))}
|
|
191
218
|
</View>
|
|
192
219
|
)}
|
|
220
|
+
{discountsString && (
|
|
221
|
+
<Text style={styles.discountText}>{discountsString}</Text>
|
|
222
|
+
)}
|
|
193
223
|
|
|
194
224
|
{/* Input Section with UOM Selector and Quantity */}
|
|
195
225
|
<View style={styles.inputRow}>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React, {createContext, useContext, useState, useEffect, useMemo } from "react";
|
|
2
2
|
import uuid from 'react-native-uuid';
|
|
3
3
|
import axios from "axios";
|
|
4
|
-
import useAsyncStorage from '../hooks/useAsyncStorage';
|
|
4
|
+
// import useAsyncStorage from '../hooks/useAsyncStorage';
|
|
5
|
+
import { loadChat, updateChat, defaultState } from '../utils/storage';
|
|
5
6
|
|
|
6
7
|
export const AppContext = createContext();
|
|
7
8
|
|
|
8
9
|
export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConfig = {}, children }) => {
|
|
9
|
-
|
|
10
10
|
const theme = {
|
|
11
11
|
userMessage: '#003764',
|
|
12
12
|
botMessage: '#003764',
|
|
@@ -16,6 +16,9 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
|
|
|
16
16
|
inlineButtonColor: '#dbd4c8',
|
|
17
17
|
primaryColor: '#161616'
|
|
18
18
|
};
|
|
19
|
+
|
|
20
|
+
const TRACK_CLICK_URL = "https://srs-external-agent-logging-586731320826.us-central1.run.app/track-click"
|
|
21
|
+
const ADD_TO_CART_URL = "https://srs-external-agent-logging-586731320826.us-central1.run.app/add-to-cart"
|
|
19
22
|
|
|
20
23
|
// Backend URLs
|
|
21
24
|
const BASE_URL = data.env === "stage"
|
|
@@ -28,31 +31,24 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
|
|
|
28
31
|
const defaultMessage = [
|
|
29
32
|
{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?"}
|
|
30
33
|
]
|
|
31
|
-
|
|
32
34
|
const maintenanceMessage = [
|
|
33
|
-
{ type: "ai", text: "Hi there 👋 I
|
|
35
|
+
{ type: "ai", text: "Hi there 👋 I'm Poseidon, your Heritage Pool+ AI Agent. I'm currently undergoing maintenance to improve my services. Thank you for your patience and understanding!",},
|
|
34
36
|
];
|
|
35
37
|
|
|
38
|
+
|
|
39
|
+
// user data variables
|
|
40
|
+
const customerToken = data.customer_token;
|
|
41
|
+
|
|
42
|
+
|
|
36
43
|
// Base Variables
|
|
37
44
|
const [showModal, setShowModal] = useState("Icon");
|
|
38
45
|
const [input, setInput] = useState('');
|
|
39
|
-
const [messages, setMessages] = useState(
|
|
46
|
+
const [messages, setMessages] = useState(defaultState.messages);
|
|
40
47
|
const [conversationStartTime, setConversationStartTime] = useState(null);
|
|
41
48
|
const [lastUserMessage, setLastUserMessage] = useState("");
|
|
42
49
|
const [lastMessageId, setLastMessageId] = useState("");
|
|
43
50
|
const [sessionId, setSessionId] = useState(null);
|
|
44
51
|
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
const newSessionId = uuid.v4(); // Generate UUID v4
|
|
47
|
-
setSessionId(newSessionId);
|
|
48
|
-
}, []);
|
|
49
|
-
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
if (showModal == "Off") {
|
|
52
|
-
setShowModal("Icon")
|
|
53
|
-
}
|
|
54
|
-
}, [uiConfig.showIcon]);
|
|
55
|
-
|
|
56
52
|
// Message UI
|
|
57
53
|
const [typingIndicator, setTypingIndicator] = useState(false);
|
|
58
54
|
const [ghostMessage, setGhostMessage] = useState(false);
|
|
@@ -61,6 +57,77 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
|
|
|
61
57
|
const [disclaimer, setDisclaimer] = useState(false);
|
|
62
58
|
const [startStreaming, setStartStreaming] = useState(false);
|
|
63
59
|
|
|
60
|
+
// Load persisted state on mount
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!customerToken) return;
|
|
63
|
+
|
|
64
|
+
const init = async () => {
|
|
65
|
+
try {
|
|
66
|
+
const cachedState = await loadChat(customerToken);
|
|
67
|
+
|
|
68
|
+
// Update all stateful values
|
|
69
|
+
setTypingIndicator(cachedState.typingIndicator);
|
|
70
|
+
setGhostMessage(cachedState.ghostMessage);
|
|
71
|
+
setGhostCard(cachedState.ghostCard);
|
|
72
|
+
setStopActivated(cachedState.stopActivated);
|
|
73
|
+
setDisclaimer(cachedState.disclaimer);
|
|
74
|
+
setStartStreaming(cachedState.startStreaming);
|
|
75
|
+
setMessages(cachedState.messages);
|
|
76
|
+
// setShowModal(cachedState.showModal);
|
|
77
|
+
|
|
78
|
+
if (uiConfig.toggleChat === false){
|
|
79
|
+
setShowModal("Icon");
|
|
80
|
+
}else{
|
|
81
|
+
setShowModal("ChatWindow");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Error loading chat state:', error);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
init();
|
|
91
|
+
}, [customerToken, uiConfig.toggleChat]);
|
|
92
|
+
|
|
93
|
+
// Persist state changes
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (!customerToken) return;
|
|
96
|
+
|
|
97
|
+
const persistState = async () => {
|
|
98
|
+
const currentState = {
|
|
99
|
+
typingIndicator,
|
|
100
|
+
ghostMessage,
|
|
101
|
+
ghostCard,
|
|
102
|
+
stopActivated,
|
|
103
|
+
disclaimer,
|
|
104
|
+
startStreaming,
|
|
105
|
+
messages,
|
|
106
|
+
showModal
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
await updateChat(customerToken, currentState);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
persistState();
|
|
113
|
+
}, [
|
|
114
|
+
customerToken,
|
|
115
|
+
typingIndicator,
|
|
116
|
+
ghostMessage,
|
|
117
|
+
ghostCard,
|
|
118
|
+
stopActivated,
|
|
119
|
+
disclaimer,
|
|
120
|
+
startStreaming,
|
|
121
|
+
messages,
|
|
122
|
+
showModal
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (showModal == "Off") {
|
|
127
|
+
setShowModal("Icon")
|
|
128
|
+
}
|
|
129
|
+
}, [uiConfig.showIcon]);
|
|
130
|
+
|
|
64
131
|
const stopGenerating = () => {
|
|
65
132
|
setTypingIndicator(false);
|
|
66
133
|
setStopActivated(true);
|
|
@@ -138,26 +205,26 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
|
|
|
138
205
|
setShowModal("Welcome");
|
|
139
206
|
}
|
|
140
207
|
if (messages.length > 1) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
208
|
+
const newState = {
|
|
209
|
+
...defaultState,
|
|
210
|
+
messages: maintenance ? maintenanceMessage : defaultMessage,
|
|
211
|
+
showModal: maintenance ? "ChatWindow" : "Welcome"
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// Update all state variables
|
|
215
|
+
setMessages(newState.messages);
|
|
148
216
|
setTypingIndicator(false);
|
|
149
217
|
setGhostMessage(false);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
} */
|
|
218
|
+
setShowModal(newState.showModal);
|
|
219
|
+
|
|
220
|
+
// Generate new session
|
|
221
|
+
const newSessionId = uuid.v4();
|
|
222
|
+
setSessionId(newSessionId);
|
|
223
|
+
|
|
224
|
+
// Clear persisted state
|
|
225
|
+
if (customerToken) {
|
|
226
|
+
await updateChat(customerToken, newState);
|
|
227
|
+
}
|
|
161
228
|
}
|
|
162
229
|
};
|
|
163
230
|
|
|
@@ -267,7 +334,7 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
|
|
|
267
334
|
startStreaming, setStartStreaming, maintenance, setMaintenance, feedback, setFeedback, handleFeedback, feedbackOpen, setFeedbackOpen,
|
|
268
335
|
writeFeedback, setWriteFeedback, writeAnswer, setWriteAnswer, BASE_URL, lastMessageId, setLastMessageId,
|
|
269
336
|
onProductCardClick, onAddToCartClick, data, sessionId, setSessionId, handleWrittenFeedback, switchFeedbackOpen, confirmDisclaimer,
|
|
270
|
-
formatChatHistory, uiConfig, handleVoiceSend
|
|
337
|
+
formatChatHistory, uiConfig, handleVoiceSend, TRACK_CLICK_URL, ADD_TO_CART_URL
|
|
271
338
|
}}
|
|
272
339
|
>
|
|
273
340
|
{children}
|
package/src/hooks/Stream.js
CHANGED
|
@@ -52,8 +52,8 @@ export function useWebSocketMessage() {
|
|
|
52
52
|
user_query: lastUserMessage,
|
|
53
53
|
session_id: String(sessionId),
|
|
54
54
|
conversation_start_time: conversationStartTime,
|
|
55
|
-
/* customer_name: "Cristin Connerney",
|
|
56
|
-
user_UUID:
|
|
55
|
+
// /* customer_name: "Cristin Connerney",
|
|
56
|
+
user_UUID: data.user_id || "mobile_user_unspecified",
|
|
57
57
|
device: "mobile",
|
|
58
58
|
window_location: "mobile"
|
|
59
59
|
};
|
package/src/layout/window.js
CHANGED
|
@@ -23,9 +23,13 @@ export const ChatWindow = ({ panHandlers }) => {
|
|
|
23
23
|
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
if (scrollViewRef.current) {
|
|
26
|
-
setTimeout(() => {
|
|
27
|
-
scrollViewRef.current
|
|
26
|
+
const timeoutId = setTimeout(() => {
|
|
27
|
+
if (scrollViewRef.current) {
|
|
28
|
+
scrollViewRef.current.scrollToEnd({ animated: false });
|
|
29
|
+
}
|
|
28
30
|
}, 100);
|
|
31
|
+
|
|
32
|
+
return () => clearTimeout(timeoutId);
|
|
29
33
|
}
|
|
30
34
|
}, []);
|
|
31
35
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
|
+
|
|
3
|
+
export interface ChatMessage {
|
|
4
|
+
type: string;
|
|
5
|
+
text: string | string[];
|
|
6
|
+
form?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ChatState {
|
|
10
|
+
typingIndicator: boolean;
|
|
11
|
+
ghostMessage: boolean;
|
|
12
|
+
ghostCard: boolean;
|
|
13
|
+
stopActivated: boolean;
|
|
14
|
+
disclaimer: boolean;
|
|
15
|
+
startStreaming: boolean;
|
|
16
|
+
messages: ChatMessage[];
|
|
17
|
+
showIcon: boolean;
|
|
18
|
+
toggleChat: boolean;
|
|
19
|
+
showModal?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Module-level singleton to cache chat states by token
|
|
23
|
+
const chatStore: Record<string, ChatState> = {};
|
|
24
|
+
|
|
25
|
+
const getStorageKey = (token: string) => `srschat_${token}`;
|
|
26
|
+
|
|
27
|
+
export const defaultState: ChatState = {
|
|
28
|
+
typingIndicator: false,
|
|
29
|
+
ghostMessage: false,
|
|
30
|
+
ghostCard: false,
|
|
31
|
+
stopActivated: false,
|
|
32
|
+
disclaimer: false,
|
|
33
|
+
startStreaming: false,
|
|
34
|
+
messages: [{
|
|
35
|
+
type: "ai",
|
|
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?"
|
|
37
|
+
}],
|
|
38
|
+
showIcon: true,
|
|
39
|
+
toggleChat: false,
|
|
40
|
+
showModal: "Icon"
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Loads chat state for a specific customer token
|
|
45
|
+
* Returns cached state if available, otherwise loads from AsyncStorage
|
|
46
|
+
*/
|
|
47
|
+
export const loadChat = async (token: string): Promise<ChatState> => {
|
|
48
|
+
// Return from in-memory cache if available
|
|
49
|
+
if (chatStore[token]) {
|
|
50
|
+
return chatStore[token];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Otherwise load from AsyncStorage
|
|
54
|
+
try {
|
|
55
|
+
const key = getStorageKey(token);
|
|
56
|
+
const storedData = await AsyncStorage.getItem(key);
|
|
57
|
+
|
|
58
|
+
if (storedData) {
|
|
59
|
+
const parsedData = JSON.parse(storedData) as ChatState;
|
|
60
|
+
// Cache in memory for future access
|
|
61
|
+
chatStore[token] = parsedData;
|
|
62
|
+
return parsedData;
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Error loading chat state:', error);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Return default state if nothing found
|
|
69
|
+
return defaultState;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Updates chat state for a specific customer token
|
|
74
|
+
* Updates both in-memory cache and persists to AsyncStorage
|
|
75
|
+
*/
|
|
76
|
+
export const updateChat = async (token: string, next: ChatState): Promise<void> => {
|
|
77
|
+
try {
|
|
78
|
+
const key = getStorageKey(token);
|
|
79
|
+
|
|
80
|
+
// Update in-memory cache
|
|
81
|
+
chatStore[token] = next;
|
|
82
|
+
|
|
83
|
+
// Persist to AsyncStorage
|
|
84
|
+
await AsyncStorage.setItem(key, JSON.stringify(next));
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Error updating chat state:', error);
|
|
87
|
+
}
|
|
88
|
+
};
|