@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,20 +1,23 @@
1
1
  import { atomWithStorage } from 'jotai/utils';
2
2
  import { atom } from 'jotai';
3
- import { SupportedEventResponse, PageVisitCategory } from '@spiffy-ai/commerce-api-client';
4
3
  import {
5
- PageVisitVariantInfo,
4
+ PageVisitCategory,
5
+ SupportedEventResponse,
6
+ UserEvent,
7
+ } from '@spiffy-ai/commerce-api-client';
8
+ import {
6
9
  PDPVariantInfo,
7
10
  PLPVariantInfo,
11
+ PageVisitVariantInfo,
8
12
  VariantInfo,
9
13
  VariantTypeEnum,
10
14
  } from 'src/application/models';
11
15
  import { sessionStorageUtil } from 'src/atoms/atomStore';
12
16
 
13
- export interface SupportedEvent
14
- extends Pick<
15
- SupportedEventResponse,
16
- 'supported' | 'ready' | 'category' | 'collections' | 'top_category'
17
- > {
17
+ export interface SupportedEvent extends Pick<
18
+ SupportedEventResponse,
19
+ 'supported' | 'ready' | 'category' | 'collections' | 'top_category'
20
+ > {
18
21
  numberOfReviews: number | undefined;
19
22
  merchant_tags?: string[];
20
23
  }
@@ -88,12 +91,7 @@ export interface UrlResolverResponse {
88
91
  variant_type: string;
89
92
  specific_details: UrlResolvingPDPConfig | UrlResolvingPLPConfig | UrlResolvingGenericConfig;
90
93
  ready: boolean;
91
- user_event?: {
92
- event_id?: string;
93
- attributes?: PDPAttributes | PLPAttributes;
94
- category?: string;
95
- created_at?: string;
96
- };
94
+ user_event?: UserEvent;
97
95
  page_variant?: BackendPageVariantConfig;
98
96
  }
99
97
 
@@ -0,0 +1,61 @@
1
+ import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
2
+ import { createStore } from 'jotai';
3
+ import { UserEvent } from 'src/application/models';
4
+ import {
5
+ clearUserEventAtom,
6
+ processUserEventAtom,
7
+ queueUserEventAtom,
8
+ userEventQueueAtom,
9
+ userQueueEventCountAtom,
10
+ } from 'src/atoms/chat/messageQueue';
11
+
12
+ const userEvent1 = {
13
+ eventId: '123',
14
+ category: UserEventCategory.AppLoaded,
15
+ createdAt: 'now',
16
+ } satisfies UserEvent;
17
+ const userEvent2 = {
18
+ eventId: '456',
19
+ category: UserEventCategory.AppLoaded,
20
+ createdAt: 'now',
21
+ } satisfies UserEvent;
22
+
23
+ describe('eventQueue', () => {
24
+ it('should be able to enqueue items and show them in the queue', () => {
25
+ const store = createStore();
26
+ store.set(queueUserEventAtom, userEvent1);
27
+ expect(store.get(userEventQueueAtom)).toEqual([userEvent1]);
28
+ expect(store.get(userQueueEventCountAtom)).toBe(1);
29
+ });
30
+ it('should be able to mark eventQueue items as processed and remove them from the queue', () => {
31
+ const store = createStore();
32
+ store.set(queueUserEventAtom, userEvent1);
33
+ store.set(queueUserEventAtom, userEvent2);
34
+ expect(store.get(userEventQueueAtom)).toEqual([userEvent1, userEvent2]);
35
+ expect(store.get(userQueueEventCountAtom)).toBe(2);
36
+ store.set(processUserEventAtom, ['123']);
37
+ expect(store.get(userEventQueueAtom)).toEqual([userEvent2]);
38
+ expect(store.get(userQueueEventCountAtom)).toBe(1);
39
+ });
40
+ it('should be able to mark non-existent eventQueue items as procesed without an exception being raised', () => {
41
+ const store = createStore();
42
+ store.set(queueUserEventAtom, userEvent1);
43
+ store.set(queueUserEventAtom, userEvent2);
44
+ expect(store.get(userEventQueueAtom)).toEqual([userEvent1, userEvent2]);
45
+ expect(store.get(userQueueEventCountAtom)).toBe(2);
46
+ store.set(processUserEventAtom, ['foo']);
47
+ expect(store.get(userEventQueueAtom)).toEqual([userEvent1, userEvent2]);
48
+ expect(store.get(userQueueEventCountAtom)).toBe(2);
49
+ });
50
+ it('should be able to clear all eventQueue items', () => {
51
+ const store = createStore();
52
+ expect(store.get(userQueueEventCountAtom)).toBe(0);
53
+ store.set(queueUserEventAtom, userEvent1);
54
+ store.set(queueUserEventAtom, userEvent2);
55
+ expect(store.get(userEventQueueAtom)).toEqual([userEvent1, userEvent2]);
56
+ expect(store.get(userQueueEventCountAtom)).toBe(2);
57
+ store.set(clearUserEventAtom);
58
+ expect(store.get(userEventQueueAtom)).toEqual([]);
59
+ expect(store.get(userQueueEventCountAtom)).toBe(0);
60
+ });
61
+ });
@@ -1,17 +1,17 @@
1
1
  import { atom } from 'jotai';
2
2
  import {
3
- responseStreamingAtom,
4
- suggestionsLoadingAtom,
5
- messagesAtom,
6
- userQueryAtom,
7
- replyEventCategoryAtom,
8
- userHasRepliedAtom,
9
3
  askQuestionBtnClickedAtom,
10
- suggestionsAtom,
11
4
  chatIsOpenAtom,
12
5
  chatOnToggleAtom,
13
- userEventsAtom,
6
+ messagesAtom,
7
+ replyEventCategoryAtom,
8
+ responseStreamingAtom,
14
9
  suggestionAtom,
10
+ suggestionsAtom,
11
+ suggestionsLoadingAtom,
12
+ userEventsAtom,
13
+ userHasRepliedAtom,
14
+ userQueryAtom,
15
15
  } from './chatState';
16
16
 
17
17
  export * from './chatState';
@@ -1,10 +1,5 @@
1
1
  import { atom } from 'jotai';
2
- import { v4 as uuid } from 'uuid';
3
- import { GenerationParams, NextMessageRequest, UserEvent } from 'src/application/models';
4
- import { getAtomStore } from 'src/atoms/atomStore/atomStore';
5
- import { userIdAtom, chatIdAtom } from 'src/atoms/app';
6
- import { orgShortNameAtom, contextSourceAtom, envAtom } from 'src/atoms/envive/enviveConfig';
7
- import { orgIdAtom, featureFlagServiceAtom } from 'src/atoms/org/graphqlConfig';
2
+ import { UserEvent } from 'src/application/models';
8
3
 
9
4
  const internalUserEventQueueAtom = atom<UserEvent[]>([]);
10
5
 
@@ -43,46 +38,5 @@ export const processUserEventAtom = atom(null, (get, set, eventIds: string[]) =>
43
38
  set(internalUserEventQueueAtom, remaining);
44
39
  });
