srs-heritage-chatbot 1.0.0

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 (187) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +194 -0
  3. package/lib/commonjs/assets/chat-icon-mobile.svg +1 -0
  4. package/lib/commonjs/assets/heritage.png +0 -0
  5. package/lib/commonjs/assets/posiden.svg +51 -0
  6. package/lib/commonjs/components/LoadingTips.js +104 -0
  7. package/lib/commonjs/components/LoadingTips.js.map +1 -0
  8. package/lib/commonjs/components/email.js +461 -0
  9. package/lib/commonjs/components/email.js.map +1 -0
  10. package/lib/commonjs/components/feedback.js +114 -0
  11. package/lib/commonjs/components/feedback.js.map +1 -0
  12. package/lib/commonjs/components/header.js +126 -0
  13. package/lib/commonjs/components/header.js.map +1 -0
  14. package/lib/commonjs/components/input.js +144 -0
  15. package/lib/commonjs/components/input.js.map +1 -0
  16. package/lib/commonjs/components/productCard.js +688 -0
  17. package/lib/commonjs/components/productCard.js.map +1 -0
  18. package/lib/commonjs/components/progressCircle.js +99 -0
  19. package/lib/commonjs/components/progressCircle.js.map +1 -0
  20. package/lib/commonjs/components/testing.js +74 -0
  21. package/lib/commonjs/components/testing.js.map +1 -0
  22. package/lib/commonjs/components/voice.js +184 -0
  23. package/lib/commonjs/components/voice.js.map +1 -0
  24. package/lib/commonjs/components/welcomeButton.js +149 -0
  25. package/lib/commonjs/components/welcomeButton.js.map +1 -0
  26. package/lib/commonjs/components/welcomeInput.js +137 -0
  27. package/lib/commonjs/components/welcomeInput.js.map +1 -0
  28. package/lib/commonjs/contexts/AppContext.js +552 -0
  29. package/lib/commonjs/contexts/AppContext.js.map +1 -0
  30. package/lib/commonjs/hooks/Stream.js +599 -0
  31. package/lib/commonjs/hooks/Stream.js.map +1 -0
  32. package/lib/commonjs/hooks/useAsyncStorage.js +36 -0
  33. package/lib/commonjs/hooks/useAsyncStorage.js.map +1 -0
  34. package/lib/commonjs/index.js +44 -0
  35. package/lib/commonjs/index.js.map +1 -0
  36. package/lib/commonjs/layout/disclaimer.js +208 -0
  37. package/lib/commonjs/layout/disclaimer.js.map +1 -0
  38. package/lib/commonjs/layout/ex.js +254 -0
  39. package/lib/commonjs/layout/ex.js.map +1 -0
  40. package/lib/commonjs/layout/icon.js +118 -0
  41. package/lib/commonjs/layout/icon.js.map +1 -0
  42. package/lib/commonjs/layout/layout.js +168 -0
  43. package/lib/commonjs/layout/layout.js.map +1 -0
  44. package/lib/commonjs/layout/welcome.js +160 -0
  45. package/lib/commonjs/layout/welcome.js.map +1 -0
  46. package/lib/commonjs/layout/window.js +396 -0
  47. package/lib/commonjs/layout/window.js.map +1 -0
  48. package/lib/commonjs/utils/audioRecorder.js +412 -0
  49. package/lib/commonjs/utils/audioRecorder.js.map +1 -0
  50. package/lib/commonjs/utils/cloudinary.js +69 -0
  51. package/lib/commonjs/utils/cloudinary.js.map +1 -0
  52. package/lib/commonjs/utils/storage.js +76 -0
  53. package/lib/commonjs/utils/storage.js.map +1 -0
  54. package/lib/commonjs/utils/textToSpeech.js +53 -0
  55. package/lib/commonjs/utils/textToSpeech.js.map +1 -0
  56. package/lib/module/assets/chat-icon-mobile.svg +1 -0
  57. package/lib/module/assets/heritage.png +0 -0
  58. package/lib/module/assets/posiden.svg +51 -0
  59. package/lib/module/components/LoadingTips.js +95 -0
  60. package/lib/module/components/LoadingTips.js.map +1 -0
  61. package/lib/module/components/email.js +452 -0
  62. package/lib/module/components/email.js.map +1 -0
  63. package/lib/module/components/feedback.js +105 -0
  64. package/lib/module/components/feedback.js.map +1 -0
  65. package/lib/module/components/header.js +117 -0
  66. package/lib/module/components/header.js.map +1 -0
  67. package/lib/module/components/input.js +135 -0
  68. package/lib/module/components/input.js.map +1 -0
  69. package/lib/module/components/productCard.js +679 -0
  70. package/lib/module/components/productCard.js.map +1 -0
  71. package/lib/module/components/progressCircle.js +91 -0
  72. package/lib/module/components/progressCircle.js.map +1 -0
  73. package/lib/module/components/testing.js +66 -0
  74. package/lib/module/components/testing.js.map +1 -0
  75. package/lib/module/components/voice.js +175 -0
  76. package/lib/module/components/voice.js.map +1 -0
  77. package/lib/module/components/welcomeButton.js +140 -0
  78. package/lib/module/components/welcomeButton.js.map +1 -0
  79. package/lib/module/components/welcomeInput.js +128 -0
  80. package/lib/module/components/welcomeInput.js.map +1 -0
  81. package/lib/module/contexts/AppContext.js +542 -0
  82. package/lib/module/contexts/AppContext.js.map +1 -0
  83. package/lib/module/hooks/Stream.js +592 -0
  84. package/lib/module/hooks/Stream.js.map +1 -0
  85. package/lib/module/hooks/useAsyncStorage.js +29 -0
  86. package/lib/module/hooks/useAsyncStorage.js.map +1 -0
  87. package/lib/module/index.js +36 -0
  88. package/lib/module/index.js.map +1 -0
  89. package/lib/module/layout/disclaimer.js +199 -0
  90. package/lib/module/layout/disclaimer.js.map +1 -0
  91. package/lib/module/layout/ex.js +253 -0
  92. package/lib/module/layout/ex.js.map +1 -0
  93. package/lib/module/layout/icon.js +108 -0
  94. package/lib/module/layout/icon.js.map +1 -0
  95. package/lib/module/layout/layout.js +160 -0
  96. package/lib/module/layout/layout.js.map +1 -0
  97. package/lib/module/layout/welcome.js +150 -0
  98. package/lib/module/layout/welcome.js.map +1 -0
  99. package/lib/module/layout/window.js +387 -0
  100. package/lib/module/layout/window.js.map +1 -0
  101. package/lib/module/utils/audioRecorder.js +398 -0
  102. package/lib/module/utils/audioRecorder.js.map +1 -0
  103. package/lib/module/utils/cloudinary.js +61 -0
  104. package/lib/module/utils/cloudinary.js.map +1 -0
  105. package/lib/module/utils/storage.js +67 -0
  106. package/lib/module/utils/storage.js.map +1 -0
  107. package/lib/module/utils/textToSpeech.js +43 -0
  108. package/lib/module/utils/textToSpeech.js.map +1 -0
  109. package/lib/typescript/components/LoadingTips.d.ts +3 -0
  110. package/lib/typescript/components/LoadingTips.d.ts.map +1 -0
  111. package/lib/typescript/components/email.d.ts +6 -0
  112. package/lib/typescript/components/email.d.ts.map +1 -0
  113. package/lib/typescript/components/feedback.d.ts +6 -0
  114. package/lib/typescript/components/feedback.d.ts.map +1 -0
  115. package/lib/typescript/components/header.d.ts +3 -0
  116. package/lib/typescript/components/header.d.ts.map +1 -0
  117. package/lib/typescript/components/input.d.ts +6 -0
  118. package/lib/typescript/components/input.d.ts.map +1 -0
  119. package/lib/typescript/components/productCard.d.ts +7 -0
  120. package/lib/typescript/components/productCard.d.ts.map +1 -0
  121. package/lib/typescript/components/progressCircle.d.ts +3 -0
  122. package/lib/typescript/components/progressCircle.d.ts.map +1 -0
  123. package/lib/typescript/components/testing.d.ts +6 -0
  124. package/lib/typescript/components/testing.d.ts.map +1 -0
  125. package/lib/typescript/components/voice.d.ts +5 -0
  126. package/lib/typescript/components/voice.d.ts.map +1 -0
  127. package/lib/typescript/components/welcomeButton.d.ts +4 -0
  128. package/lib/typescript/components/welcomeButton.d.ts.map +1 -0
  129. package/lib/typescript/components/welcomeInput.d.ts +6 -0
  130. package/lib/typescript/components/welcomeInput.d.ts.map +1 -0
  131. package/lib/typescript/contexts/AppContext.d.ts +10 -0
  132. package/lib/typescript/contexts/AppContext.d.ts.map +1 -0
  133. package/lib/typescript/hooks/Stream.d.ts +2 -0
  134. package/lib/typescript/hooks/Stream.d.ts.map +1 -0
  135. package/lib/typescript/hooks/useAsyncStorage.d.ts +2 -0
  136. package/lib/typescript/hooks/useAsyncStorage.d.ts.map +1 -0
  137. package/lib/typescript/index.d.ts +8 -0
  138. package/lib/typescript/index.d.ts.map +1 -0
  139. package/lib/typescript/layout/disclaimer.d.ts +5 -0
  140. package/lib/typescript/layout/disclaimer.d.ts.map +1 -0
  141. package/lib/typescript/layout/ex.d.ts +1 -0
  142. package/lib/typescript/layout/ex.d.ts.map +1 -0
  143. package/lib/typescript/layout/icon.d.ts +3 -0
  144. package/lib/typescript/layout/icon.d.ts.map +1 -0
  145. package/lib/typescript/layout/layout.d.ts +3 -0
  146. package/lib/typescript/layout/layout.d.ts.map +1 -0
  147. package/lib/typescript/layout/welcome.d.ts +6 -0
  148. package/lib/typescript/layout/welcome.d.ts.map +1 -0
  149. package/lib/typescript/layout/window.d.ts +5 -0
  150. package/lib/typescript/layout/window.d.ts.map +1 -0
  151. package/lib/typescript/utils/audioRecorder.d.ts +9 -0
  152. package/lib/typescript/utils/audioRecorder.d.ts.map +1 -0
  153. package/lib/typescript/utils/cloudinary.d.ts +17 -0
  154. package/lib/typescript/utils/cloudinary.d.ts.map +1 -0
  155. package/lib/typescript/utils/storage.d.ts +29 -0
  156. package/lib/typescript/utils/storage.d.ts.map +1 -0
  157. package/lib/typescript/utils/textToSpeech.d.ts +2 -0
  158. package/lib/typescript/utils/textToSpeech.d.ts.map +1 -0
  159. package/package.json +109 -0
  160. package/src/assets/chat-icon-mobile.svg +1 -0
  161. package/src/assets/heritage.png +0 -0
  162. package/src/assets/posiden.svg +51 -0
  163. package/src/components/LoadingTips.js +99 -0
  164. package/src/components/email.js +467 -0
  165. package/src/components/feedback.js +114 -0
  166. package/src/components/header.js +119 -0
  167. package/src/components/input.js +133 -0
  168. package/src/components/productCard.js +815 -0
  169. package/src/components/progressCircle.js +88 -0
  170. package/src/components/testing.js +60 -0
  171. package/src/components/voice.js +228 -0
  172. package/src/components/welcomeButton.js +161 -0
  173. package/src/components/welcomeInput.js +133 -0
  174. package/src/contexts/AppContext.js +678 -0
  175. package/src/hooks/Stream.js +655 -0
  176. package/src/hooks/useAsyncStorage.js +33 -0
  177. package/src/index.js +30 -0
  178. package/src/layout/disclaimer.js +231 -0
  179. package/src/layout/ex.js +252 -0
  180. package/src/layout/icon.js +105 -0
  181. package/src/layout/layout.js +160 -0
  182. package/src/layout/welcome.js +172 -0
  183. package/src/layout/window.js +476 -0
  184. package/src/utils/audioRecorder.js +445 -0
  185. package/src/utils/cloudinary.js +61 -0
  186. package/src/utils/storage.ts +89 -0
  187. package/src/utils/textToSpeech.js +49 -0
