@envive-ai/react-hooks 0.3.1 → 0.3.2

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 (259) hide show
  1. package/dist/application/commerce-api.cjs +4 -4
  2. package/dist/application/commerce-api.js +4 -4
  3. package/dist/application/models/api/response.d.cts +1 -1
  4. package/dist/application/models/api/response.d.ts +1 -1
  5. package/dist/application/models/frontendConfig.d.cts +1 -1
  6. package/dist/application/models/frontendConfig.d.ts +1 -1
  7. package/dist/application/models/guards/api/isApiFormResponse.cjs +1 -1
  8. package/dist/application/models/guards/api/isApiFormResponse.js +1 -1
  9. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +1 -1
  10. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +1 -1
  11. package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +2 -2
  12. package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +2 -2
  13. package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +1 -1
  14. package/dist/application/models/guards/api/isApiProductResponseAttributes.js +1 -1
  15. package/dist/application/models/guards/api/isApiResponse.cjs +1 -1
  16. package/dist/application/models/guards/api/isApiResponse.js +1 -1
  17. package/dist/application/models/guards/api/isApiSearchEventAttributes.cjs +2 -2
  18. package/dist/application/models/guards/api/isApiSearchEventAttributes.js +2 -2
  19. package/dist/application/models/message.cjs +1 -1
  20. package/dist/application/models/message.d.cts +1 -1
  21. package/dist/application/models/message.d.ts +1 -1
  22. package/dist/application/models/message.js +1 -1
  23. package/dist/application/models/validators/validateGraphQLColorsConfig.cjs +2 -1
  24. package/dist/application/models/validators/validateGraphQLColorsConfig.js +2 -1
  25. package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +1 -1
  26. package/dist/application/models/validators/validateGraphQLFrontendConfig.d.cts +1 -1
  27. package/dist/application/models/validators/validateGraphQLFrontendConfig.d.ts +1 -1
  28. package/dist/application/models/validators/validateGraphQLFrontendConfig.js +1 -1
  29. package/dist/application/utils/analyticsUtils.cjs +2 -2
  30. package/dist/application/utils/analyticsUtils.js +2 -2
  31. package/dist/application/utils/domObserver.cjs +1 -1
  32. package/dist/application/utils/domObserver.js +1 -1
  33. package/dist/application/utils/elementObserver.cjs +1 -1
  34. package/dist/application/utils/elementObserver.js +1 -1
  35. package/dist/application/utils/mutationHelper.cjs +2 -2
  36. package/dist/application/utils/mutationHelper.js +2 -2
  37. package/dist/application/utils/nodeSelector.cjs +5 -2
  38. package/dist/application/utils/nodeSelector.js +5 -2
  39. package/dist/application/utils/stringUtils.cjs +1 -1
  40. package/dist/application/utils/stringUtils.js +1 -1
  41. package/dist/atoms/app/index.cjs +1 -1
  42. package/dist/atoms/app/index.d.cts +1 -1
  43. package/dist/atoms/app/index.d.ts +1 -1
  44. package/dist/atoms/app/index.js +1 -1
  45. package/dist/atoms/app/variant.cjs +1 -1
  46. package/dist/atoms/app/variant.d.cts +3 -3
  47. package/dist/atoms/app/variant.d.ts +3 -3
  48. package/dist/atoms/app/variant.js +1 -1
  49. package/dist/atoms/chat/chatState.d.cts +15 -15
  50. package/dist/atoms/chat/chatState.d.ts +15 -15
  51. package/dist/atoms/chat/form.d.cts +2 -2
  52. package/dist/atoms/chat/form.d.ts +2 -2
  53. package/dist/atoms/chat/index.cjs +1 -1
  54. package/dist/atoms/chat/index.d.ts +3 -3
  55. package/dist/atoms/chat/index.js +1 -1
  56. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  57. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  58. package/dist/atoms/chat/messageQueue.cjs +1 -1
  59. package/dist/atoms/chat/messageQueue.js +1 -1
  60. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  61. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  62. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  63. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  64. package/dist/atoms/chat/replies.cjs +2 -2
  65. package/dist/atoms/chat/replies.d.cts +2 -2
  66. package/dist/atoms/chat/replies.d.ts +2 -2
  67. package/dist/atoms/chat/replies.js +2 -2
  68. package/dist/atoms/chat/suggestions.d.cts +2 -2
  69. package/dist/atoms/chat/suggestions.d.ts +2 -2
  70. package/dist/atoms/globalSearch/globalSearch.cjs +3 -1
  71. package/dist/atoms/globalSearch/globalSearch.d.cts +10 -7
  72. package/dist/atoms/globalSearch/globalSearch.d.ts +10 -7
  73. package/dist/atoms/globalSearch/globalSearch.js +3 -2
  74. package/dist/atoms/globalSearch/index.cjs +1 -0
  75. package/dist/atoms/globalSearch/index.d.cts +2 -2
  76. package/dist/atoms/globalSearch/index.d.ts +2 -2
  77. package/dist/atoms/globalSearch/index.js +2 -2
  78. package/dist/atoms/org/customerService.d.cts +7 -7
  79. package/dist/atoms/org/customerService.d.ts +6 -6
  80. package/dist/atoms/org/graphqlConfig.cjs +1 -1
  81. package/dist/atoms/org/graphqlConfig.d.cts +5 -5
  82. package/dist/atoms/org/graphqlConfig.d.ts +5 -5
  83. package/dist/atoms/org/graphqlConfig.js +1 -1
  84. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  85. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  86. package/dist/atoms/org/orgAnalyticsConfig.cjs +1 -1
  87. package/dist/atoms/org/orgAnalyticsConfig.d.cts +6 -6
  88. package/dist/atoms/org/orgAnalyticsConfig.d.ts +6 -6
  89. package/dist/atoms/org/orgAnalyticsConfig.js +1 -1
  90. package/dist/atoms/search/chatSearch.d.cts +17 -17
  91. package/dist/atoms/search/chatSearch.d.ts +17 -17
  92. package/dist/atoms/search/searchAPI.cjs +1 -1
  93. package/dist/atoms/search/searchAPI.d.cts +14 -14
  94. package/dist/atoms/search/searchAPI.d.ts +14 -14
  95. package/dist/atoms/search/searchAPI.js +1 -1
  96. package/dist/atoms/search/searchServiceAdapter.cjs +1 -1
  97. package/dist/atoms/search/searchServiceAdapter.js +1 -1
  98. package/dist/atoms/search/types.d.cts +1 -1
  99. package/dist/atoms/search/types.d.ts +1 -1
  100. package/dist/atoms/search/utils.d.cts +1 -1
  101. package/dist/atoms/search/utils.d.ts +1 -1
  102. package/dist/contexts/amplitudeContext/amplitudeContext.cjs +6 -6
  103. package/dist/contexts/amplitudeContext/amplitudeContext.js +6 -6
  104. package/dist/contexts/cdnContext/cdnContext.cjs +1 -1
  105. package/dist/contexts/cdnContext/cdnContext.js +1 -1
  106. package/dist/contexts/chatContext/chatContext.cjs +4 -4
  107. package/dist/contexts/chatContext/chatContext.js +4 -4
  108. package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +2 -3
  109. package/dist/contexts/enviveConfigContext/enviveConfigContext.js +2 -3
  110. package/dist/contexts/enviveContext/enviveContext.cjs +52 -0
  111. package/dist/contexts/enviveContext/enviveContext.d.cts +31 -0
  112. package/dist/contexts/enviveContext/enviveContext.d.ts +31 -0
  113. package/dist/contexts/enviveContext/enviveContext.js +51 -0
  114. package/dist/contexts/enviveContext/index.cjs +5 -0
  115. package/dist/contexts/enviveContext/index.d.cts +3 -0
  116. package/dist/contexts/enviveContext/index.d.ts +3 -0
  117. package/dist/contexts/enviveContext/index.js +4 -0
  118. package/dist/contexts/enviveContext/types.cjs +11 -0
  119. package/dist/contexts/enviveContext/types.d.cts +8 -0
  120. package/dist/contexts/enviveContext/types.d.ts +8 -0
  121. package/dist/contexts/enviveContext/types.js +10 -0
  122. package/dist/contexts/featureFlagContext/featureFlagContext.cjs +2 -2
  123. package/dist/contexts/featureFlagContext/featureFlagContext.js +2 -2
  124. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +2 -2
  125. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +2 -2
  126. package/dist/contexts/graphqlContext/graphqlContext.cjs +3 -3
  127. package/dist/contexts/graphqlContext/graphqlContext.js +3 -3
  128. package/dist/contexts/localStorageContext/localStorageContext.cjs +1 -1
  129. package/dist/contexts/localStorageContext/localStorageContext.js +1 -1
  130. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +1 -1
  131. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.js +1 -1
  132. package/dist/contexts/searchContext/searchContext.cjs +1 -1
  133. package/dist/contexts/searchContext/searchContext.js +1 -1
  134. package/dist/contexts/sessionStorageContext/sessionStorageContext.cjs +1 -1
  135. package/dist/contexts/sessionStorageContext/sessionStorageContext.js +1 -1
  136. package/dist/contexts/types.cjs +1 -1
  137. package/dist/contexts/types.d.cts +1 -1
  138. package/dist/contexts/types.d.ts +1 -1
  139. package/dist/contexts/types.js +1 -1
  140. package/dist/contexts/userIdentityContext/userIdentityContext.cjs +1 -1
  141. package/dist/contexts/userIdentityContext/userIdentityContext.js +1 -1
  142. package/dist/events/index.cjs +2 -4
  143. package/dist/events/index.js +2 -4
  144. package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.cjs +1 -1
  145. package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.js +1 -1
  146. package/dist/hooks/Debounce/useDebounce.cjs +1 -1
  147. package/dist/hooks/Debounce/useDebounce.js +1 -1
  148. package/dist/hooks/ElementObserver/useElementObserver.cjs +2 -2
  149. package/dist/hooks/ElementObserver/useElementObserver.js +2 -2
  150. package/dist/hooks/IdentifyUser/useIdentifyUser.cjs +1 -1
  151. package/dist/hooks/IdentifyUser/useIdentifyUser.js +1 -1
  152. package/dist/hooks/ImageResolver/useImageResolver.cjs +2 -2
  153. package/dist/hooks/ImageResolver/useImageResolver.js +2 -2
  154. package/dist/hooks/IsSmallScreen/useIsSmallScreen.cjs +1 -1
  155. package/dist/hooks/IsSmallScreen/useIsSmallScreen.js +1 -1
  156. package/dist/hooks/LocalStorageOperations/useLocalStorageOperations.cjs +11 -3
  157. package/dist/hooks/LocalStorageOperations/useLocalStorageOperations.js +11 -3
  158. package/dist/hooks/Search/useRecommendedProducts.cjs +1 -1
  159. package/dist/hooks/Search/useRecommendedProducts.js +1 -1
  160. package/dist/hooks/Search/useSearch.cjs +6 -3
  161. package/dist/hooks/Search/useSearch.d.cts +3 -1
  162. package/dist/hooks/Search/useSearch.d.ts +3 -1
  163. package/dist/hooks/Search/useSearch.js +7 -4
  164. package/dist/hooks/Search/useSearchInput.cjs +1 -1
  165. package/dist/hooks/Search/useSearchInput.js +1 -1
  166. package/dist/hooks/SearchOperations/useSearchOperations.cjs +1 -1
  167. package/dist/hooks/SearchOperations/useSearchOperations.d.cts +1 -1
  168. package/dist/hooks/SearchOperations/useSearchOperations.d.ts +1 -1
  169. package/dist/hooks/SearchOperations/useSearchOperations.js +1 -1
  170. package/dist/hooks/SessionStorageOperations/useSessionStorageOperations.cjs +1 -1
  171. package/dist/hooks/SessionStorageOperations/useSessionStorageOperations.js +1 -1
  172. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.cjs +1 -1
  173. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.js +1 -1
  174. package/dist/hooks/utils.cjs +3 -3
  175. package/dist/hooks/utils.d.ts +1 -1
  176. package/dist/hooks/utils.js +3 -3
  177. package/package.json +25 -6
  178. package/src/application/commerce-api.ts +12 -10
  179. package/src/application/models/api/nextMessageRequest.ts +2 -0
  180. package/src/application/models/api/response.ts +4 -4
  181. package/src/application/models/api/search.ts +1 -2
  182. package/src/application/models/api/userEvent.ts +1 -2
  183. package/src/application/models/frontendConfig.ts +2 -2
  184. package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +8 -4
  185. package/src/application/models/guards/api/isApiSearchEventAttributes.ts +1 -1
  186. package/src/application/models/index.ts +1 -0
  187. package/src/application/models/message.ts +5 -5
  188. package/src/application/models/utilityTypes/delimiterCase.ts +1 -0
  189. package/src/application/models/validators/validateGraphQLColorsConfig.ts +2 -1
  190. package/src/application/models/validators/validateGraphQLFrontendConfig.ts +1 -1
  191. package/src/application/models/variantInfo/variantInfo.ts +3 -0
  192. package/src/application/utils/analyticsUtils.ts +3 -3
  193. package/src/application/utils/domObserver.ts +1 -0
  194. package/src/application/utils/elementObserver.ts +1 -0
  195. package/src/application/utils/mutationHelper.ts +3 -1
  196. package/src/application/utils/nodeSelector.ts +7 -1
  197. package/src/application/utils/stringUtils.ts +1 -0
  198. package/src/atoms/app/index.ts +17 -6
  199. package/src/atoms/app/variant.ts +11 -13
  200. package/src/atoms/chat/__tests__/messageQueue.test.spec.ts +61 -0
  201. package/src/atoms/chat/index.ts +8 -8
  202. package/src/atoms/chat/messageQueue.ts +2 -48
  203. package/src/atoms/chat/replies.ts +3 -3
  204. package/src/atoms/org/graphqlConfig.ts +0 -1
  205. package/src/atoms/org/orgAnalyticsConfig.ts +1 -1
  206. package/src/atoms/search/searchAPI.ts +1 -1
  207. package/src/atoms/search/searchServiceAdapter.ts +1 -1
  208. package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +4 -3
  209. package/src/contexts/amplitudeContext/amplitudeContext.tsx +5 -5
  210. package/src/contexts/cdnContext/cdnContext.tsx +1 -1
  211. package/src/contexts/enviveConfigContext/__tests__/enviveConfigContext.test.tsx +2 -3
  212. package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +3 -3
  213. package/src/contexts/enviveContext/enviveContext.tsx +89 -0
  214. package/src/contexts/enviveContext/index.ts +2 -0
  215. package/src/contexts/enviveContext/types.ts +4 -0
  216. package/src/contexts/featureFlagContext/featureFlagContext.tsx +1 -1
  217. package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +1 -1
  218. package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +7 -5
  219. package/src/contexts/graphqlContext/graphqlContext.tsx +1 -5
  220. package/src/contexts/hardcopyContext/hardcopyContext.tsx +70 -0
  221. package/src/contexts/hardcopyContext/index.ts +1 -0
  222. package/src/contexts/localStorageContext/__tests__/localStorageContext.test.tsx +9 -3
  223. package/src/contexts/localStorageContext/localStorageContext.tsx +1 -1
  224. package/src/contexts/newOrgConfigContext/__tests__/newOrgConfigContext.test.tsx +2 -3
  225. package/src/contexts/newOrgConfigContext/newOrgConfigContext.tsx +1 -1
  226. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +666 -0
  227. package/src/contexts/pageContext/index.ts +2 -0
  228. package/src/contexts/pageContext/mapping.ts +38 -0
  229. package/src/contexts/pageContext/pageContext.tsx +78 -0
  230. package/src/contexts/pageContext/types.ts +27 -0
  231. package/src/contexts/salesAgentContext/chatAPI.ts +75 -0
  232. package/src/contexts/salesAgentContext/index.ts +3 -0
  233. package/src/contexts/salesAgentContext/salesAgentContext.tsx +128 -0
  234. package/src/contexts/salesAgentContext/salesAgentService.ts +197 -0
  235. package/src/contexts/searchContext/__tests__/searchContext.test.tsx +14 -15
  236. package/src/contexts/searchContext/searchContext.tsx +1 -1
  237. package/src/contexts/sessionStorageContext/sessionStorageContext.tsx +1 -1
  238. package/src/contexts/systemSettingsContext/__tests__/systemSettingsContext.test.tsx +7 -6
  239. package/src/contexts/types.ts +20 -22
  240. package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +3 -8
  241. package/src/contexts/userIdentityContext/userIdentityContext.tsx +1 -1
  242. package/src/events/index.ts +5 -7
  243. package/src/hooks/AmplitudeOperations/useAmplitudeOperations.ts +1 -1
  244. package/src/hooks/Debounce/useDebounce.ts +1 -1
  245. package/src/hooks/ElementObserver/useElementObserver.ts +2 -1
  246. package/src/hooks/GraphQLConfig/useGraphQLConfig.ts +4 -2
  247. package/src/hooks/IdentifyUser/useIdentifyUser.ts +1 -1
  248. package/src/hooks/ImageResolver/useImageResolver.ts +2 -0
  249. package/src/hooks/IsSmallScreen/useIsSmallScreen.ts +1 -1
  250. package/src/hooks/LocalStorageOperations/useLocalStorageOperations.ts +20 -4
  251. package/src/hooks/Search/__tests__/useSearch.test.tsx +15 -10
  252. package/src/hooks/Search/useRecommendedProducts.ts +2 -2
  253. package/src/hooks/Search/useSearchInput.ts +1 -1
  254. package/src/hooks/SearchOperations/useSearchOperations.ts +2 -2
  255. package/src/hooks/SessionStorageOperations/useSessionStorageOperations.ts +1 -1
  256. package/src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.ts +2 -2
  257. package/src/hooks/utils.ts +3 -2
  258. package/src/contexts/chatContext/chatContext.tsx +0 -463
  259. package/src/contexts/chatContext/index.ts +0 -1
