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.
@@ -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":"AAKO;;;sBAyQN;kBA9QsD,OAAO"}
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":"AAKA,4CAA0C;AAEnC;;;;;;sBA4QN;kBAnR6E,OAAO"}
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;;sBAiJN;kBAhK8D,OAAO"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-srschat",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "private": false,
5
5
  "description": "A modern, sophisticated chat interface for React Native",
6
6
  "main": "lib/commonjs/index",
@@ -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 discounts = Array.isArray(uomInfo.discounts) ? uomInfo.discounts : [];
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
- {discounts.length > 0 && (
213
+ {discountsArray.length > 0 && (
187
214
  <View style={styles.discountContainer}>
188
- {discounts.map((discount, index) => (
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 👋 Im 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,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
- if (maintenance) {
142
- setMessages(maintenanceMessage);
143
- } else {
144
- setMessages(defaultMessage);
145
- }
146
- const newSessionId = uuid.v4();
147
- setSessionId(newSessionId);
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
- /* 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
- } */
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}
@@ -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
  };
@@ -23,9 +23,13 @@ export const ChatWindow = ({ panHandlers }) => {
23
23
 
24
24
  useEffect(() => {
25
25
  if (scrollViewRef.current) {
26
- setTimeout(() => {
27
- scrollViewRef.current.scrollToEnd({ animated: false });
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
+ };