45
40
 
46
- export const userQueueEventCountAtom = atom(get => get(userEventQueueAtom).length);
47
-
48
- import { ContextSourceEnum, ContextEnvEnum } from '@spiffy-ai/commerce-api-client'; // Import necessary enums
41
+ export const userQueueEventCountAtom = atom(get => get(userEventQueueAtom).length); // Import necessary enums
49
42
  // import type { Context } from "@spiffy-ai/commerce-api-client/dist/models/Context"; // Import Context type
50
-
51
- export const createResponsePayload = ({
52
- userEvents,
53
- generationParams,
54
- }: {
55
- userEvents: UserEvent[];
56
- generationParams?: GenerationParams;
57
- }): NextMessageRequest => {
58
- const atomStore = getAtomStore();
59
- const orgShortName = atomStore.get(orgShortNameAtom);
60
- const orgId = atomStore.get(orgIdAtom);
61
- const userId = atomStore.get(userIdAtom);
62
- const chatId = atomStore.get(chatIdAtom);
63
- const source = atomStore.get(contextSourceAtom);
64
- const env = atomStore.get(envAtom);
65
-
66
- const featureFlagService = atomStore.get(featureFlagServiceAtom);
67
-
68
- const context = {
69
- userId: userId ?? '',
70
- org_id: orgId ?? '',
71
- org_short_name: orgShortName ?? '',
72
- chat_id: chatId ?? '',
73
- source: source ?? ContextSourceEnum.App,
74
- env: (env as ContextEnvEnum) ?? ContextEnvEnum.Dev,
75
- };
76
-
77
- const featureFlags = featureFlagService?.featureFlagService?.getFeatureFlags() || {};
78
-
79
- return {
80
- id: uuid(),
81
- context,
82
- userEvents,
83
- featureFlags: Object.fromEntries(
84
- Object.entries(featureFlags).filter(([, isEnabled]) => isEnabled),
85
- ), // Convert back to Record<string, boolean>
86
- generationParams,
87
- };
88
- };
@@ -1,15 +1,15 @@
1
1
  import { atom } from 'jotai';
