@envive-ai/react-hooks 0.3.0 → 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.
- package/dist/application/commerce-api.cjs +4 -4
- package/dist/application/commerce-api.js +4 -4
- package/dist/application/models/api/response.d.cts +1 -1
- package/dist/application/models/api/response.d.ts +1 -1
- package/dist/application/models/frontendConfig.d.cts +1 -1
- package/dist/application/models/frontendConfig.d.ts +1 -1
- package/dist/application/models/guards/api/isApiFormResponse.cjs +1 -1
- package/dist/application/models/guards/api/isApiFormResponse.js +1 -1
- package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +1 -1
- package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +1 -1
- package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +2 -2
- package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +2 -2
- package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +1 -1
- package/dist/application/models/guards/api/isApiProductResponseAttributes.js +1 -1
- package/dist/application/models/guards/api/isApiResponse.cjs +1 -1
- package/dist/application/models/guards/api/isApiResponse.js +1 -1
- package/dist/application/models/guards/api/isApiSearchEventAttributes.cjs +2 -2
- package/dist/application/models/guards/api/isApiSearchEventAttributes.js +2 -2
- package/dist/application/models/message.cjs +1 -1
- package/dist/application/models/message.d.cts +1 -1
- package/dist/application/models/message.d.ts +1 -1
- package/dist/application/models/message.js +1 -1
- package/dist/application/models/validators/validateGraphQLColorsConfig.cjs +2 -1
- package/dist/application/models/validators/validateGraphQLColorsConfig.js +2 -1
- package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +1 -1
- package/dist/application/models/validators/validateGraphQLFrontendConfig.d.cts +1 -1
- package/dist/application/models/validators/validateGraphQLFrontendConfig.d.ts +1 -1
- package/dist/application/models/validators/validateGraphQLFrontendConfig.js +1 -1
- package/dist/application/utils/analyticsUtils.cjs +2 -2
- package/dist/application/utils/analyticsUtils.js +2 -2
- package/dist/application/utils/domObserver.cjs +1 -1
- package/dist/application/utils/domObserver.js +1 -1
- package/dist/application/utils/elementObserver.cjs +1 -1
- package/dist/application/utils/elementObserver.d.cts +2 -2
- package/dist/application/utils/elementObserver.js +1 -1
- package/dist/application/utils/mutationHelper.cjs +2 -2
- package/dist/application/utils/mutationHelper.js +2 -2
- package/dist/application/utils/nodeSelector.cjs +5 -2
- package/dist/application/utils/nodeSelector.js +5 -2
- package/dist/application/utils/stringUtils.cjs +1 -1
- package/dist/application/utils/stringUtils.js +1 -1
- package/dist/atoms/app/index.cjs +1 -1
- package/dist/atoms/app/index.d.cts +1 -1
- package/dist/atoms/app/index.js +1 -1
- package/dist/atoms/app/variant.cjs +1 -1
- package/dist/atoms/app/variant.d.cts +3 -3
- package/dist/atoms/app/variant.d.ts +3 -3
- package/dist/atoms/app/variant.js +1 -1
- package/dist/atoms/chat/chatState.d.cts +15 -15
- package/dist/atoms/chat/chatState.d.ts +15 -15
- package/dist/atoms/chat/form.d.cts +2 -2
- package/dist/atoms/chat/form.d.ts +2 -2
- package/dist/atoms/chat/index.cjs +1 -1
- package/dist/atoms/chat/index.d.cts +3 -3
- package/dist/atoms/chat/index.d.ts +2 -2
- package/dist/atoms/chat/index.js +1 -1
- package/dist/atoms/chat/lastMessage.d.cts +2 -2
- package/dist/atoms/chat/lastMessage.d.ts +2 -2
- package/dist/atoms/chat/messageQueue.cjs +1 -1
- package/dist/atoms/chat/messageQueue.js +1 -1
- package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
- package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
- package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
- package/dist/atoms/chat/replies.cjs +2 -2
- package/dist/atoms/chat/replies.d.cts +2 -2
- package/dist/atoms/chat/replies.d.ts +2 -2
- package/dist/atoms/chat/replies.js +2 -2
- package/dist/atoms/chat/suggestions.d.cts +2 -2
- package/dist/atoms/chat/suggestions.d.ts +2 -2
- package/dist/atoms/globalSearch/globalSearch.cjs +3 -1
- package/dist/atoms/globalSearch/globalSearch.d.cts +10 -7
- package/dist/atoms/globalSearch/globalSearch.d.ts +10 -7
- package/dist/atoms/globalSearch/globalSearch.js +3 -2
- package/dist/atoms/globalSearch/index.cjs +1 -0
- package/dist/atoms/globalSearch/index.d.cts +2 -2
- package/dist/atoms/globalSearch/index.d.ts +2 -2
- package/dist/atoms/globalSearch/index.js +2 -2
- package/dist/atoms/org/customerService.d.cts +7 -7
- package/dist/atoms/org/graphqlConfig.cjs +1 -1
- package/dist/atoms/org/graphqlConfig.d.cts +6 -6
- package/dist/atoms/org/graphqlConfig.d.ts +5 -5
- package/dist/atoms/org/graphqlConfig.js +1 -1
- package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
- package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
- package/dist/atoms/org/orgAnalyticsConfig.cjs +1 -1
- package/dist/atoms/org/orgAnalyticsConfig.d.cts +6 -6
- package/dist/atoms/org/orgAnalyticsConfig.d.ts +6 -6
- package/dist/atoms/org/orgAnalyticsConfig.js +1 -1
- package/dist/atoms/search/chatSearch.d.cts +17 -17
- package/dist/atoms/search/chatSearch.d.ts +17 -17
- package/dist/atoms/search/searchAPI.cjs +1 -1
- package/dist/atoms/search/searchAPI.d.cts +14 -14
- package/dist/atoms/search/searchAPI.d.ts +14 -14
- package/dist/atoms/search/searchAPI.js +1 -1
- package/dist/atoms/search/searchServiceAdapter.cjs +1 -1
- package/dist/atoms/search/searchServiceAdapter.js +1 -1
- package/dist/atoms/search/types.d.cts +1 -1
- package/dist/contexts/amplitudeContext/amplitudeContext.cjs +6 -6
- package/dist/contexts/amplitudeContext/amplitudeContext.js +6 -6
- package/dist/contexts/cdnContext/cdnContext.cjs +1 -1
- package/dist/contexts/cdnContext/cdnContext.js +1 -1
- package/dist/contexts/chatContext/chatContext.cjs +4 -4
- package/dist/contexts/chatContext/chatContext.d.cts +2 -2
- package/dist/contexts/chatContext/chatContext.js +4 -4
- package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +2 -3
- package/dist/contexts/enviveConfigContext/enviveConfigContext.js +2 -3
- package/dist/contexts/enviveContext/enviveContext.cjs +52 -0
- package/dist/contexts/enviveContext/enviveContext.d.cts +31 -0
- package/dist/contexts/enviveContext/enviveContext.d.ts +31 -0
- package/dist/contexts/enviveContext/enviveContext.js +51 -0
- package/dist/contexts/enviveContext/index.cjs +5 -0
- package/dist/contexts/enviveContext/index.d.cts +3 -0
- package/dist/contexts/enviveContext/index.d.ts +3 -0
- package/dist/contexts/enviveContext/index.js +4 -0
- package/dist/contexts/enviveContext/types.cjs +11 -0
- package/dist/contexts/enviveContext/types.d.cts +8 -0
- package/dist/contexts/enviveContext/types.d.ts +8 -0
- package/dist/contexts/enviveContext/types.js +10 -0
- package/dist/contexts/featureFlagContext/featureFlagContext.cjs +2 -2
- package/dist/contexts/featureFlagContext/featureFlagContext.js +2 -2
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +2 -2
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +2 -2
- package/dist/contexts/graphqlContext/graphqlContext.cjs +3 -3
- package/dist/contexts/graphqlContext/graphqlContext.js +3 -3
- package/dist/contexts/localStorageContext/localStorageContext.cjs +1 -1
- package/dist/contexts/localStorageContext/localStorageContext.js +1 -1
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +1 -1
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.js +1 -1
- package/dist/contexts/searchContext/searchContext.cjs +1 -1
- package/dist/contexts/searchContext/searchContext.js +1 -1
- package/dist/contexts/sessionStorageContext/sessionStorageContext.cjs +1 -1
- package/dist/contexts/sessionStorageContext/sessionStorageContext.js +1 -1
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
- package/dist/contexts/types.cjs +1 -1
- package/dist/contexts/types.d.cts +1 -1
- package/dist/contexts/types.d.ts +1 -1
- package/dist/contexts/types.js +1 -1
- package/dist/contexts/userIdentityContext/userIdentityContext.cjs +1 -1
- package/dist/contexts/userIdentityContext/userIdentityContext.js +1 -1
- package/dist/events/index.cjs +2 -4
- package/dist/events/index.js +2 -4
- package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.cjs +1 -1
- package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.js +1 -1
- package/dist/hooks/Debounce/useDebounce.cjs +1 -1
- package/dist/hooks/Debounce/useDebounce.js +1 -1
- package/dist/hooks/ElementObserver/useElementObserver.cjs +2 -2
- package/dist/hooks/ElementObserver/useElementObserver.js +2 -2
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
- package/dist/hooks/IdentifyUser/useIdentifyUser.cjs +1 -1
- package/dist/hooks/IdentifyUser/useIdentifyUser.js +1 -1
- package/dist/hooks/ImageResolver/useImageResolver.cjs +2 -2
- package/dist/hooks/ImageResolver/useImageResolver.js +2 -2
- package/dist/hooks/IsSmallScreen/useIsSmallScreen.cjs +1 -1
- package/dist/hooks/IsSmallScreen/useIsSmallScreen.js +1 -1
- package/dist/hooks/LocalStorageOperations/useLocalStorageOperations.cjs +11 -3
- package/dist/hooks/LocalStorageOperations/useLocalStorageOperations.js +11 -3
- package/dist/hooks/Search/useRecommendedProducts.cjs +1 -1
- package/dist/hooks/Search/useRecommendedProducts.js +1 -1
- package/dist/hooks/Search/useSearch.cjs +6 -3
- package/dist/hooks/Search/useSearch.d.cts +3 -1
- package/dist/hooks/Search/useSearch.d.ts +3 -1
- package/dist/hooks/Search/useSearch.js +7 -4
- package/dist/hooks/Search/useSearchInput.cjs +1 -1
- package/dist/hooks/Search/useSearchInput.js +1 -1
- package/dist/hooks/SearchOperations/useSearchOperations.cjs +1 -1
- package/dist/hooks/SearchOperations/useSearchOperations.d.cts +1 -1
- package/dist/hooks/SearchOperations/useSearchOperations.d.ts +1 -1
- package/dist/hooks/SearchOperations/useSearchOperations.js +1 -1
- package/dist/hooks/SessionStorageOperations/useSessionStorageOperations.cjs +1 -1
- package/dist/hooks/SessionStorageOperations/useSessionStorageOperations.js +1 -1
- package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.cts +2 -2
- package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.ts +2 -2
- package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.cjs +1 -1
- package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.js +1 -1
- package/dist/hooks/utils.cjs +3 -3
- package/dist/hooks/utils.d.cts +1 -1
- package/dist/hooks/utils.d.ts +1 -1
- package/dist/hooks/utils.js +3 -3
- package/package.json +25 -6
- package/src/application/commerce-api.ts +12 -10
- package/src/application/models/api/nextMessageRequest.ts +2 -0
- package/src/application/models/api/response.ts +4 -4
- package/src/application/models/api/search.ts +1 -2
- package/src/application/models/api/userEvent.ts +1 -2
- package/src/application/models/frontendConfig.ts +2 -2
- package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +8 -4
- package/src/application/models/guards/api/isApiSearchEventAttributes.ts +1 -1
- package/src/application/models/index.ts +1 -0
- package/src/application/models/message.ts +5 -5
- package/src/application/models/utilityTypes/delimiterCase.ts +1 -0
- package/src/application/models/validators/validateGraphQLColorsConfig.ts +2 -1
- package/src/application/models/validators/validateGraphQLFrontendConfig.ts +1 -1
- package/src/application/models/variantInfo/variantInfo.ts +3 -0
- package/src/application/utils/analyticsUtils.ts +3 -3
- package/src/application/utils/domObserver.ts +1 -0
- package/src/application/utils/elementObserver.ts +1 -0
- package/src/application/utils/mutationHelper.ts +3 -1
- package/src/application/utils/nodeSelector.ts +7 -1
- package/src/application/utils/stringUtils.ts +1 -0
- package/src/atoms/app/index.ts +17 -6
- package/src/atoms/app/variant.ts +11 -13
- package/src/atoms/chat/__tests__/messageQueue.test.spec.ts +61 -0
- package/src/atoms/chat/index.ts +8 -8
- package/src/atoms/chat/messageQueue.ts +2 -48
- package/src/atoms/chat/replies.ts +3 -3
- package/src/atoms/org/graphqlConfig.ts +0 -1
- package/src/atoms/org/orgAnalyticsConfig.ts +1 -1
- package/src/atoms/search/searchAPI.ts +1 -1
- package/src/atoms/search/searchServiceAdapter.ts +1 -1
- package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +4 -3
- package/src/contexts/amplitudeContext/amplitudeContext.tsx +5 -5
- package/src/contexts/cdnContext/cdnContext.tsx +1 -1
- package/src/contexts/enviveConfigContext/__tests__/enviveConfigContext.test.tsx +2 -3
- package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +3 -3
- package/src/contexts/enviveContext/enviveContext.tsx +89 -0
- package/src/contexts/enviveContext/index.ts +2 -0
- package/src/contexts/enviveContext/types.ts +4 -0
- package/src/contexts/featureFlagContext/featureFlagContext.tsx +1 -1
- package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +1 -1
- package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +7 -5
- package/src/contexts/graphqlContext/graphqlContext.tsx +1 -5
- package/src/contexts/hardcopyContext/hardcopyContext.tsx +70 -0
- package/src/contexts/hardcopyContext/index.ts +1 -0
- package/src/contexts/localStorageContext/__tests__/localStorageContext.test.tsx +9 -3
- package/src/contexts/localStorageContext/localStorageContext.tsx +1 -1
- package/src/contexts/newOrgConfigContext/__tests__/newOrgConfigContext.test.tsx +2 -3
- package/src/contexts/newOrgConfigContext/newOrgConfigContext.tsx +1 -1
- package/src/contexts/pageContext/__tests__/pageContext.test.tsx +666 -0
- package/src/contexts/pageContext/index.ts +2 -0
- package/src/contexts/pageContext/mapping.ts +38 -0
- package/src/contexts/pageContext/pageContext.tsx +78 -0
- package/src/contexts/pageContext/types.ts +27 -0
- package/src/contexts/salesAgentContext/chatAPI.ts +75 -0
- package/src/contexts/salesAgentContext/index.ts +3 -0
- package/src/contexts/salesAgentContext/salesAgentContext.tsx +128 -0
- package/src/contexts/salesAgentContext/salesAgentService.ts +197 -0
- package/src/contexts/searchContext/__tests__/searchContext.test.tsx +14 -15
- package/src/contexts/searchContext/searchContext.tsx +1 -1
- package/src/contexts/sessionStorageContext/sessionStorageContext.tsx +1 -1
- package/src/contexts/systemSettingsContext/__tests__/systemSettingsContext.test.tsx +7 -6
- package/src/contexts/types.ts +20 -22
- package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +3 -8
- package/src/contexts/userIdentityContext/userIdentityContext.tsx +1 -1
- package/src/events/index.ts +5 -7
- package/src/hooks/AmplitudeOperations/useAmplitudeOperations.ts +1 -1
- package/src/hooks/Debounce/useDebounce.ts +1 -1
- package/src/hooks/ElementObserver/useElementObserver.ts +2 -1
- package/src/hooks/GraphQLConfig/useGraphQLConfig.ts +4 -2
- package/src/hooks/IdentifyUser/useIdentifyUser.ts +1 -1
- package/src/hooks/ImageResolver/useImageResolver.ts +2 -0
- package/src/hooks/IsSmallScreen/useIsSmallScreen.ts +1 -1
- package/src/hooks/LocalStorageOperations/useLocalStorageOperations.ts +20 -4
- package/src/hooks/Search/__tests__/useSearch.test.tsx +15 -10
- package/src/hooks/Search/useRecommendedProducts.ts +2 -2
- package/src/hooks/Search/useSearchInput.ts +1 -1
- package/src/hooks/SearchOperations/useSearchOperations.ts +2 -2
- package/src/hooks/SessionStorageOperations/useSessionStorageOperations.ts +1 -1
- package/src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.ts +2 -2
- package/src/hooks/utils.ts +3 -2
- package/src/contexts/chatContext/chatContext.tsx +0 -463
- package/src/contexts/chatContext/index.ts +0 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ReactNode,
|
|
3
|
+
createContext,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
useEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import { UserEvent } from '@spiffy-ai/commerce-api-client';
|
|
11
|
+
import { UrlResolverResponse, urlResolverAtom } from 'src/atoms/app/variant';
|
|
12
|
+
import { useAtom } from 'jotai';
|
|
13
|
+
|
|
14
|
+
import CommerceApiClient from 'src/application/commerce-api';
|
|
15
|
+
import Logger from 'src/application/logging/logger';
|
|
16
|
+
import { mapUrlResolverResponseToVariantInfo } from './mapping';
|
|
17
|
+
import { PageDetails, PageVariantInfo } from './types';
|
|
18
|
+
|
|
19
|
+
const PageContext = createContext<PageDetails | undefined>(undefined);
|
|
20
|
+
|
|
21
|
+
export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
|
22
|
+
const [pageUrl, setPageUrl] = useState<string | undefined>(undefined);
|
|
23
|
+
const [variantInfo, setVariantInfo] = useState<PageVariantInfo | undefined>(undefined);
|
|
24
|
+
const [urlResolverResponse, setUrlResolverResponse] = useAtom(urlResolverAtom);
|
|
25
|
+
const [userEvent, setUserEvent] = useState<UserEvent | undefined>(undefined);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
// TODO: Add support for SPA's and other changes to the URL to ensure that the pageUrl is set correctly
|
|
29
|
+
setPageUrl(window.location.href);
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
const setVariantFromUrlResolver = useCallback(
|
|
33
|
+
(url: string, response: UrlResolverResponse) => {
|
|
34
|
+
const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
|
|
35
|
+
const newUserEvent = response.user_event ?? undefined;
|
|
36
|
+
setVariantInfo(newVariantInfo);
|
|
37
|
+
setUserEvent(newUserEvent);
|
|
38
|
+
},
|
|
39
|
+
[setVariantInfo],
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const resolvePageUrl = async () => {
|
|
44
|
+
try {
|
|
45
|
+
if (!pageUrl) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const cleansedUrl = pageUrl.toLowerCase().trim();
|
|
49
|
+
const response =
|
|
50
|
+
urlResolverResponse[cleansedUrl] ??
|
|
51
|
+
((await CommerceApiClient.resolveUrl(cleansedUrl)) as UrlResolverResponse);
|
|
52
|
+
setVariantFromUrlResolver(cleansedUrl, response);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
Logger.logError('Failed to resolve page URL', e, { pageUrl });
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
resolvePageUrl();
|
|
58
|
+
}, [pageUrl, urlResolverResponse, setUrlResolverResponse, setVariantFromUrlResolver]);
|
|
59
|
+
|
|
60
|
+
const value = useMemo(
|
|
61
|
+
() => ({
|
|
62
|
+
pageUrl,
|
|
63
|
+
variantInfo,
|
|
64
|
+
userEvent,
|
|
65
|
+
}),
|
|
66
|
+
[pageUrl, userEvent, variantInfo],
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
return <PageContext.Provider value={value}>{children}</PageContext.Provider>;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const usePage = () => {
|
|
73
|
+
const context = useContext(PageContext);
|
|
74
|
+
if (!context) {
|
|
75
|
+
throw new Error('usePage must be used within a PageProvider');
|
|
76
|
+
}
|
|
77
|
+
return context;
|
|
78
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { UserEvent } from '@spiffy-ai/commerce-api-client';
|
|
2
|
+
import { VariantTypeEnum } from 'src/application/models';
|
|
3
|
+
|
|
4
|
+
export type PDPPageVariantInfo = {
|
|
5
|
+
variantType: VariantTypeEnum.Pdp;
|
|
6
|
+
productId: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type PLPPageVariantInfo = {
|
|
11
|
+
variantType: VariantTypeEnum.Plp;
|
|
12
|
+
plpId: string;
|
|
13
|
+
url: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type VisitPageVariantInfo = {
|
|
17
|
+
variantType: VariantTypeEnum.PageVisit;
|
|
18
|
+
url: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type PageVariantInfo = PDPPageVariantInfo | PLPPageVariantInfo | VisitPageVariantInfo;
|
|
22
|
+
|
|
23
|
+
export interface PageDetails {
|
|
24
|
+
pageUrl: string | undefined;
|
|
25
|
+
variantInfo: PageVariantInfo | undefined;
|
|
26
|
+
userEvent: UserEvent | undefined;
|
|
27
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// This component will interact with the backend API to get the responses from the sales agent.
|
|
2
|
+
|
|
3
|
+
import { PageVisitCategory, UserEventCategory } from '@spiffy-ai/commerce-api-client';
|
|
4
|
+
import { Suggestion, UserEvent } from 'src/application/models';
|
|
5
|
+
import { useSetAtom } from 'jotai';
|
|
6
|
+
import { useCallback } from 'react';
|
|
7
|
+
import { v4 as uuid } from 'uuid';
|
|
8
|
+
import { queueUserEventAtom } from 'src/atoms/chat/messageQueue';
|
|
9
|
+
|
|
10
|
+
export interface SalesAgentChatAPI {
|
|
11
|
+
logPageVisit: ({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => void;
|
|
12
|
+
onSuggestionClicked: (suggestion: Suggestion) => void;
|
|
13
|
+
onTypedMessageSubmitted: ({ query }: { query: string }) => void;
|
|
14
|
+
onFormResponseSubmitted: (formResponse: any) => void; // TODO: Figure out the right type
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useSalesAgentChatAPI = () => {
|
|
18
|
+
// TODO: Each of these functions will trigger both the necessary amplitude events and initiate the
|
|
19
|
+
// necessary actions to trigger the backend API
|
|
20
|
+
const queueUserEvent = useSetAtom(queueUserEventAtom);
|
|
21
|
+
|
|
22
|
+
const logPageVisit = useCallback(
|
|
23
|
+
({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => {
|
|
24
|
+
const event: UserEvent = {
|
|
25
|
+
eventId: uuid(),
|
|
26
|
+
category: UserEventCategory.PageVisit,
|
|
27
|
+
createdAt: new Date().toISOString(),
|
|
28
|
+
attributes: {
|
|
29
|
+
url: window.location.href,
|
|
30
|
+
pageVisitCategory,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
queueUserEvent(event);
|
|
34
|
+
},
|
|
35
|
+
[queueUserEvent],
|
|
36
|
+
);
|
|
37
|
+
const onSuggestionClicked = useCallback(
|
|
38
|
+
(suggestion: Suggestion) => {
|
|
39
|
+
const event: UserEvent = {
|
|
40
|
+
eventId: uuid(),
|
|
41
|
+
category: UserEventCategory.SuggestionClicked,
|
|
42
|
+
createdAt: new Date().toISOString(),
|
|
43
|
+
attributes: {
|
|
44
|
+
suggestionId: suggestion.id,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
queueUserEvent(event);
|
|
48
|
+
},
|
|
49
|
+
[queueUserEvent],
|
|
50
|
+
);
|
|
51
|
+
const onTypedMessageSubmitted = useCallback(
|
|
52
|
+
({ query }: { query: string }) => {
|
|
53
|
+
const event: UserEvent = {
|
|
54
|
+
eventId: uuid(),
|
|
55
|
+
category: UserEventCategory.QueryTyped,
|
|
56
|
+
createdAt: new Date().toISOString(),
|
|
57
|
+
attributes: {
|
|
58
|
+
query,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
queueUserEvent(event);
|
|
62
|
+
},
|
|
63
|
+
[queueUserEvent],
|
|
64
|
+
);
|
|
65
|
+
const onFormResponseSubmitted = useCallback(() => {
|
|
66
|
+
// TODO: Implement the form response submitted
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
logPageVisit,
|
|
71
|
+
onSuggestionClicked,
|
|
72
|
+
onTypedMessageSubmitted,
|
|
73
|
+
onFormResponseSubmitted,
|
|
74
|
+
};
|
|
75
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { useAtomValue, useSetAtom } from 'jotai';
|
|
2
|
+
import { ReactNode, createContext, useCallback, useEffect, useMemo } from 'react';
|
|
3
|
+
import { Message } from 'src/application/models/message';
|
|
4
|
+
import { Suggestion, UserEvent } from 'src/application/models';
|
|
5
|
+
import { messagesAtom, suggestionsAtom } from 'src/atoms/chat/chatState';
|
|
6
|
+
import {
|
|
7
|
+
processUserEventAtom,
|
|
8
|
+
userEventQueueAtom,
|
|
9
|
+
userQueueEventCountAtom,
|
|
10
|
+
} from 'src/atoms/chat/messageQueue';
|
|
11
|
+
import { useSystemSettingsContext } from 'src/hooks/SystemSettingsContext';
|
|
12
|
+
import { SalesAgentChatAPI, useSalesAgentChatAPI } from './chatAPI';
|
|
13
|
+
import { useSalesAgentService } from './salesAgentService';
|
|
14
|
+
|
|
15
|
+
interface SalesAgent extends SalesAgentChatAPI {
|
|
16
|
+
// Messages are the full list of all turns
|
|
17
|
+
messages: Message[][];
|
|
18
|
+
// Pending messages are messages that the user has clicked/typed but have not yet been sent to the backend.
|
|
19
|
+
pendingMessages: UserEvent[];
|
|
20
|
+
// Suggestions are the list of suggestions that the user can click on in response to the most recent message from the backend
|
|
21
|
+
suggestions: Suggestion[];
|
|
22
|
+
// True while the response is streaming from the backend
|
|
23
|
+
isResponseStreaming: boolean;
|
|
24
|
+
// True while the response is pending from the backend
|
|
25
|
+
isPendingResponse: boolean;
|
|
26
|
+
// True when the sales agent is initialized
|
|
27
|
+
isInitialized: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const SalesAgentContext = createContext<SalesAgent | undefined>(undefined);
|
|
31
|
+
|
|
32
|
+
export const SalesAgentProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
|
33
|
+
const userEvents = useAtomValue(userEventQueueAtom);
|
|
34
|
+
const userQueueEventCount = useAtomValue(userQueueEventCountAtom);
|
|
35
|
+
const markUserEventsProcessed = useSetAtom(processUserEventAtom);
|
|
36
|
+
const settingsContext = useSystemSettingsContext();
|
|
37
|
+
|
|
38
|
+
const { getStreamingResponses, createResponsePayload } = useSalesAgentService();
|
|
39
|
+
|
|
40
|
+
// TODO: Ensure that amplitude events are being emitted
|
|
41
|
+
|
|
42
|
+
// TODO: Add support for the streaming responses to function
|
|
43
|
+
|
|
44
|
+
// TODO: Add support for the hydration of the messages from the backend on initialization
|
|
45
|
+
const sendMessagesToBackend = useCallback(async () => {
|
|
46
|
+
// Fast exit if there are no pending messages
|
|
47
|
+
if (userEvents.length === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// TODO: Support sending multiple messages to the backend in one request
|
|
51
|
+
const [pendingMessage] = userEvents.slice(0, userQueueEventCount);
|
|
52
|
+
try {
|
|
53
|
+
const requestPayload = createResponsePayload({
|
|
54
|
+
userEvents: [pendingMessage],
|
|
55
|
+
generationParams: settingsContext.generationParams,
|
|
56
|
+
});
|
|
57
|
+
const response = await getStreamingResponses(requestPayload);
|
|
58
|
+
|
|
59
|
+
console.log('response', response);
|
|
60
|
+
// Remove the pending message from the user events
|
|
61
|
+
markUserEventsProcessed([pendingMessage.eventId]);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('error sending message');
|
|
64
|
+
}
|
|
65
|
+
}, [
|
|
66
|
+
userEvents,
|
|
67
|
+
userQueueEventCount,
|
|
68
|
+
createResponsePayload,
|
|
69
|
+
settingsContext.generationParams,
|
|
70
|
+
getStreamingResponses,
|
|
71
|
+
markUserEventsProcessed,
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
console.log('userQueueEventCount', userQueueEventCount);
|
|
75
|
+
console.log('userEvents', userEvents);
|
|
76
|
+
|
|
77
|
+
// This is the primary event loop for communicating with the backend API
|
|
78
|
+
// It will be triggered when there are pending messages to be sent to the backend
|
|
79
|
+
// It will be responsible for sending the messages to the backend and receiving the responses
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (userQueueEventCount > 0) {
|
|
82
|
+
sendMessagesToBackend();
|
|
83
|
+
}
|
|
84
|
+
// TODO: Add a suggestion retrieval here (don't get suggestions unless the event queue is empty)
|
|
85
|
+
console.log('SalesAgentProvider useEffect');
|
|
86
|
+
}, [sendMessagesToBackend, userQueueEventCount]);
|
|
87
|
+
|
|
88
|
+
return <SalesAgentContext.Provider value={undefined}>{children}</SalesAgentContext.Provider>;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const useSalesAgent = (): SalesAgent => {
|
|
92
|
+
const messages = useAtomValue(messagesAtom);
|
|
93
|
+
const suggestions = useAtomValue(suggestionsAtom);
|
|
94
|
+
const pendingMessages = useAtomValue(userEventQueueAtom);
|
|
95
|
+
const isResponseStreaming = false; // useAtomValue(isResponseStreamingAtom);
|
|
96
|
+
const isPendingResponse = false; // useAtomValue(isPendingResponseAtom);
|
|
97
|
+
const isInitialized = false; // useAtomValue(isInitializedAtom);
|
|
98
|
+
|
|
99
|
+
const { logPageVisit, onSuggestionClicked, onTypedMessageSubmitted, onFormResponseSubmitted } =
|
|
100
|
+
useSalesAgentChatAPI();
|
|
101
|
+
|
|
102
|
+
const salesAgent: SalesAgent = useMemo(() => {
|
|
103
|
+
return {
|
|
104
|
+
messages,
|
|
105
|
+
suggestions,
|
|
106
|
+
pendingMessages,
|
|
107
|
+
isResponseStreaming,
|
|
108
|
+
isPendingResponse,
|
|
109
|
+
isInitialized,
|
|
110
|
+
logPageVisit,
|
|
111
|
+
onSuggestionClicked,
|
|
112
|
+
onTypedMessageSubmitted,
|
|
113
|
+
onFormResponseSubmitted,
|
|
114
|
+
};
|
|
115
|
+
}, [
|
|
116
|
+
messages,
|
|
117
|
+
suggestions,
|
|
118
|
+
pendingMessages,
|
|
119
|
+
isResponseStreaming,
|
|
120
|
+
isPendingResponse,
|
|
121
|
+
isInitialized,
|
|
122
|
+
logPageVisit,
|
|
123
|
+
onSuggestionClicked,
|
|
124
|
+
onTypedMessageSubmitted,
|
|
125
|
+
onFormResponseSubmitted,
|
|
126
|
+
]);
|
|
127
|
+
return salesAgent;
|
|
128
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { useAtomValue, useSetAtom } from 'jotai';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { v4 as uuid } from 'uuid';
|
|
4
|
+
import CommerceApiClient from 'src/application/commerce-api';
|
|
5
|
+
import { appDetailsAtom } from 'src/atoms/app';
|
|
6
|
+
import Logger from 'src/application/logging/logger';
|
|
7
|
+
import {
|
|
8
|
+
GenerationParams,
|
|
9
|
+
Message,
|
|
10
|
+
MessageType,
|
|
11
|
+
NextMessageRequest,
|
|
12
|
+
Response,
|
|
13
|
+
UserEvent,
|
|
14
|
+
} from 'src/application/models';
|
|
15
|
+
import { messageFromResponse } from 'src/application/utils';
|
|
16
|
+
import { messagesAtom, requestFailureAtom } from 'src/atoms/chat/chatState';
|
|
17
|
+
import { useMessageInterceptor } from 'src/interceptors/useMessageInterceptor';
|
|
18
|
+
import { useFeatureFlagService } from '../featureFlagServiceContext';
|
|
19
|
+
|
|
20
|
+
interface SalesAgentService {
|
|
21
|
+
createResponsePayload: (payload: {
|
|
22
|
+
userEvents: UserEvent[];
|
|
23
|
+
generationParams?: GenerationParams;
|
|
24
|
+
}) => NextMessageRequest;
|
|
25
|
+
getStreamingResponses: (payload: NextMessageRequest) => Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const getQueryParam = (key: string): string | null => {
|
|
29
|
+
const urlObj = new URL(window.location.href);
|
|
30
|
+
return urlObj.searchParams.get(key);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const updateMessageState = (
|
|
34
|
+
message: Message,
|
|
35
|
+
lastMessage: Message,
|
|
36
|
+
setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
|
|
37
|
+
): Message => {
|
|
38
|
+
if (lastMessage == null) {
|
|
39
|
+
setMessages(prev => [...prev, [message]]);
|
|
40
|
+
return message;
|
|
41
|
+
}
|
|
42
|
+
if (lastMessage.type === MessageType.Text && message.type === MessageType.Text) {
|
|
43
|
+
const newMessage = {
|
|
44
|
+
...lastMessage,
|
|
45
|
+
metadata: {
|
|
46
|
+
...lastMessage.metadata,
|
|
47
|
+
content: lastMessage.metadata.content + message.metadata.content,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
setMessages(prev => {
|
|
51
|
+
const lastTurn = prev[prev.length - 1];
|
|
52
|
+
return [
|
|
53
|
+
...prev.slice(0, prev.length - 1),
|
|
54
|
+
[...lastTurn.slice(0, lastTurn.length - 1), newMessage],
|
|
55
|
+
];
|
|
56
|
+
});
|
|
57
|
+
return newMessage;
|
|
58
|
+
}
|
|
59
|
+
setMessages(prev => [...prev.slice(0, prev.length - 1), [...prev[prev.length - 1], message]]);
|
|
60
|
+
return message;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const processStreamingResponse = async (
|
|
64
|
+
stream: AsyncIterable<Response>,
|
|
65
|
+
messageInterceptor: { intercept: (response?: Response) => boolean | undefined },
|
|
66
|
+
setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
|
|
67
|
+
): Promise<void> => {
|
|
68
|
+
let lastMessage: Message | undefined;
|
|
69
|
+
|
|
70
|
+
for await (const response of stream) {
|
|
71
|
+
try {
|
|
72
|
+
if (messageInterceptor.intercept(response)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!response) {
|
|
77
|
+
throw new Error('No response from stream');
|
|
78
|
+
}
|
|
79
|
+
const message = messageFromResponse(response);
|
|
80
|
+
if (!message) {
|
|
81
|
+
throw new Error('Failed to transform API response to client message');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// No support for ChatSearch messages at the current time.
|
|
85
|
+
// Perhaps we add support back in the future
|
|
86
|
+
// if (message.type === MessageType.ProductSearch) {
|
|
87
|
+
// handleSearchResults(message);
|
|
88
|
+
// hasSearchResults = true;
|
|
89
|
+
// setSearchIsLoading(false); // Update search loading immediately when results are detected
|
|
90
|
+
// }
|
|
91
|
+
|
|
92
|
+
lastMessage = updateMessageState(message, lastMessage!, setMessages);
|
|
93
|
+
} catch (error: unknown) {
|
|
94
|
+
Logger.logWarn(`[spiffy-ai] Failed to generate responses from stream`, error, {
|
|
95
|
+
lastResponse: lastMessage,
|
|
96
|
+
response,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const useSalesAgentService: () => SalesAgentService = () => {
|
|
103
|
+
const setRequestFailure = useSetAtom(requestFailureAtom);
|
|
104
|
+
const setMessages = useSetAtom(messagesAtom);
|
|
105
|
+
const messageInterceptor = useMessageInterceptor();
|
|
106
|
+
|
|
107
|
+
const featureFlagService = useFeatureFlagService();
|
|
108
|
+
const context = useAtomValue(appDetailsAtom);
|
|
109
|
+
|
|
110
|
+
const createResponsePayload = useCallback(
|
|
111
|
+
({
|
|
112
|
+
userEvents,
|
|
113
|
+
generationParams,
|
|
114
|
+
}: {
|
|
115
|
+
userEvents: UserEvent[];
|
|
116
|
+
generationParams?: GenerationParams;
|
|
117
|
+
}): NextMessageRequest => {
|
|
118
|
+
const featureFlags = featureFlagService?.featureFlagService?.getFeatureFlags() || {};
|
|
119
|
+
|
|
120
|
+
const overrideConfigVersion =
|
|
121
|
+
getQueryParam('spiffy_config_version') ||
|
|
122
|
+
getQueryParam('envive_config_version') ||
|
|
123
|
+
undefined;
|
|
124
|
+
const overrideModelDatetime = getQueryParam('override_model_datetime') || undefined;
|
|
125
|
+
return {
|
|
126
|
+
id: uuid(),
|
|
127
|
+
context,
|
|
128
|
+
userEvents,
|
|
129
|
+
featureFlags,
|
|
130
|
+
generationParams,
|
|
131
|
+
overrideConfigVersion,
|
|
132
|
+
overrideModelDatetime,
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
[context, featureFlagService?.featureFlagService],
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const getStreamingResponses = useCallback(
|
|
139
|
+
async (payload: NextMessageRequest): Promise<void> => {
|
|
140
|
+
// logPerfMetric(PerfMetricsEvents.FirstResponseStarted);
|
|
141
|
+
// const startTime = Date.now();
|
|
142
|
+
console.log('getStreamingResponses payload', JSON.stringify(payload, null, 2));
|
|
143
|
+
const stream = CommerceApiClient.getNextResponseStreaming(payload);
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
setRequestFailure(false);
|
|
147
|
+
|
|
148
|
+
await processStreamingResponse(stream, messageInterceptor, setMessages);
|
|
149
|
+
|
|
150
|
+
// TODO: Add support for the Chrome Extension communication
|
|
151
|
+
// Log successful next_responses call
|
|
152
|
+
// const responseTime = Date.now() - startTime;
|
|
153
|
+
// await logBundleEvent({
|
|
154
|
+
// level: 'info',
|
|
155
|
+
// event: 'NEXT_RESPONSE_SUCCESS',
|
|
156
|
+
// context: {
|
|
157
|
+
// type: 'next_responses',
|
|
158
|
+
// endpoint: '/v1/next_responses',
|
|
159
|
+
// statusCode: 200,
|
|
160
|
+
// responseTime,
|
|
161
|
+
// },
|
|
162
|
+
// });
|
|
163
|
+
} catch (e) {
|
|
164
|
+
console.error('error getting streaming responses', e);
|
|
165
|
+
// Log failed next_responses call
|
|
166
|
+
// const responseTime = Date.now() - startTime;
|
|
167
|
+
// await logBundleEvent({
|
|
168
|
+
// level: 'error',
|
|
169
|
+
// event: 'NEXT_RESPONSE_FAILED',
|
|
170
|
+
// message: `Failed to get streaming response: ${e}`,
|
|
171
|
+
// context: {
|
|
172
|
+
// type: 'next_responses',
|
|
173
|
+
// endpoint: '/v1/next_responses',
|
|
174
|
+
// responseTime,
|
|
175
|
+
// error: e instanceof Error ? e.message : String(e),
|
|
176
|
+
// },
|
|
177
|
+
// });
|
|
178
|
+
|
|
179
|
+
// handleStreamingError(e, setRequestFailure, setMessages);
|
|
180
|
+
throw e;
|
|
181
|
+
// } finally {
|
|
182
|
+
// logPerfMetric(PerfMetricsEvents.FirstResponseCompleted);
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
[
|
|
186
|
+
// logPerfMetric,
|
|
187
|
+
setRequestFailure,
|
|
188
|
+
messageInterceptor,
|
|
189
|
+
setMessages,
|
|
190
|
+
],
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
createResponsePayload,
|
|
195
|
+
getStreamingResponses,
|
|
196
|
+
};
|
|
197
|
+
};
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, waitFor
|
|
3
|
-
import { Provider } from 'jotai';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import { Provider, useAtomValue } from 'jotai';
|
|
4
|
+
import {
|
|
5
|
+
EnviveConfigProvider,
|
|
6
|
+
useEnviveConfig,
|
|
7
|
+
} from 'src/contexts/enviveConfigContext/enviveConfigContext';
|
|
7
8
|
import { LocalStorageProvider } from 'src/contexts/localStorageContext/localStorageContext';
|
|
8
9
|
import { GraphQLProvider } from 'src/contexts/graphqlContext/graphqlContext';
|
|
9
10
|
import { UserIdentityProvider } from 'src/contexts/userIdentityContext/userIdentityContext';
|
|
10
11
|
import { FeatureFlagServiceProvider } from 'src/contexts/featureFlagServiceContext/featureFlagServiceContext';
|
|
11
12
|
import { baseUrlAtom } from 'src/atoms/envive/enviveConfig';
|
|
12
13
|
import {
|
|
13
|
-
setSearchServiceFunction,
|
|
14
14
|
clearSearchServiceFunction,
|
|
15
|
-
|
|
15
|
+
setSearchServiceFunction,
|
|
16
16
|
} from 'src/atoms/search/searchServiceAdapter';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
17
|
+
import { SearchResult } from 'src/application/models/api/search';
|
|
18
|
+
|
|
19
|
+
import { useAppDetails } from 'src/hooks/AppDetails/useAppDetails';
|
|
20
|
+
import * as commerceApiClient from '@spiffy-ai/commerce-api-client';
|
|
21
|
+
import { SearchProvider, useSearchService } from '../searchContext';
|
|
21
22
|
|
|
22
23
|
// Mock the commerce-api-client
|
|
23
24
|
const mockV1SearchQueryGet = vi.fn();
|
|
@@ -41,6 +42,7 @@ vi.mock('@spiffy-ai/commerce-api-client', () => {
|
|
|
41
42
|
},
|
|
42
43
|
ResponseError: class ResponseError extends Error {
|
|
43
44
|
response: any;
|
|
45
|
+
|
|
44
46
|
constructor(message: string, response?: any) {
|
|
45
47
|
super(message);
|
|
46
48
|
this.response = response;
|
|
@@ -85,10 +87,6 @@ vi.mock('src/atoms/search/searchServiceAdapter', () => ({
|
|
|
85
87
|
getSearchServiceFunction: vi.fn(),
|
|
86
88
|
}));
|
|
87
89
|
|
|
88
|
-
import { useAppDetails } from 'src/hooks/AppDetails/useAppDetails';
|
|
89
|
-
import { useEnviveConfig } from 'src/contexts/enviveConfigContext/enviveConfigContext';
|
|
90
|
-
import * as commerceApiClient from '@spiffy-ai/commerce-api-client';
|
|
91
|
-
|
|
92
90
|
// Get mocked functions
|
|
93
91
|
const getMocks = () => {
|
|
94
92
|
return (commerceApiClient as any).__getMocks();
|
|
@@ -129,6 +127,7 @@ const MockSearchComponent: React.FC = () => {
|
|
|
129
127
|
<button
|
|
130
128
|
data-testid="search-btn"
|
|
131
129
|
onClick={handleSearch}
|
|
130
|
+
type="button"
|
|
132
131
|
>
|
|
133
132
|
Search
|
|
134
133
|
</button>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useContext,
|
|
1
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo } from 'react';
|
|
2
2
|
import Logger from '../../application/logging/logger';
|
|
3
3
|
|
|
4
4
|
interface SessionStorageContextType {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, waitFor
|
|
3
|
-
import { Provider } from 'jotai';
|
|
4
|
-
import { useAtomValue } from 'jotai';
|
|
5
|
-
import { SystemSettingsContextProvider, defaultGenerationParams } from '../systemSettingsContext';
|
|
2
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import { Provider, useAtomValue } from 'jotai';
|
|
6
4
|
import { useSystemSettingsContext } from 'src/hooks/SystemSettingsContext/useSystemSettingsContext';
|
|
7
5
|
import { EnviveConfigProvider } from 'src/contexts/enviveConfigContext/enviveConfigContext';
|
|
8
6
|
import { baseUrlAtom } from 'src/atoms/envive/enviveConfig';
|
|
9
7
|
import { GenerationParams } from 'src/application/models';
|
|
8
|
+
import { SystemSettingsContextProvider, defaultGenerationParams } from '../systemSettingsContext';
|
|
10
9
|
|
|
11
10
|
// Component that uses the useSystemSettingsContext hook
|
|
12
11
|
const MockSystemSettingsComponent: React.FC = () => {
|
|
@@ -38,6 +37,7 @@ const MockSystemSettingsComponent: React.FC = () => {
|
|
|
38
37
|
<button
|
|
39
38
|
data-testid="update-params-btn"
|
|
40
39
|
onClick={handleUpdate}
|
|
40
|
+
type="button"
|
|
41
41
|
>
|
|
42
42
|
Update Params
|
|
43
43
|
</button>
|
|
@@ -212,7 +212,7 @@ describe('SystemSettingsContextProvider', () => {
|
|
|
212
212
|
describe('showDebugBar Prop', () => {
|
|
213
213
|
it('should pass showDebugBar prop to context', async () => {
|
|
214
214
|
render(
|
|
215
|
-
<TestWrapper showDebugBar
|
|
215
|
+
<TestWrapper showDebugBar>
|
|
216
216
|
<MockSystemSettingsComponent />
|
|
217
217
|
</TestWrapper>,
|
|
218
218
|
);
|
|
@@ -346,6 +346,7 @@ describe('SystemSettingsContextProvider', () => {
|
|
|
346
346
|
<button
|
|
347
347
|
data-testid="partial-update-btn"
|
|
348
348
|
onClick={handlePartialUpdate}
|
|
349
|
+
type="button"
|
|
349
350
|
>
|
|
350
351
|
Partial Update
|
|
351
352
|
</button>
|
|
@@ -449,7 +450,7 @@ describe('SystemSettingsContextProvider', () => {
|
|
|
449
450
|
const firstShowDebugBar = contextValue1.showDebugBar;
|
|
450
451
|
|
|
451
452
|
rerender(
|
|
452
|
-
<TestWrapper showDebugBar
|
|
453
|
+
<TestWrapper showDebugBar>
|
|
453
454
|
<Component1 />
|
|
454
455
|
<Component2 />
|
|
455
456
|
</TestWrapper>,
|