react-native-srschat 0.1.44 → 0.1.45

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.
@@ -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’m Poseidon, your Heritage Pool+ AI Agent. I'm currently undergoing maintenance to improve my services. Thank you for your patience and understanding!",},
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(defaultMessage);
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,69 @@ 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
+ } catch (error) {
78
+ console.error('Error loading chat state:', error);
79
+ }
80
+ };
81
+
82
+ init();
83
+ }, [customerToken]);
84
+
85
+ // Persist state changes
86
+ useEffect(() => {
87
+ if (!customerToken) return;
88
+
89
+ const persistState = async () => {
90
+ const currentState = {
91
+ typingIndicator,
92
+ ghostMessage,
93
+ ghostCard,
94
+ stopActivated,
95
+ disclaimer,
96
+ startStreaming,
97
+ messages,
98
+ showModal
99
+ };
100
+
101
+ await updateChat(customerToken, currentState);
102
+ };
103
+
104
+ persistState();
105
+ }, [
106
+ customerToken,
107
+ typingIndicator,
108
+ ghostMessage,
109
+ ghostCard,
110
+ stopActivated,
111
+ disclaimer,
112
+ startStreaming,
113
+ messages,
114
+ showModal
115
+ ]);
116
+
117
+ useEffect(() => {
118
+ if (showModal == "Off") {
119
+ setShowModal("Icon")
120
+ }
121
+ }, [uiConfig.showIcon]);
122
+
64
123
  const stopGenerating = () => {
65
124
  setTypingIndicator(false);
66
125
  setStopActivated(true);
@@ -138,26 +197,26 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
138
197
  setShowModal("Welcome");
139
198
  }
140
199
  if (messages.length > 1) {
141
- if (maintenance) {
142
- setMessages(maintenanceMessage);
143
- } else {
144
- setMessages(defaultMessage);
145
- }
146
- const newSessionId = uuid.v4();
147
- setSessionId(newSessionId);
200
+ const newState = {
201
+ ...defaultState,
202
+ messages: maintenance ? maintenanceMessage : defaultMessage,
203
+ showModal: maintenance ? "ChatWindow" : "Welcome"
204
+ };
205
+
206
+ // Update all state variables
207
+ setMessages(newState.messages);
148
208
  setTypingIndicator(false);
149
209
  setGhostMessage(false);
150
- /* try {
151
- const response = await axios.post(API_PREFIX + BASE_URL + "/clear", {
152
- customer_code: data.customer_code,
153
- session_id: data.session_id,
154
- message_id: lastMessageId,
155
- user_UUID: data.user_UUID,
156
- });
157
- console.log(response);
158
- } catch (error) {
159
- console.error("Error in Clear:", error);
160
- } */
210
+ setShowModal(newState.showModal);
211
+
212
+ // Generate new session
213
+ const newSessionId = uuid.v4();
214
+ setSessionId(newSessionId);
215
+
216
+ // Clear persisted state
217
+ if (customerToken) {
218
+ await updateChat(customerToken, newState);
219
+ }
161
220
  }
162
221
  };
163
222
 
@@ -267,7 +326,7 @@ export const AppProvider = ({ data, onProductCardClick, onAddToCartClick, uiConf
267
326
  startStreaming, setStartStreaming, maintenance, setMaintenance, feedback, setFeedback, handleFeedback, feedbackOpen, setFeedbackOpen,
268
327
  writeFeedback, setWriteFeedback, writeAnswer, setWriteAnswer, BASE_URL, lastMessageId, setLastMessageId,
269
328
  onProductCardClick, onAddToCartClick, data, sessionId, setSessionId, handleWrittenFeedback, switchFeedbackOpen, confirmDisclaimer,
270
- formatChatHistory, uiConfig, handleVoiceSend
329
+ formatChatHistory, uiConfig, handleVoiceSend, TRACK_CLICK_URL, ADD_TO_CART_URL
271
330
  }}
272
331
  >
273
332
  {children}
@@ -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: "cristin.connerney@srsdistribution.com", */
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
  };
@@ -0,0 +1,86 @@
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
+ }
20
+
21
+ // Module-level singleton to cache chat states by token
22
+ const chatStore: Record<string, ChatState> = {};
23
+
24
+ const getStorageKey = (token: string) => `srschat_${token}`;
25
+
26
+ export const defaultState: ChatState = {
27
+ typingIndicator: false,
28
+ ghostMessage: false,
29
+ ghostCard: false,
30
+ stopActivated: false,
31
+ disclaimer: false,
32
+ startStreaming: false,
33
+ messages: [{
34
+ type: "ai",
35
+ 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
+ showIcon: true,
38
+ toggleChat: false
39
+ };
40
+
41
+ /**
42
+ * Loads chat state for a specific customer token
43
+ * Returns cached state if available, otherwise loads from AsyncStorage
44
+ */
45
+ export const loadChat = async (token: string): Promise<ChatState> => {
46
+ // Return from in-memory cache if available
47
+ if (chatStore[token]) {
48
+ return chatStore[token];
49
+ }
50
+
51
+ // Otherwise load from AsyncStorage
52
+ try {
53
+ const key = getStorageKey(token);
54
+ const storedData = await AsyncStorage.getItem(key);
55
+
56
+ if (storedData) {
57
+ const parsedData = JSON.parse(storedData) as ChatState;
58
+ // Cache in memory for future access
59
+ chatStore[token] = parsedData;
60
+ return parsedData;
61
+ }
62
+ } catch (error) {
63
+ console.error('Error loading chat state:', error);
64
+ }
65
+
66
+ // Return default state if nothing found
67
+ return defaultState;
68
+ };
69
+
70
+ /**
71
+ * Updates chat state for a specific customer token
72
+ * Updates both in-memory cache and persists to AsyncStorage
73
+ */
74
+ export const updateChat = async (token: string, next: ChatState): Promise<void> => {
75
+ try {
76
+ const key = getStorageKey(token);
77
+
78
+ // Update in-memory cache
79
+ chatStore[token] = next;
80
+
81
+ // Persist to AsyncStorage
82
+ await AsyncStorage.setItem(key, JSON.stringify(next));
83
+ } catch (error) {
84
+ console.error('Error updating chat state:', error);
85
+ }
86
+ };