2
2
  import { Message, MessageType } from 'src/application/models';
3
3
  import {
4
- userHasRepliedAtom,
5
4
  messagesAtom,
6
- userQueryAtom,
7
5
  replyEventCategoryAtom,
6
+ userHasRepliedAtom,
7
+ userQueryAtom,
8
8
  } from 'src/atoms/chat';
9
9
  import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
10
- import { queueUserEventAtom } from './messageQueue';
11
10
  import { SpiffyMetricsEventName } from 'src/contexts/amplitudeContext/amplitudeContext';
12
11
  import { amplitudeTrackEventAtom } from 'src/atoms/amplitude/amplitudeTrackEventAtom';
12
+ import { queueUserEventAtom } from './messageQueue';
13
13
 
14
14
  type HandleReplyParams = {
15
15
  message: Message;
@@ -1,7 +1,6 @@
1
1
  import { atom } from 'jotai';
2
2
  import { ColorMapping } from 'src/application/models/colorsConfig';
3
3
  import { FrontendConfig } from 'src/application/models/frontendConfig';
4
- import { orgShortNameAtom } from '../envive/enviveConfig';
5
4
  import { FeatureFlagContextType } from 'src/contexts/featureFlagServiceContext/featureFlagServiceContext'; // Import FeatureFlagContextType from new context
6
5
 
7
6
  export const internalGraphQLColorsConfigAtom = atom<ColorMapping | undefined>(undefined);
@@ -1,7 +1,7 @@
1
1
  import { atom } from 'jotai';
2
2
  import {
3
- OrgAnalyticsConfig,
4
3
  OrgAnalyticsAmplitudeConfig,
4
+ OrgAnalyticsConfig,
5
5
  OrgAnalyticsCustomerServiceConfig,
6
6
  OrgAnalyticsGoogleAnalyticsConfig,
7
7
  } from 'src/application/models/api/orgAnalyticsConfig';
@@ -1,5 +1,5 @@
1
1
  import { atom } from 'jotai';
2
- import { SearchResult, SearchParams } from 'src/application/models/api/search';
2
+ import { SearchParams, SearchResult } from 'src/application/models/api/search';
3
3
  import { ProductSorting } from './types';
4
4
  import { ProductFilters } from './productFilters';
5
5
  import { ProductSorter } from './productSorter';
@@ -1,4 +1,4 @@
1
- import { SearchResult, SearchParams } from 'src/application/models/api/search';
1
+ import { SearchParams, SearchResult } from 'src/application/models/api/search';
2
2
 
3
3
  // This will be set by the SearchProvider when it initializes
4
4
  let searchServiceFunction: ((params: SearchParams) => Promise<SearchResult>) | null = null;
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
- import { render, screen, waitFor, act } from '@testing-library/react';
2
+ import { act, render, screen, waitFor } from '@testing-library/react';
3
3
  import { Provider, useStore } from 'jotai';
4
- import { AmplitudeProvider, useAmplitude, SpiffyMetricsEventName } from '../amplitudeContext';
5
4
  import {
6
5
  UserIdentityProvider,
7
6
  useUserIdentity,
@@ -11,7 +10,7 @@ import { EnviveConfigProvider } from 'src/contexts/enviveConfigContext/enviveCon
11
10
  import { FeatureFlagServiceProvider } from 'src/contexts/featureFlagServiceContext/featureFlagServiceContext';
12
11
  import { userIdAtom } from 'src/atoms/app';
13
12
  import Logger from 'src/application/logging/logger';
14
- import { createInstance } from '@amplitude/analytics-browser';
13
+ import { AmplitudeProvider, SpiffyMetricsEventName, useAmplitude } from '../amplitudeContext';
15
14
 
16
15
  // Mock the Logger to avoid console output in tests
17
16
  // vi.spyOn(Logger, "logInfo").mockImplementation(() => {});
@@ -62,6 +61,7 @@ const MockAmplitudeComponent: React.FC = () => {
62
61
  <div data-testid="is-ready">{amplitude.isReady.toString()}</div>
63
62
  <button
64
63
  data-testid="track-event-button"
64
+ type="button"
65
65
  onClick={() =>
66
66
  amplitude.trackEvent({
67
67
  eventName: SpiffyMetricsEventName.ChatUserMessageInput,
@@ -373,6 +373,7 @@ describe('AmplitudeProvider with UserIdentityContext', () => {
373
373
  return (
374
374
  <button
375
375
  data-testid="track-multiple"
376
+ type="button"
376
377
  onClick={trackMultiple}
377
378
  >
378
379
  Track Multiple
@@ -1,4 +1,4 @@
1
- import React, { createContext, useContext, useCallback, useMemo, useEffect } from 'react';
1
+ import React, { createContext, useCallback, useContext, useEffect, useMemo } from 'react';
2
2
  import { useAtomValue } from 'jotai';
3
3
  import { createInstance } from '@amplitude/analytics-browser';
4
4
  import { FeatureGates } from 'src/application/models/featureGates';
@@ -8,12 +8,12 @@ import {
8
8
  amplitudeApiKeyAtom,
9
9
  contextSourceAtom,
10
10
  dataResidencyAtom,
11
+ envAtom,
11
12
  identifyingPrefixAtom,
12
13
  } from 'src/atoms/envive/enviveConfig';
13
14
  import { LocalStorageKeys, useLocalStorage } from 'src/contexts/localStorageContext';
14
15
  import { orgAnalyticsGoogleAnalyticsConfigAtom } from 'src/atoms/org/orgAnalyticsConfig';
15
16
  import { userIdAtom } from 'src/atoms/app';
16
- import { envAtom } from 'src/atoms/envive/enviveConfig';
17
17
  import Logger from 'src/application/logging/logger';
18
18
  import type {
19
19
  BrowserClient,
@@ -162,8 +162,8 @@ export const AmplitudeProvider: React.FC<{ children: React.ReactNode }> = ({ chi
162
162
  const amplitudeSessionReplayInit = useCallback((): boolean => {
163
163
  const isEnabled = Boolean(
164
164
  orgShortName === OrgShortName.UniqueVintage &&
165
- featureFlagService?.isClientSessionEnabled() &&
166
- featureFlagService?.isFeatureGateEnabled(FeatureGates.IsNewFeatureEnabled),
165
+ featureFlagService?.isClientSessionEnabled() &&
166
+ featureFlagService?.isFeatureGateEnabled(FeatureGates.IsNewFeatureEnabled),
167
167
  );
168
168
  const sampleRate = 1;
169
169
 
@@ -358,7 +358,7 @@ export const AmplitudeProvider: React.FC<{ children: React.ReactNode }> = ({ chi
358
358
  if (window.dataLayer) {
359
359
  (window.dataLayer as any[]).push({
360
360
  event: decoratedEventName,
361
- eventProps: eventProps,
361
+ eventProps,
362
362
  });
363
363
  }
364
364
  }
@@ -1,4 +1,4 @@
1
- import React, { createContext, useContext, useCallback, useMemo } from 'react';
1
+ import React, { createContext, useCallback, useContext, useMemo } from 'react';
2
2
  import { useAtomValue } from 'jotai';
3
3
  import { cdnUrlAtom } from '../../atoms/envive/enviveConfig';
4
4
 
@@ -1,10 +1,9 @@
1
1
  import React from 'react';
2
2
  import { render, screen, waitFor } from '@testing-library/react';
3
- import { Provider } from 'jotai';
4
- import { useAtomValue } from 'jotai';
5
- import { EnviveConfigProvider, useEnviveConfig } from '../enviveConfigContext';
3
+ import { Provider, useAtomValue } from 'jotai';
6
4
  import { enviveConfigAtom } from 'src/atoms/envive/enviveConfig';
7
5
  import Logger from 'src/application/logging/logger';
6
+ import { EnviveConfigProvider, useEnviveConfig } from '../enviveConfigContext';
8
7
 
9
8
  // Mock the Logger to avoid console output in tests
10
9
  vi.spyOn(Logger, 'logDebug').mockImplementation(() => {});
@@ -1,5 +1,5 @@
1
- import React, { createContext, useContext, ReactNode, useEffect } from 'react';
2
- import { useSetAtom, useAtomValue } from 'jotai';
1
+ import React, { ReactNode, createContext, useEffect } from 'react';
2
+ import { useAtomValue, useSetAtom } from 'jotai';
3
3
  import { enviveConfigAtom } from 'src/atoms/envive/enviveConfig';
4
4
  import Logger from 'src/application/logging/logger';
5
5
  import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
@@ -82,5 +82,5 @@ export const EnviveConfigProvider: React.FC<EnviveConfigProviderProps> = ({
82
82
  export const useEnviveConfig = (): EnviveConfig => {
83
83
  const config = useAtomValue(enviveConfigAtom);
84
84
 
85
- return config ? config : {};
85
+ return config || {};
86
86
  };
@@ -0,0 +1,89 @@
1
+ import { ReactNode, createContext } from 'react';
2
+
3
+ import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
4
+ import { AmplitudeProvider } from '../amplitudeContext';
5
+ import { EnviveConfigProvider } from '../enviveConfigContext';
6
+ import { EnviveCssProvider } from '../enviveCssContext';
7
+ import { FeatureFlagServiceProvider } from '../featureFlagServiceContext';
8
+ import { GraphQLProvider } from '../graphqlContext';
9
+ import { LocalStorageProvider } from '../localStorageContext';
10
+ import { NewOrgConfigProvider } from '../newOrgConfigContext';
11
+ import { UserIdentityProvider } from '../userIdentityContext';
12
+ import { EnviveAgent } from './types';
13
+ import { SearchProvider } from '../searchContext';
14
+ import { SalesAgentProvider } from '../salesAgentContext/salesAgentContext';
15
+ import { SystemSettingsContextProvider } from '../systemSettingsContext';
16
+
17
+ const EnviveContext = createContext<null>(null);
18
+
19
+ interface AgentWrapperProps {
20
+ children: ReactNode;
21
+ enabledAgents: EnviveAgent[];
22
+ }
23
+
24
+ interface EnviveProviderProps extends AgentWrapperProps {
25
+ amplitudeApiKey?: string;
26
+ dataResidency?: string;
27
+ env?: string;
28
+ baseUrl?: string;
29
+ reactAppName?: string;
30
+ cdnUrl?: string;
31
+ contextSource?: string;
32
+ orgLevelApiKey?: string;
33
+ orgShortName?: string;
34
+ identifyingPrefix: string;
35
+ featureOverrides?: Record<string, boolean>;
36
+ variantUrlOverride?: string;
37
+ variantInfoOverride?: any;
38
+ show?: boolean;
39
+ publicKey?: string;
40
+ featureGates?: OrgConfigFeatureGate[]; // New prop for feature gates
41
+ }
42
+
43
+ const SearchAgentWrapper: React.FC<AgentWrapperProps> = ({ children, enabledAgents }) => {
44
+ if (!enabledAgents.includes(EnviveAgent.SearchAgent)) {
45
+ return children;
46
+ }
47
+ return <SearchProvider>{children}</SearchProvider>;
48
+ };
49
+
50
+ const SalesAgentWrapper: React.FC<AgentWrapperProps> = ({ children, enabledAgents }) => {
51
+ if (!enabledAgents.includes(EnviveAgent.SalesAgent)) {
52
+ return children;
53
+ }
54
+ return (
55
+ <SystemSettingsContextProvider>
56
+ <SalesAgentProvider>{children}</SalesAgentProvider>
57
+ </SystemSettingsContextProvider>
58
+ );
59
+ };
60
+
61
+ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
62
+ children,
63
+ enabledAgents,
64
+ ...config
65
+ }) => (
66
+ <EnviveContext.Provider value={null}>
67
+ <EnviveConfigProvider {...config}>
68
+ <GraphQLProvider>
69
+ <NewOrgConfigProvider>
70
+ <LocalStorageProvider>
71
+ <FeatureFlagServiceProvider featureGates={[]}>
72
+ <UserIdentityProvider>
73
+ <AmplitudeProvider>
74
+ <EnviveCssProvider>
75
+ <SearchAgentWrapper enabledAgents={enabledAgents}>
76
+ <SalesAgentWrapper enabledAgents={enabledAgents}>
77
+ {children}
78
+ </SalesAgentWrapper>
79
+ </SearchAgentWrapper>
80
+ </EnviveCssProvider>
81
+ </AmplitudeProvider>
82
+ </UserIdentityProvider>
83
+ </FeatureFlagServiceProvider>
84
+ </LocalStorageProvider>
85
+ </NewOrgConfigProvider>
86
+ </GraphQLProvider>
87
+ </EnviveConfigProvider>
88
+ </EnviveContext.Provider>
89
+ );
@@ -0,0 +1,2 @@
1
+ export * from './enviveContext';
2
+ export * from './types';
@@ -0,0 +1,4 @@
1
+ export enum EnviveAgent {
2
+ SalesAgent = 'sales',
3
+ SearchAgent = 'search',
4
+ }
@@ -1,4 +1,4 @@
1
- import React, { createContext, useContext, useCallback, useMemo } from 'react';
1
+ import React, { createContext, useCallback, useContext, useMemo } from 'react';
2
2
  import Logger from 'src/application/logging/logger';
3
3
  import { StatsigFeatureGate } from '@spiffy-ai/commerce-api-client';
4
4
  import { FeatureGates } from 'src/application/models/featureGates';
@@ -1,4 +1,4 @@
1
- import React, { createContext, useContext, useMemo, ReactNode } from 'react';
1
+ import React, { ReactNode, createContext, useContext, useMemo } from 'react';
2
2
  import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
3
3
  import { FeatureGates } from 'src/application/models/featureGates';
4
4
  import Logger from 'src/application/logging/logger';
@@ -1,12 +1,11 @@
1
1
  import React from 'react';
2
- import { render, screen, waitFor, act } from '@testing-library/react';
3
- import { Provider } from 'jotai';
4
- import { useAtomValue } from 'jotai';
5
- import { GraphQLProvider, useGraphQLClient } from '../graphqlContext';
2
+ import { act, render, screen, waitFor } from '@testing-library/react';
3
+ import { Provider, useAtomValue } from 'jotai';
6
4
  import { EnviveConfigProvider } from 'src/contexts/enviveConfigContext/enviveConfigContext';
7
- import { orgLevelApiKeyAtom, baseUrlAtom } from 'src/atoms/envive/enviveConfig';
5
+ import { baseUrlAtom, orgLevelApiKeyAtom } from 'src/atoms/envive/enviveConfig';
8
6
  import Logger from 'src/application/logging/logger';
9
7
  import { getMerchantOrgIdQuery } from 'src/application/models/graphql/queries/getMerchantOrgIdQuery';
8
+ import { GraphQLProvider, useGraphQLClient } from '../graphqlContext';
10
9
 
11
10
  // Mock the Logger to avoid console output in tests
12
11
  vi.spyOn(Logger, 'logDebug').mockImplementation(() => {});
@@ -25,6 +24,7 @@ const MockGraphQLComponent: React.FC = () => {
25
24
  <div data-testid="is-ready">{client.isReady.toString()}</div>
26
25
  <button
27
26
  data-testid="execute-query-btn"
27
+ type="button"
28
28
  onClick={async () => {
29
29
  try {
30
30
  const result = await client.executeQuery('query { test }');
@@ -38,6 +38,7 @@ const MockGraphQLComponent: React.FC = () => {
38
38
  </button>
39
39
  <button
40
40
  data-testid="get-org-id-btn"
41
+ type="button"
41
42
  onClick={async () => {
42
43
  try {
43
44
  const orgId = await client.getOrgId();
@@ -51,6 +52,7 @@ const MockGraphQLComponent: React.FC = () => {
51
52
  </button>
52
53
  <button
53
54
  data-testid="get-config-btn"
55
+ type="button"
54
56
  onClick={async () => {
55
57
  try {
56
58
  const config = await client.getColorsAndFrontendConfig();
@@ -1,16 +1,12 @@
1
- import React, { createContext, useContext, useCallback, useMemo, ReactNode } from 'react';
1
+ import React, { ReactNode, createContext, useCallback, useContext, useMemo } from 'react';
2
2
  import { useAtomValue } from 'jotai';
3
3
  import { baseUrlAtom, orgLevelApiKeyAtom } from 'src/atoms/envive/enviveConfig';
4
4
  import { getMerchantOrgIdQuery } from 'src/application/models/graphql/queries/getMerchantOrgIdQuery';
5
5
  import { validateGraphQLOrgId } from 'src/application/models/validators/validateGraphQLOrgId';
6
6
  import {
7
- getMerchantColorsQuery,
8
7
  GetMerchantColorsQueryData,
9
- getMerchantFrontendConfigQuery,
10
8
  GetMerchantFrontendConfigQueryData,
11
9
  } from 'src/application/models/graphql';
12
- import { validateGraphQLColorsConfig } from 'src/application/models/validators/validateGraphQLColorsConfig';
13
- import { validateGraphQLFrontendConfig } from 'src/application/models/validators/validateGraphQLFrontendConfig';
14
10
  import { ColorMapping } from 'src/application/models/colorsConfig';
15
11
  import { FrontendConfig } from 'src/application/models/frontendConfig';
16
12
  import Logger from 'src/application/logging/logger';
@@ -0,0 +1,70 @@
1
+ import { UserEvent } from '@spiffy-ai/commerce-api-client';
2
+ import { ReactNode, createContext, useCallback, useContext, useMemo } from 'react';
3
+ import Logger from 'src/application/logging/logger';
4
+ import { WidgetTypeV3 } from '../types';
5
+
6
+ interface HardcopyRequest {
7
+ widgetType: WidgetTypeV3;
8
+ userEvent: UserEvent;
9
+ }
10
+
11
+ export type HardcopyResponse = {
12
+ language: string;
13
+ values: Record<string, string | string[]>;
14
+ };
15
+
16
+ interface HardcopyContextType {
17
+ getHardcopy: (HardcopyRequest: HardcopyRequest) => Promise<HardcopyResponse>;
18
+ }
19
+
20
+ // These are just sample responses for the sake of testing.
21
+ // As we start to build the actual widgets we should determine what the actual
22
+ // values and their names should be.
23
+ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> = {
24
+ [WidgetTypeV3.SuggestionBarV3]: {
25
+ language: 'en',
26
+ values: {
27
+ suggestionBarButtons: ['Button 1', 'Button 2', 'Button 3'],
28
+ },
29
+ },
30
+ [WidgetTypeV3.ChatPreviewV3]: {
31
+ language: 'en',
32
+ values: {
33
+ chatPreviewTitle: 'Chat Preview Title',
34
+ typewriterTextPrefix: 'Want to know',
35
+ typewriterTexts: ['more about this product?', 'what others are saying?', 'how to use it?'],
36
+ suggestionButtons: ['Button 1', 'Button 2', 'Button 3'],
37
+ footerText: 'Ask me anything...',
38
+
39
+ chatPreviewDescription: 'Chat Preview Description',
40
+ },
41
+ },
42
+ };
43
+
44
+ const HardcopyContext = createContext<HardcopyContextType | undefined>(undefined);
45
+
46
+ export const HardcopyProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
47
+ const languages = useMemo(() => navigator.languages, []);
48
+
49
+ const getHardcopy = useCallback(async (request: HardcopyRequest): Promise<HardcopyResponse> => {
50
+ Logger.logInfo('hardcopyContext | retrieving hardcopy', languages);
51
+ const response = MOCK_HARDCOPY_RESPONSE[request.widgetType];
52
+ Logger.logInfo('hardcopyContext | returning hardcopy response', response);
53
+ if (!response) {
54
+ throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
55
+ }
56
+ return response;
57
+ }, []);
58
+
59
+ const value = useMemo(() => ({ getHardcopy }), [getHardcopy]);
60
+
61
+ return <HardcopyContext.Provider value={value}>{children}</HardcopyContext.Provider>;
62
+ };
63
+
64
+ export const useHardcopy = () => {
65
+ const context = useContext(HardcopyContext);
66
+ if (!context) {
67
+ throw new Error('useHardcopy must be used within a HardcopyProvider');
68
+ }
69
+ return context;
70
+ };
@@ -0,0 +1 @@
1
+ export * from './hardcopyContext';
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import { render, screen, waitFor, act } from '@testing-library/react';
3
- import { LocalStorageProvider, useLocalStorage, LocalStorageKeys } from '../localStorageContext';
2
+ import { act, render, screen, waitFor } from '@testing-library/react';
4
3
  import Logger from 'src/application/logging/logger';
5
4
  import { LocalStorageEventListener } from 'src/application/models/localStorageEventListener';
5
+ import { LocalStorageKeys, LocalStorageProvider, useLocalStorage } from '../localStorageContext';
6
6
 
7
7
  // Mock the Logger to avoid console output in tests
8
8
  vi.spyOn(Logger, 'logDebug').mockImplementation(() => {});
@@ -56,6 +56,7 @@ const MockLocalStorageComponent: React.FC = () => {
56
56
  <div data-testid="event-received">{eventReceived.toString()}</div>
57
57
  <button
58
58
  data-testid="set-item-btn"
59
+ type="button"
59
60
  onClick={() => {
60
61
  setItem('test-key', 'test-value');
61
62
  setTestValue(getItem('test-key'));
@@ -65,6 +66,7 @@ const MockLocalStorageComponent: React.FC = () => {
65
66
  </button>
66
67
  <button
67
68
  data-testid="set-spiffy-on-true-btn"
69
+ type="button"
68
70
  onClick={() => {
69
71
  setSpiffyOnFeatureFlag(true);
70
72
  setSpiffyOnValue(getSpiffyOnFeatureFlag());
@@ -74,6 +76,7 @@ const MockLocalStorageComponent: React.FC = () => {
74
76
  </button>
75
77
  <button
76
78
  data-testid="set-spiffy-on-false-btn"
79
+ type="button"
77
80
  onClick={() => {
78
81
  setSpiffyOnFeatureFlag(false);
79
82
  setSpiffyOnValue(getSpiffyOnFeatureFlag());
@@ -83,6 +86,7 @@ const MockLocalStorageComponent: React.FC = () => {
83
86
  </button>
84
87
  <button
85
88
  data-testid="trigger-event-btn"
89
+ type="button"
86
90
  onClick={() => {
87
91
  setItem('test-listener-key', 'event-value');
88
92
  }}
@@ -479,7 +483,9 @@ describe('LocalStorageProvider', () => {
479
483
  });
480
484
 
481
485
  // Wait a bit to ensure listener is attached
482
- await new Promise(resolve => setTimeout(resolve, 50));
486
+ await new Promise(resolve => {
487
+ setTimeout(resolve, 50);
488
+ });
483
489
 
484
490
  await act(async () => {
485
491
  screen.getByTestId('trigger-event-btn').click();