@@ -0,0 +1,678 @@
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useState,
5
+ useEffect,
6
+ useMemo,
7
+ } from 'react';
8
+ import uuid from 'react-native-uuid';
9
+ // import useAsyncStorage from '../hooks/useAsyncStorage';
10
+ import { loadChat, updateChat, defaultState } from '../utils/storage';
11
+
12
+ export const AppContext = createContext();
13
+
14
+ export const AppProvider = ({
15
+ data,
16
+ onProductCardClick,
17
+ onAddToCartClick,
18
+ uiConfig = {},
19
+ children,
20
+ }) => {
21
+ // Brand-driven configuration
22
+ const version =
23
+ data?.brand_version === 'pool' || data?.brand_version === 'landscape'
24
+ ? data.brand_version
25
+ : 'landscape';
26
+ const API_PREFIX = 'https://';
27
+
28
+ const BRAND_CONFIG = (() => {
29
+ const isStage = data?.env === 'stage';
30
+ return {
31
+ pool: {
32
+ primaryColor: '#004687',
33
+ userMessageColor: '#003764',
34
+ cloudName: 'heritageplus',
35
+ // Pool assets live under mobileapp/ in heritageplus cloud
36
+ logoId: 'mobileapp/logos/HPSG_HPlus_Logo_White',
37
+ baseHost: isStage
38
+ ? 'pool-stage-external-agent-adk-586731320826.us-east1.run.app'
39
+ : 'pool-prod-external-agent-adk-586731320826.us-east1.run.app',
40
+ // baseHost: isStage
41
+ // ? '0.0.0.0:8080'
42
+ // : 'pool-prod-external-agent-adk-586731320826.us-east1.run.app',
43
+ loggingHost:
44
+ 'srs-external-agent-logging-586731320826.us-central1.run.app',
45
+ },
46
+ landscape: {
47
+ primaryColor: '#437D3D',
48
+ userMessageColor: '#437D3D',
49
+ cloudName: 'mktg',
50
+ logoId: 'logos/HLSG_Logo_Lockup_Color',
51
+ baseHost: isStage
52
+ ? 'landscape-stage-external-agent-adk-586731320826.us-east1.run.app'
53
+ : 'landscape-prod-external-agent-adk-586731320826.us-east1.run.app',
54
+ loggingHost:
55
+ 'srs-external-agent-landscape-logging-586731320826.us-central1.run.app',
56
+ },
57
+ }[version];
58
+ })();
59
+
60
+ const BASE_URL = BRAND_CONFIG.baseHost;
61
+ const LOGGING_URL = BRAND_CONFIG.loggingHost;
62
+ const TRACK_CLICK_URL = `${API_PREFIX}${LOGGING_URL}/track-click`;
63
+ const ADD_TO_CART_URL = `${API_PREFIX}${LOGGING_URL}/add-to-cart`;
64
+
65
+ const theme = {
66
+ userMessage: BRAND_CONFIG.userMessageColor,
67
+ botMessage: BRAND_CONFIG.userMessageColor,
68
+ backgroundColor: '#f6f6f6',
69
+ textColor: '#161616',
70
+ textColorSecondary: '#FFFFFF',
71
+ inlineButtonColor: '#dbd4c8',
72
+ primaryColor: BRAND_CONFIG.primaryColor,
73
+ };
74
+
75
+ const brandLogo = BRAND_CONFIG.logoId;
76
+ const brandCloudName = BRAND_CONFIG.cloudName;
77
+
78
+ // Default Messages
79
+ const defaultMessage = [
80
+ {
81
+ type: 'ai',
82
+ text: `Hi there 👋 I'm your ${
83
+ version === 'pool' ? 'HeritagePool+' : 'Heritage+'
84
+ } AI Assistant. I'm here to help you with Product and Account information during your online visit. I'm still learning and growing - the more we interact and the more feedback you share, the better I can assist you. How can I help you today?`,
85
+ },
86
+ ];
87
+ const maintenanceMessage = [
88
+ {
89
+ type: 'ai',
90
+ text: "Hi there 👋 I'm your Heritage+ AI Agent. I'm currently undergoing maintenance to improve my services. Thank you for your patience and understanding!",
91
+ },
92
+ ];
93
+
94
+ // user data variables
95
+ const customerToken = data.customer_token;
96
+
97
+ // Base Variables
98
+ const [showModal, setShowModal] = useState('Icon');
99
+ const [input, setInput] = useState('');
100
+ const [messages, setMessages] = useState(defaultState.messages);
101
+ const [conversationStartTime, setConversationStartTime] = useState(null);
102
+ const [lastUserMessage, setLastUserMessage] = useState('');
103
+ const [lastMessageId, setLastMessageId] = useState('');
104
+ const [sessionId, setSessionId] = useState(null);
105
+ const [isListening, setIsListening] = useState(false);
106
+
107
+ // Message UI
108
+ const [typingIndicator, setTypingIndicator] = useState(false);
109
+ const [ghostMessage, setGhostMessage] = useState(false);
110
+ const [ghostCard, setGhostCard] = useState(false);
111
+ const [stopActivated, setStopActivated] = useState(false);
112
+ const [disclaimer, setDisclaimer] = useState(false);
113
+ const [startStreaming, setStartStreaming] = useState(false);
114
+
115
+ // Load persisted state on mount
116
+ useEffect(() => {
117
+ if (!customerToken) return;
118
+
119
+ const init = async () => {
120
+ try {
121
+ const cachedState = await loadChat(customerToken);
122
+
123
+ // Update all stateful values
124
+ setTypingIndicator(cachedState.typingIndicator);
125
+ setGhostMessage(cachedState.ghostMessage);
126
+ setGhostCard(cachedState.ghostCard);
127
+ setStopActivated(cachedState.stopActivated);
128
+ setDisclaimer(cachedState.disclaimer);
129
+ setStartStreaming(cachedState.startStreaming);
130
+ setMessages(cachedState.messages);
131
+ // setShowModal(cachedState.showModal);
132
+
133
+ if (uiConfig.toggleChat === false) {
134
+ setShowModal('Icon');
135
+ } else {
136
+ if (!disclaimer) {
137
+ setShowModal('Form');
138
+ } else {
139
+ if (
140
+ (uiConfig.showWelcome === true ||
141
+ cachedState.showWelcome === true) &&
142
+ messages.length < 2
143
+ ) {
144
+ // console.log("showWelcome", uiConfig.showWelcome, cachedState.showWelcome)
145
+ setShowModal('Welcome');
146
+ } else {
147
+ setShowModal('ChatWindow');
148
+ }
149
+ }
150
+ }
151
+ } catch (error) {
152
+ console.error('Error loading chat state:', error);
153
+ }
154
+ };
155
+
156
+ init();
157
+ }, [customerToken, uiConfig.toggleChat, uiConfig.showWelcome]);
158
+
159
+ // Persist state changes
160
+ useEffect(() => {
161
+ if (!customerToken) return;
162
+
163
+ const persistState = async () => {
164
+ const currentState = {
165
+ typingIndicator,
166
+ ghostMessage,
167
+ ghostCard,
168
+ stopActivated,
169
+ disclaimer,
170
+ startStreaming,
171
+ messages,
172
+ showModal,
173
+ showWelcome: uiConfig.showWelcome,
174
+ };
175
+
176
+ await updateChat(customerToken, currentState);
177
+ };
178
+
179
+ persistState();
180
+ }, [
181
+ customerToken,
182
+ typingIndicator,
183
+ ghostMessage,
184
+ ghostCard,
185
+ stopActivated,
186
+ disclaimer,
187
+ startStreaming,
188
+ messages,
189
+ showModal,
190
+ uiConfig.showWelcome,
191
+ ]);
192
+
193
+ useEffect(() => {
194
+ if (showModal == 'Off') {
195
+ setShowModal('Icon');
196
+ }
197
+ }, [uiConfig.showIcon]);
198
+
199
+ const stopGenerating = () => {
200
+ setTypingIndicator(false);
201
+ setStopActivated(true);
202
+ };
203
+
204
+ function handleSend(input) {
205
+ if (maintenance) {
206
+ setMessages([
207
+ ...messages,
208
+ { type: 'user', text: input },
209
+ {
210
+ type: 'ai',
211
+ text: 'The chat is currently unavailable, please come back later!',
212
+ },
213
+ ]);
214
+ return;
215
+ }
216
+
217
+ // Ensure input is a string and not empty
218
+ const userInput =
219
+ typeof input === 'string' ? input.trim() : String(input || '').trim();
220
+
221
+ if (userInput !== '') {
222
+ // Ensure sessionId exists before starting a conversation
223
+ if (!sessionId) {
224
+ const newSessionId = uuid.v4();
225
+ setSessionId(newSessionId);
226
+ console.log('[AppContext] Generated new sessionId:', newSessionId);
227
+ }
228
+ if (messages.length <= 1) {
229
+ const startTime = new Date().toISOString();
230
+ setConversationStartTime(startTime);
231
+ }
232
+
233
+ // Create user message object with immutable text
234
+ const userMessage = {
235
+ type: 'user',
236
+ text: userInput,
237
+ session_id: data.session_id || data.session || sessionId,
238
+ };
239
+
240
+ // Initiate streaming
241
+ setShowModal('ChatWindow');
242
+ setLastUserMessage(userInput);
243
+ setMessages([...messages, userMessage]);
244
+ setTypingIndicator(true);
245
+ setGhostMessage(true);
246
+ setStartStreaming(true);
247
+ setInput('');
248
+ }
249
+ }
250
+
251
+ // After form submission
252
+ function setNextMessage(name) {
253
+ setMessages(prevMessages => {
254
+ const updatedMessages = prevMessages.map((message, index) => {
255
+ if (index === prevMessages.length - 1 && message.form) {
256
+ return { ...message, form: false };
257
+ }
258
+ return message;
259
+ });
260
+
261
+ const nextMessage = {
262
+ type: 'ai',
263
+ text: [`Nice to meet you ${name}. How can I help you today?`],
264
+ };
265
+ return [...updatedMessages, nextMessage];
266
+ });
267
+ }
268
+
269
+ // Confirm Disclaimer
270
+ async function confirmDisclaimer() {
271
+ setDisclaimer(true);
272
+ if (!maintenance) {
273
+ setShowModal('Welcome');
274
+ setMessages(defaultMessage);
275
+ } else {
276
+ setShowModal('ChatWindow');
277
+ setMessages(maintenanceMessage);
278
+ }
279
+ try {
280
+ const response = await fetch(
281
+ API_PREFIX + LOGGING_URL + '/log-disclaimer',
282
+ {
283
+ method: 'POST',
284
+ headers: {
285
+ 'Content-Type': 'application/json',
286
+ },
287
+ body: JSON.stringify({ email: data.user_email }),
288
+ },
289
+ );
290
+ if (!response.ok) {
291
+ throw new Error(`HTTP error! status: ${response.status}`);
292
+ }
293
+ } catch (error) {
294
+ console.error('Error in Log disclaimer:', error);
295
+ }
296
+ }
297
+
298
+ function handleButtonClick(buttonText) {
299
+ handleSend(buttonText);
300
+ }
301
+
302
+ const [maintenance, setMaintenance] = useState(false);
303
+
304
+ const handleClearState = async () => {
305
+ if (!maintenance) {
306
+ setShowModal('Welcome');
307
+ }
308
+ if (messages.length > 1) {
309
+ const newState = {
310
+ ...defaultState,
311
+ messages: maintenance ? maintenanceMessage : defaultMessage,
312
+ showModal: maintenance ? 'ChatWindow' : 'Welcome',
313
+ };
314
+
315
+ // Update all state variables
316
+ setMessages(newState.messages);
317
+ setTypingIndicator(false);
318
+ setGhostMessage(false);
319
+ setShowModal(newState.showModal);
320
+
321
+ // Generate new session
322
+ const newSessionId = uuid.v4();
323
+ setSessionId(newSessionId);
324
+
325
+ // Clear persisted state
326
+ if (customerToken) {
327
+ await updateChat(customerToken, newState);
328
+ }
329
+ }
330
+ };
331
+
332
+ const [feedback, setFeedback] = useState({});
333
+
334
+ async function handleFeedback(feedbackValue, messageId) {
335
+ switchFeedbackOpen(true, messageId, true);
336
+ setFeedback(prevFeedback => {
337
+ const updatedFeedback = { ...prevFeedback };
338
+
339
+ if (!updatedFeedback[messageId]) {
340
+ updatedFeedback[messageId] = 0;
341
+ }
342
+
343
+ updatedFeedback[messageId] = feedbackValue;
344
+
345
+ return updatedFeedback;
346
+ });
347
+ try {
348
+ const response = await fetch(API_PREFIX + LOGGING_URL + '/feedback', {
349
+ method: 'POST',
350
+ headers: {
351
+ 'Content-Type': 'application/json',
352
+ },
353
+ body: JSON.stringify({
354
+ message_id: messageId,
355
+ feedback: feedbackValue,
356
+ }),
357
+ });
358
+ if (!response.ok) {
359
+ throw new Error(`HTTP error! status: ${response.status}`);
360
+ }
361
+ //console.log(response)
362
+ } catch (error) {
363
+ console.error('Error in feedback post:', error);
364
+ }
365
+ }
366
+
367
+ const [feedbackOpen, setFeedbackOpen] = useState({});
368
+ const [writeFeedback, setWriteFeedback] = useState('');
369
+ const [writeAnswer, setWriteAnswer] = useState('');
370
+
371
+ // Written Feedback ----------------------------
372
+
373
+ function switchFeedbackOpen(newVal, messageId, resetvalue) {
374
+ console.log(newVal, feedbackOpen[messageId], messageId, resetvalue);
375
+ console.log(feedbackOpen);
376
+ if (newVal != feedbackOpen[messageId]) {
377
+ setWriteFeedback('');
378
+ setWriteAnswer('');
379
+ }
380
+ if (resetvalue) {
381
+ setWriteFeedback('');
382
+ setWriteAnswer('');
383
+ }
384
+ if (feedbackOpen[messageId] == 'done') {
385
+ return;
386
+ }
387
+ setFeedbackOpen(prevFeedback => {
388
+ const updatedFeedback = { ...prevFeedback };
389
+ updatedFeedback[messageId] = newVal;
390
+ return updatedFeedback;
391
+ });
392
+ console.log(feedbackOpen);
393
+ }
394
+
395
+ async function handleWrittenFeedback(messageId) {
396
+ if (writeFeedback.trim() !== '' || writeAnswer.trim() !== '') {
397
+ //console.log(messageId, writeFeedback)
398
+ switchFeedbackOpen(-1, messageId, true);
399
+ try {
400
+ const response = await fetch(
401
+ API_PREFIX + LOGGING_URL + '/feedback-message',
402
+ {
403
+ method: 'POST',
404
+ headers: {
405
+ 'Content-Type': 'application/json',
406
+ },
407
+ body: JSON.stringify({
408
+ message_id: messageId,
409
+ feedback_message: writeFeedback,
410
+ correct_answer: writeAnswer,
411
+ }),
412
+ },
413
+ );
414
+ if (!response.ok) {
415
+ throw new Error(`HTTP error! status: ${response.status}`);
416
+ }
417
+ //console.log(response)
418
+ } catch (error) {
419
+ console.error('Error in feedback_message:', error);
420
+ }
421
+ }
422
+ }
423
+
424
+ const formatChatHistory = () => {
425
+ // Skip the first message (index 0) which is the welcome message
426
+ return messages.slice(1).map(message => {
427
+ if (Array.isArray(message.text)) {
428
+ return {
429
+ type: message.type,
430
+ content: message.text.join('\n'),
431
+ };
432
+ }
433
+ return {
434
+ type: message.type,
435
+ content: message.text,
436
+ };
437
+ });
438
+ };
439
+
440
+ function handleVoiceSend(audio, transcription) {
441
+ //setReadAloud(true)
442
+ handleSend(transcription);
443
+ }
444
+
445
+ // Wrapper function for onAddToCartClick to add middle message
446
+ const handleAddToCartWithMessage = cartData => {
447
+ // Add middle message indicating item is being added to cart
448
+ setMessages(prevMessages => [
449
+ ...prevMessages,
450
+ {
451
+ type: 'middle',
452
+ text: `${cartData.quantity} ${cartData.selectedUom} of item ${cartData.product.product_details.product_name} added to cart`,
453
+ products: [],
454
+ product_cards: 'False',
455
+ },
456
+ ]);
457
+
458
+ // Call the original onAddToCartClick function
459
+ if (onAddToCartClick) {
460
+ onAddToCartClick(cartData);
461
+ }
462
+ };
463
+
464
+ // translations from web: port to mobile in an effort to standardize experiences
465
+ const translations = {
466
+ en: {
467
+ greeting: 'Hi',
468
+ aiAssistantIntro:
469
+ "I'm your Heritage Pool+ AI Assistant. I can help you during your online visit with Product and Account information.",
470
+ askAway: 'Ask away...',
471
+ betaDisclaimer: 'Beta version. AI Assistant is still learning!',
472
+ helpCategories: 'Here are some areas I can help you with:',
473
+ suggestedQuestions: 'Suggested Questions...',
474
+ languageToggle: 'Ayuda en Español',
475
+ products: 'Products',
476
+ orders: 'Orders',
477
+ invoices: 'Invoices',
478
+ branchInfo: 'Branch Information',
479
+ hiMessage:
480
+ "Hi, I'm your Heritage Pool+ AI Assistant. How can I help you?",
481
+ hiMessageMobile:
482
+ "Hi, I'm your Heritage Pool+ AI Assistant! How can I help you?",
483
+ defaultMessage:
484
+ "Hi there 👋 I'm your Heritage Pool+ AI Assistant. I'm here to help you with Product and Account information during your online visit. I'm still learning and growing - the more we interact and the more feedback you share, the better I can assist you. How can I help you today?",
485
+ nameMessage:
486
+ "Hi there 👋 I'm your Heritage Pool+ AI Assistant. I'm here to help you with Product and Account information during your online visit. I'm still learning and growing - the more we interact and the more feedback you share, the better I can assist you. How can I help you today?",
487
+ nextMessage: 'Nice to meet you {name}. How can I help you today?',
488
+ maintenanceMessage:
489
+ "Hi there 👋 I'm your Heritage Pool+ AI Assistant. I'm currently undergoing maintenance to improve my services. Thank you for your patience and understanding!",
490
+ followUpQuestions: {
491
+ products: [
492
+ 'Do you have part # JNDDEV48 in stock?',
493
+ 'Which grid assembly goes with the Hayward DE4820 filter?',
494
+ "What's the max flow rate for the Tristar VS 950?",
495
+ "What's the difference between the Jandy VS FloPro 2.7 HP and the Jandy VS PlusHP 2.7 HP?",
496
+ ],
497
+ branchInfo: [
498
+ 'What are the hours of my current branch?',
499
+ 'How can I contact my branch?',
500
+ 'Branches near me.',
501
+ ],
502
+ orders: [
503
+ "Where can I find my PO's?",
504
+ 'How do I change my shipping method?',
505
+ 'How do I place my early buys?',
506
+ 'Can I pick up my open order?',
507
+ 'I need to edit a recently placed order.',
508
+ ],
509
+ invoices: [
510
+ 'How do I pay for invoices?',
511
+ 'How do I print past invoices?',
512
+ 'What is my current account balance?',
513
+ 'How many unpaid invoices do I have?',
514
+ 'How do I change my payment on file?',
515
+ ],
516
+ },
517
+ loadingTips: [
518
+ 'Use 👍👎 next to each response to help us improve the AI Assistant',
519
+ '🗑️ Clear the chat history after each conversation for continued accurate responses',
520
+ ],
521
+ addToCart: 'Add to Cart',
522
+ },
523
+ es: {
524
+ greeting: 'Hola',
525
+ aiAssistantIntro:
526
+ 'Soy tu Asistente de IA de Heritage Pool+. Puedo ayudarte durante tu visita en línea con información de productos y cuentas.',
527
+ askAway: 'Pregunta lo que quieras...',
528
+ betaDisclaimer: 'Versión beta. ¡Asistente de IA sigue aprendiendo!',
529
+ helpCategories: 'Estas son algunas áreas en las que puedo ayudarte:',
530
+ suggestedQuestions: 'Preguntas Sugeridas...',
531
+ languageToggle: 'Assistance in English',
532
+ products: 'Productos',
533
+ orders: 'Pedidos',
534
+ invoices: 'Facturas',
535
+ branchInfo: 'Información de Sucursal',
536
+ hiMessage:
537
+ 'Hola, soy tu Asistente de IA de Heritage Pool+. ¿Cómo puedo ayudarte?',
538
+ hiMessageMobile:
539
+ '¡Hola, soy tu Asistente de IA de Heritage Pool+! ¿Cómo puedo ayudarte?',
540
+ defaultMessage:
541
+ 'Hola 👋 Soy tu Asistente de IA de Heritage Pool+. Estoy aquí para ayudarte con información de productos y cuentas durante tu visita en línea. Sigo aprendiendo y creciendo - mientras más interactuemos y más comentarios compartas, mejor podré asistirte. ¿Cómo puedo ayudarte hoy?',
542
+ nameMessage:
543
+ 'Hola 👋 Soy tu Asistente de IA de Heritage Pool+. Estoy aquí para ayudarte con información de productos y cuentas durante tu visita en línea. Sigo aprendiendo y creciendo - mientras más interactuemos y más comentarios compartas, mejor podré asistirte. ¿Cómo puedo ayudarte hoy?',
544
+ nextMessage: 'Mucho gusto en conocerte {name}. ¿Cómo puedo ayudarte hoy?',
545
+ maintenanceMessage:
546
+ 'Hola 👋 Soy tu Asistente de IA de Heritage Pool+. Actualmente estoy en mantenimiento para mejorar mis servicios. ¡Gracias por tu paciencia y comprensión!',
547
+ followUpQuestions: {
548
+ products: [
549
+ '¿Tienen la pieza # JNDDEV48 en existencia?',
550
+ '¿Qué ensamble de rejilla corresponde al filtro Hayward DE4820?',
551
+ '¿Cuál es el caudal máximo del Tristar VS 950?',
552
+ '¿Cuál es la diferencia entre el Jandy VS FloPro de 2.7 HP y el Jandy VS PlusHP de 2.7 HP?',
553
+ ],
554
+ branchInfo: [
555
+ '¿Cuáles son los horarios de mi sucursal actual?',
556
+ '¿Cómo puedo contactar a mi sucursal?',
557
+ 'Sucursales cerca de mí.',
558
+ ],
559
+ orders: [
560
+ '¿Dónde puedo encontrar mis órdenes de compra?',
561
+ '¿Cómo cambio mi método de envío?',
562
+ '¿Cómo realizo mis compras anticipadas?',
563
+ '¿Puedo recoger mi pedido abierto?',
564
+ 'Necesito editar un pedido recién realizado.',
565
+ ],
566
+ invoices: [
567
+ '¿Cómo pago las facturas?',
568
+ '¿Cómo imprimo facturas anteriores?',
569
+ '¿Cuál es el saldo actual de mi cuenta?',
570
+ '¿Cuántas facturas sin pagar tengo?',
571
+ '¿Cómo cambio mi método de pago registrado?',
572
+ ],
573
+ },
574
+ loadingTips: [
575
+ 'Usa 👍👎 junto a cada respuesta para ayudarnos a mejorar el Asistente de IA',
576
+ '🗑️ Borra el historial de chat después de cada conversación para mantener respuestas precisas',
577
+ ],
578
+ addToCart: 'Agregar al Carrito',
579
+ },
580
+ };
581
+
582
+ const [isSpanish, setIsSpanish] = useState('isSpanish', false);
583
+ const getCurrentTranslations = () => translations[isSpanish ? 'es' : 'en'];
584
+
585
+ const toggleLanguage = () => {
586
+ const newLanguage = !isSpanish;
587
+ setIsSpanish(newLanguage);
588
+
589
+ // Update messages when language changes
590
+ const currentTranslations = translations[newLanguage ? 'es' : 'en'];
591
+
592
+ if (maintenance) {
593
+ setMessages([
594
+ {
595
+ type: 'ai',
596
+ text: [currentTranslations.maintenanceMessage],
597
+ },
598
+ ]);
599
+ } else {
600
+ setMessages([
601
+ {
602
+ type: 'ai',
603
+ text: [currentTranslations.defaultMessage],
604
+ },
605
+ ]);
606
+ }
607
+ };
608
+
609
+ return (
610
+ <AppContext.Provider
611
+ value={{
612
+ isSpanish,
613
+ getCurrentTranslations,
614
+ toggleLanguage,
615
+ showModal,
616
+ setShowModal,
617
+ messages,
618
+ setMessages,
619
+ handleSend,
620
+ input,
621
+ setInput,
622
+ defaultMessage,
623
+ typingIndicator,
624
+ setTypingIndicator,
625
+ handleClearState,
626
+ theme,
627
+ handleButtonClick,
628
+ conversationStartTime,
629
+ setConversationStartTime,
630
+ lastUserMessage,
631
+ setLastUserMessage,
632
+ ghostMessage,
633
+ setGhostMessage,
634
+ ghostCard,
635
+ setGhostCard,
636
+ stopActivated,
637
+ setStopActivated,
638
+ disclaimer,
639
+ setDisclaimer,
640
+ startStreaming,
641
+ setStartStreaming,
642
+ maintenance,
643
+ setMaintenance,
644
+ feedback,
645
+ setFeedback,
646
+ handleFeedback,
647
+ feedbackOpen,
648
+ setFeedbackOpen,
649
+ writeFeedback,
650
+ setWriteFeedback,
651
+ writeAnswer,
652
+ setWriteAnswer,
653
+ BASE_URL,
654
+ lastMessageId,
655
+ setLastMessageId,
656
+ onProductCardClick,
657
+ onAddToCartClick: handleAddToCartWithMessage,
658
+ data,
659
+ sessionId,
660
+ setSessionId,
661
+ handleWrittenFeedback,
662
+ switchFeedbackOpen,
663
+ confirmDisclaimer,
664
+ formatChatHistory,
665
+ uiConfig,
666
+ handleVoiceSend,
667
+ TRACK_CLICK_URL,
668
+ ADD_TO_CART_URL,
669
+ isListening,
670
+ setIsListening,
671
+ brandLogo,
672
+ brandCloudName,
673
+ version,
674
+ }}>
675
+ {children}
676
+ </AppContext.Provider>
677
+ );
678
+ };