@@ -1,463 +0,0 @@
1
- import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
2
- import { useAtom, useAtomValue, useSetAtom } from 'jotai';
3
- import { createContext, useEffect, useState, ReactNode, useCallback, useMemo } from 'react';
4
- import CommerceApiClient from 'src/application/commerce-api';
5
- import { v4 as uuid } from 'uuid';
6
- import { SessionRestartRequired } from 'src/types/exceptions/sessionExceptions';
7
- import Logger from 'src/application/logging/logger';
8
- import {
9
- Message,
10
- MessageRole,
11
- MessageType,
12
- NextMessageRequest,
13
- Response,
14
- } from 'src/application/models';
15
- import { SpiffyMetricsEventName } from 'src/contexts/amplitudeContext/amplitudeContext';
16
- import { messageFromResponse } from 'src/application/utils';
17
- import { chatIdAtom, userIdAtom, variantInfoAtom } from 'src/atoms/app';
18
- import {
19
- messagesAtom,
20
- requestFailureAtom,
21
- responseStreamingAtom,
22
- userHasRepliedAtom,
23
- PerfMetricsEvents,
24
- logPerfMetricAtom,
25
- userEventsAtom,
26
- suggestionsLoadingAtom,
27
- suggestionsAtom,
28
- } from 'src/atoms/chat';
29
- import {
30
- chatSearchProductSortingAtom,
31
- chatSearchProducts,
32
- chatSearchStateAtom,
33
- handleSearchResultsAtom,
34
- chatSearchIsLoadingAtom,
35
- } from 'src/atoms/search/chatSearch';
36
- import { createAppLoadedEvent, createVisitUserEvent } from 'src/hooks/utils';
37
- import { useMessageInterceptor } from 'src/interceptors/useMessageInterceptor';
38
- import { supportedEventAtom } from 'src/atoms/app/variant';
39
- import { chatAtom } from 'src/atoms/chat';
40
- import { getAtomStore } from 'src/atoms/atomStore';
41
- import {
42
- clearUserEventAtom,
43
- createResponsePayload,
44
- processUserEventAtom,
45
- userEventQueueAtom,
46
- userQueueEventCountAtom,
47
- } from 'src/atoms/chat/messageQueue';
48
- import { useAmplitudeTracking } from 'src/hooks/AmplitudeOperations/useAmplitudeOperations';
49
- import { useSystemSettingsContext } from 'src/hooks/SystemSettingsContext';
50
-
51
- /**
52
- * Record the chat assistant response in Amplitude
53
- *
54
- * @param startTimeMs The start time of the assistant response
55
- * @param payload The payload used to generate the response
56
- */
57
- const recordAssistantResponse = (
58
- startTimeMs: number,
59
- payload: NextMessageRequest,
60
- track: (eventName: SpiffyMetricsEventName, eventProps?: Record<string, unknown>) => void,
61
- ) => {
62
- const atomStore = getAtomStore();
63
- const chatState = atomStore.get(chatAtom);
64
- const chatSearchState = atomStore.get(chatSearchStateAtom);
65
- const searchProducts = atomStore.get(chatSearchProducts);
66
- const searchProductsSort = atomStore.get(chatSearchProductSortingAtom);
67
- const assistantResponseTimeMs = { start: startTimeMs, end: Date.now() };
68
- let userQueryProperty: string | undefined;
69
-
70
- if (
71
- chatState.replyEventCategory === UserEventCategory.SuggestionClicked &&
72
- chatState.suggestion
73
- ) {
74
- userQueryProperty = chatState.suggestion.content;
75
- } else if (chatState.userQuery && chatState.userQuery.length > 0) {
76
- userQueryProperty = chatState.userQuery;
77
- }
78
-
79
- const eventProps: Record<string, unknown> = {
80
- response_time_ms: assistantResponseTimeMs.end - assistantResponseTimeMs.start,
81
- user_event_type: chatState.replyEventCategory,
82
- user_query: userQueryProperty,
83
- };
84
-
85
- if (chatState.replyEventCategory === UserEventCategory.FormSubmitted) {
86
- const lastAssistantTurn = chatState.messages
87
- .filter(turn => turn.length > 0 && turn[0].role === MessageRole.Assistant)
88
- .pop();
89
- const formType = payload.userEvents?.find(
90
- event => event.category === UserEventCategory.FormSubmitted,
91
- )?.attributes.formType;
92
- const formStatus = lastAssistantTurn?.some(response => response.type === MessageType.Order);
93
- eventProps.form_submitted_attributes = {
94
- form_type: formType,
95
- status: formStatus ? 'success' : 'failed',
96
- };
97
- }
98
-
99
- if (chatSearchState === 'product-page') {
100
- eventProps.search_products_returned = searchProducts.length;
101
- eventProps.search_products_sort_type = searchProductsSort;
102
- }
103
-
104
- track(SpiffyMetricsEventName.ChatAssistantResponse, {
105
- eventProps,
106
- });
107
- };
108
-
109
- interface ChatContextParams {}
110
-
111
- const ChatContext = createContext<ChatContextParams | undefined>(undefined);
112
-
113
- const updateMessageState = (
114
- message: Message,
115
- lastMessage: Message,
116
- setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
117
- ): Message => {
118
- if (lastMessage == null) {
119
- setMessages(prev => [...prev, [message]]);
120
- return message;
121
- }
122
- if (lastMessage.type === MessageType.Text && message.type === MessageType.Text) {
123
- const newMessage = {
124
- ...lastMessage,
125
- metadata: {
126
- ...lastMessage.metadata,
127
- content: lastMessage.metadata.content + message.metadata.content,
128
- },
129
- };
130
- setMessages(prev => {
131
- const lastTurn = prev[prev.length - 1];
132
- return [
133
- ...prev.slice(0, prev.length - 1),
134
- [...lastTurn.slice(0, lastTurn.length - 1), newMessage],
135
- ];
136
- });
137
- return newMessage;
138
- }
139
- setMessages(prev => [...prev.slice(0, prev.length - 1), [...prev[prev.length - 1], message]]);
140
- return message;
141
- };
142
-
143
- const handleStreamingError = (
144
- _error: unknown,
145
- setRequestFailure: (failed: boolean) => void,
146
- setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
147
- ) => {
148
- setRequestFailure(true);
149
- setMessages(prev => [
150
- ...prev,
151
- [
152
- {
153
- id: uuid(),
154
- role: MessageRole.Assistant,
155
- type: MessageType.Text,
156
- createdAt: new Date().toISOString(),
157
- metadata: {
158
- content:
159
- "I'm sorry! I'm having trouble right now. Please refresh the page or try again in a moment.",
160
- },
161
- },
162
- ],
163
- ]);
164
- };
165
-
166
- const processStreamingResponse = async (
167
- stream: AsyncIterable<Response>,
168
- messageInterceptor: {
169
- intercept: (response?: Response) => boolean | undefined;
170
- },
171
- handleSearchResults: (message: Message) => void,
172
- setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
173
- setSearchIsLoading: (loading: boolean) => void,
174
- chatId: string,
175
- ): Promise<{ hasSearchResults: boolean }> => {
176
- let lastMessage: Message | undefined;
177
- let hasSearchResults = false;
178
-
179
- for await (const response of stream) {
180
- try {
181
- if (messageInterceptor.intercept(response)) {
182
- return { hasSearchResults };
183
- }
184
-
185
- const message = messageFromResponse(response);
186
- if (!message) {
187
- throw new Error('Failed to transform API response to client message');
188
- }
189
-
190
- if (message.type === MessageType.ProductSearch) {
191
- handleSearchResults(message);
192
- hasSearchResults = true;
193
- setSearchIsLoading(false); // Update search loading immediately when results are detected
194
- }
195
-
196
- lastMessage = updateMessageState(message, lastMessage!, setMessages);
197
- } catch (error: unknown) {
198
- Logger.logWarn(
199
- `[spiffy-ai] Failed to generate responses from stream chat_id=${chatId}`,
200
- error,
201
- {
202
- lastResponse: lastMessage,
203
- response,
204
- },
205
- );
206
- }
207
- }
208
-
209
- return { hasSearchResults };
210
- };
211
-
212
- const ChatContextProvider = ({ children }: { children: ReactNode }) => {
213
- const logPerfMetric = useSetAtom(logPerfMetricAtom);
214
- const [widgetInitialized, setWidgetInitialized] = useState(false);
215
- const setUserHasReplied = useSetAtom(userHasRepliedAtom);
216
- // TODO: create atoms for setting/getting the last message turn
217
- const [messages, setMessages] = useAtom<Message[][]>(messagesAtom);
218
- const setUserEvents = useSetAtom(userEventsAtom);
219
- const setSuggestions = useSetAtom(suggestionsAtom);
220
- const [suggestionsLoading, setSuggestionsLoading] = useAtom<boolean>(suggestionsLoadingAtom);
221
- const [responseStreaming, setResponseStreaming] = useAtom<boolean>(responseStreamingAtom);
222
- const setRequestFailure = useSetAtom(requestFailureAtom);
223
- const userEvents = useAtomValue(userEventQueueAtom);
224
- const userQueueEventCount = useAtomValue(userQueueEventCountAtom);
225
- const markUserEventsProcessed = useSetAtom(processUserEventAtom);
226
- const clearUserEventQueue = useSetAtom(clearUserEventAtom);
227
- const userId = useAtomValue(userIdAtom);
228
- const chatId = useAtomValue(chatIdAtom);
229
- const supportedEvent = useAtomValue(supportedEventAtom);
230
- // TODO: Replace with actual orgId from useEnviveConfig or NewOrgConfigContext when available
231
- const orgId = 'mock-org-id';
232
-
233
- const variantInfo = useAtomValue(variantInfoAtom);
234
- const settingsContext = useSystemSettingsContext();
235
- const messageInterceptor = useMessageInterceptor();
236
- const handleSearchResults = useSetAtom(handleSearchResultsAtom);
237
- const setSearchIsLoading = useSetAtom(chatSearchIsLoadingAtom);
238
- const { track } = useAmplitudeTracking();
239
-
240
- const getStreamingResponses = useCallback(
241
- async (payload: NextMessageRequest): Promise<{ hasSearchResults: boolean }> => {
242
- logPerfMetric(PerfMetricsEvents.FirstResponseStarted);
243
- const stream = CommerceApiClient.getNextResponseStreaming(payload);
244
-
245
- try {
246
- setRequestFailure(false);
247
-
248
- const { hasSearchResults } = await processStreamingResponse(
249
- stream,
250
- messageInterceptor,
251
- handleSearchResults,
252
- setMessages,
253
- setSearchIsLoading,
254
- chatId,
255
- );
256
-
257
- return { hasSearchResults };
258
- } catch (e) {
259
- handleStreamingError(e, setRequestFailure, setMessages);
260
- throw e;
261
- } finally {
262
- logPerfMetric(PerfMetricsEvents.FirstResponseCompleted);
263
- }
264
- },
265
- [
266
- logPerfMetric,
267
- setRequestFailure,
268
- messageInterceptor,
269
- handleSearchResults,
270
- setMessages,
271
- setSearchIsLoading,
272
- chatId,
273
- ],
274
- );
275
-
276
- const getSuggestions = useCallback(async () => {
277
- logPerfMetric(PerfMetricsEvents.FirstSuggestionsStarted);
278
- setSuggestionsLoading(true);
279
- setSuggestions([]);
280
-
281
- const payloadWithoutAppLoaded = createResponsePayload({
282
- userEvents: [],
283
- generationParams: settingsContext.generationParams,
284
- });
285
- const response = await CommerceApiClient.getNextSuggestions(payloadWithoutAppLoaded);
286
-
287
- // sort the suggestions by shortest length so the pills can be stacked horizontally
288
- setSuggestions(response.sort((a, b) => a.content.length - b.content.length));
289
- setSuggestionsLoading(false);
290
- logPerfMetric(PerfMetricsEvents.FirstSuggestionsCompleted);
291
- }, [logPerfMetric, setSuggestionsLoading, setSuggestions, settingsContext.generationParams]);
292
-
293
- const getResponses = useCallback(
294
- async (payload?: NextMessageRequest) => {
295
- try {
296
- const requestPayload =
297
- payload ??
298
- createResponsePayload({
299
- userEvents,
300
- generationParams: settingsContext.generationParams,
301
- });
302
-
303
- setResponseStreaming(true);
304
- setSuggestions([]);
305
- const startTimeMs = Date.now();
306
-
307
- await getStreamingResponses(requestPayload);
308
-
309
- recordAssistantResponse(startTimeMs, requestPayload, track);
310
- await getSuggestions();
311
- } catch (error) {
312
- Logger.logError('[spiffy-ai] getResponses error', error);
313
- } finally {
314
- // Remove search loading management from here - it's now handled independently
315
- // in the processStreamingResponse function when search results are detected
316
- markUserEventsProcessed(userEvents.map(({ eventId }) => eventId));
317
- setUserHasReplied(false);
318
- setResponseStreaming(false);
319
- }
320
- },
321
- [
322
- userEvents,
323
- settingsContext.generationParams,
324
- setResponseStreaming,
325
- setSuggestions,
326
- getStreamingResponses,
327
- markUserEventsProcessed,
328
- getSuggestions,
329
- setUserHasReplied,
330
- track,
331
- ],
332
- );
333
-
334
- useEffect(() => {
335
- const processUserEvents = async () => {
336
- if (responseStreaming || !widgetInitialized) {
337
- return;
338
- }
339
-
340
- if (
341
- (variantInfo.variant === 'pdp' && !variantInfo.productId) ||
342
- (variantInfo.variant === 'plp' && !variantInfo.plpId) ||
343
- (variantInfo.variant === 'page_visit' && !variantInfo.url)
344
- ) {
345
- Logger.logDebug('[spiffy-ai] variantInfo has invalid values, skipping...', {
346
- variantInfo,
347
- supportedEvent,
348
- });
349
- return;
350
- }
351
-
352
- Logger.logDebug(
353
- `Assistants Turn is_currently_streaming=${responseStreaming} initialized=${widgetInitialized}`,
354
- );
355
- try {
356
- await getResponses();
357
- Logger.logInfo(`Assistants Turn [finished]`);
358
- } catch (error: unknown) {
359
- Logger.logError('[spiffy-ai] Assistants Turn error', error);
360
- }
361
- };
362
- if (userQueueEventCount > 0) {
363
- processUserEvents();
364
- }
365
- }, [
366
- getResponses,
367
- responseStreaming,
368
- userQueueEventCount,
369
- widgetInitialized,
370
- variantInfo,
371
- supportedEvent,
372
- ]);
373
-
374
- useEffect(() => {
375
- if (widgetInitialized || responseStreaming) {
376
- Logger.logDebug(
377
- `[spiffy-ai] initializeWidget [skipped] is_currently_streaming=${responseStreaming} is_initialized=${widgetInitialized}`,
378
- );
379
- return;
380
- }
381
-
382
- const hydrateChat = async () => {
383
- try {
384
- Logger.logDebug(
385
- `[spiffy-ai] initializeWidget is_currently_streaming=${responseStreaming} is_initialized=${widgetInitialized}`,
386
- );
387
- // on mount, try to get the responses from an active session if one exists
388
- if (!orgId) {
389
- throw new Error('orgId is not available');
390
- }
391
- const { messages: existingMessages, userEvents } = await CommerceApiClient.getResponses(
392
- orgId,
393
- chatId,
394
- userId,
395
- );
396
- setMessages([...existingMessages]);
397
- setUserEvents([...userEvents]);
398
- getResponses();
399
- } catch (error) {
400
- // no active chat session was found, start a new one
401
- Logger.logInfo(`Init chat [exception] chat_id=${chatId} error=${error}`, error);
402
- if (error instanceof SessionRestartRequired) {
403
- const appLoadedEvent = createAppLoadedEvent();
404
- const visitEvent = createVisitUserEvent({ variantInfo });
405
- setMessages([]);
406
- clearUserEventQueue();
407
- if (visitEvent) {
408
- const payload = createResponsePayload({
409
- userEvents: [appLoadedEvent, visitEvent],
410
- generationParams: settingsContext.generationParams,
411
- });
412
- getResponses(payload);
413
- }
414
- }
415
- } finally {
416
- setWidgetInitialized(true);
417
- }
418
- };
419
-
420
- hydrateChat();
421
- }, []);
422
-
423
- const onFocus = useCallback(async () => {
424
- try {
425
- if (!responseStreaming && !suggestionsLoading && orgId) {
426
- const { messages: existingMessages } = await CommerceApiClient.getResponses(
427
- orgId,
428
- chatId,
429
- userId,
430
- );
431
-
432
- if (existingMessages.length > messages.length) {
433
- setMessages([...existingMessages]);
434
- // TODO: Is this bug hack still necessary?
435
- // If it is, come up with a better solution for it
436
- // } else if (existingMessages.length === 0) {
437
- // // if there was an error during the initialization of a new session, the session would be
438
- // // created in the backend but without any messages. Retry the next_responses request with
439
- // // the current set of parameters to "jumpstart" the session
440
- // triggerGetResponseCall('onFocus');
441
- }
442
- }
443
- } catch (error: unknown) {
444
- Logger.logError('[spiffy-ai] onFocus error', error);
445
- }
446
- }, [responseStreaming, suggestionsLoading, orgId, chatId, userId, messages.length, setMessages]);
447
-
448
- // listen for page focus to get latest messages from the server
449
- useEffect(() => {
450
- window.addEventListener('focus', onFocus);
451
-
452
- return () => {
453
- window.removeEventListener('focus', onFocus);
454
- };
455
- }, [onFocus]);
456
-
457
- const chatContext = useMemo(() => ({}), []);
458
-
459
- return <ChatContext.Provider value={chatContext}>{children}</ChatContext.Provider>;
460
- };
461
-
462
- export { ChatContext, ChatContextProvider };
463
- export type { ChatContextParams };
@@ -1 +0,0 @@
1
- export * from './chatContext';