@constructor-io/constructorio-ui-pia 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constructorio-ui-pia-bundled.js +76 -73
- package/lib/cjs/components/CioPia/CioPia.js +27 -5
- package/lib/cjs/components/CioPia/PiaCustomCarousel.js +6 -2
- package/lib/cjs/components/ConversationHistory/ConversationHistory.js +3 -3
- package/lib/cjs/components/PiaConversation/PiaConversation.js +2 -2
- package/lib/cjs/components/PiaInlineAnswer/PiaInlineAnswer.js +3 -3
- package/lib/cjs/constants.js +2 -1
- package/lib/cjs/hooks/mocks/MockConstructorIOClient.js +1 -2
- package/lib/cjs/hooks/mocks/agent.js +16 -1
- package/lib/cjs/hooks/useCioClient.js +2 -2
- package/lib/cjs/hooks/useCioPia.js +12 -3
- package/lib/cjs/hooks/useConversation.js +32 -9
- package/lib/cjs/hooks/useTracking.js +71 -0
- package/lib/cjs/hooks/useViewportTracking.js +92 -0
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/components/CioPia/CioPia.js +26 -5
- package/lib/mjs/components/CioPia/PiaCustomCarousel.js +6 -2
- package/lib/mjs/components/ConversationHistory/ConversationHistory.js +3 -3
- package/lib/mjs/components/PiaConversation/PiaConversation.js +2 -2
- package/lib/mjs/components/PiaInlineAnswer/PiaInlineAnswer.js +3 -3
- package/lib/mjs/constants.js +1 -0
- package/lib/mjs/hooks/mocks/MockConstructorIOClient.js +5 -2
- package/lib/mjs/hooks/mocks/agent.js +16 -1
- package/lib/mjs/hooks/useCioClient.js +2 -2
- package/lib/mjs/hooks/useCioPia.js +13 -4
- package/lib/mjs/hooks/useConversation.js +24 -2
- package/lib/mjs/hooks/useTracking.js +107 -0
- package/lib/mjs/hooks/useViewportTracking.js +89 -0
- package/lib/mjs/version.js +1 -1
- package/lib/types/components/CioPia/CioPia.d.ts +2 -0
- package/lib/types/components/CioPia/PiaCustomCarousel.d.ts +4 -1
- package/lib/types/components/ConversationHistory/ConversationHistory.d.ts +5 -2
- package/lib/types/components/PiaConversation/PiaConversation.d.ts +5 -2
- package/lib/types/components/PiaInlineAnswer/PiaInlineAnswer.d.ts +6 -2
- package/lib/types/constants.d.ts +1 -0
- package/lib/types/hooks/useCioClient.d.ts +3 -7
- package/lib/types/hooks/useCioPia.d.ts +4 -0
- package/lib/types/hooks/useConversation.d.ts +5 -2
- package/lib/types/hooks/useTracking.d.ts +27 -0
- package/lib/types/hooks/useViewportTracking.d.ts +10 -0
- package/lib/types/utils/transformers.d.ts +1 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +6 -3
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
const react_1 = tslib_1.
|
|
4
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
5
|
const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-components");
|
|
6
6
|
const Input_1 = tslib_1.__importDefault(require("../Input/Input"));
|
|
7
7
|
const SuggestedQuestionsContainer_1 = tslib_1.__importDefault(require("../SuggestedQuestionsContainer/SuggestedQuestionsContainer"));
|
|
8
8
|
const useCioPia_1 = tslib_1.__importDefault(require("../../hooks/useCioPia"));
|
|
9
9
|
const useConversation_1 = tslib_1.__importDefault(require("../../hooks/useConversation"));
|
|
10
|
+
const useTracking_1 = tslib_1.__importDefault(require("../../hooks/useTracking"));
|
|
11
|
+
const useViewportTracking_1 = tslib_1.__importDefault(require("../../hooks/useViewportTracking"));
|
|
10
12
|
const useViewportCallbacks_1 = tslib_1.__importDefault(require("../../hooks/useViewportCallbacks"));
|
|
11
13
|
const ErrorBlock_1 = tslib_1.__importDefault(require("../Error/ErrorBlock"));
|
|
12
14
|
const LoadingSkeleton_1 = tslib_1.__importDefault(require("../LoadingSkeleton/LoadingSkeleton"));
|
|
@@ -16,7 +18,8 @@ const PiaModal_1 = tslib_1.__importDefault(require("../PiaConversation/PiaModal"
|
|
|
16
18
|
const PiaConversation_1 = tslib_1.__importDefault(require("../PiaConversation/PiaConversation"));
|
|
17
19
|
// eslint-disable-next-line complexity
|
|
18
20
|
function CioPia(props) {
|
|
19
|
-
|
|
21
|
+
var _a;
|
|
22
|
+
const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, children, translations, suggestedQuestionsParameters, } = props;
|
|
20
23
|
const { learnMoreUrl, showFeedback, mode = 'default', type = 'inline', showPreviousItems, disclaimerPosition = 'bottom', } = displayConfigs || {};
|
|
21
24
|
const isConversation = mode === 'conversation' || type === 'modal';
|
|
22
25
|
const pia = (0, useCioPia_1.default)({
|
|
@@ -28,8 +31,24 @@ function CioPia(props) {
|
|
|
28
31
|
suggestedQuestionsParameters,
|
|
29
32
|
formatImageUrl: formatters === null || formatters === void 0 ? void 0 : formatters.formatImageUrl,
|
|
30
33
|
});
|
|
31
|
-
const
|
|
32
|
-
|
|
34
|
+
const tracking = (0, useTracking_1.default)({
|
|
35
|
+
cioClient: pia.cioClient,
|
|
36
|
+
itemId,
|
|
37
|
+
itemName,
|
|
38
|
+
variationId,
|
|
39
|
+
threadId: pia.threadId,
|
|
40
|
+
});
|
|
41
|
+
const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, context, handleSubmitQuestion, handleQuestionClick, handleInputFocus, handleFeedback, resetState, } = (0, useConversation_1.default)({ pia, itemId, isConversation, callbacks, tracking });
|
|
42
|
+
const { containerRef: viewportContainerRef } = (0, useViewportTracking_1.default)({
|
|
43
|
+
tracking,
|
|
44
|
+
questions: displayedQuestions,
|
|
45
|
+
});
|
|
46
|
+
const { containerRef: callbackContainerRef } = (0, useViewportCallbacks_1.default)({ callbacks, context });
|
|
47
|
+
const containerRef = (0, react_1.useCallback)((node) => {
|
|
48
|
+
viewportContainerRef(node);
|
|
49
|
+
callbackContainerRef(node);
|
|
50
|
+
}, [viewportContainerRef, callbackContainerRef]);
|
|
51
|
+
const qnaResultId = (_a = pia.answers.data) === null || _a === void 0 ? void 0 : _a.qna_result_id;
|
|
33
52
|
const renderProps = {
|
|
34
53
|
items: currentItems,
|
|
35
54
|
isLoading,
|
|
@@ -55,6 +74,9 @@ function CioPia(props) {
|
|
|
55
74
|
displayedQuestions,
|
|
56
75
|
handleSubmitQuestion,
|
|
57
76
|
handleQuestionClick,
|
|
77
|
+
handleFeedback,
|
|
78
|
+
onResultClick: tracking.trackResultClick,
|
|
79
|
+
qnaResultId,
|
|
58
80
|
containerRef,
|
|
59
81
|
onInputFocus: handleInputFocus,
|
|
60
82
|
};
|
|
@@ -72,7 +94,7 @@ function CioPia(props) {
|
|
|
72
94
|
isLoading && react_1.default.createElement(LoadingSkeleton_1.default, { componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.loading }),
|
|
73
95
|
!isLoading && error && react_1.default.createElement(ErrorBlock_1.default, { message: (error === null || error === void 0 ? void 0 : error.message) || 'Unexpected error' }),
|
|
74
96
|
!isLoading && !error && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
75
|
-
currentAnswer && (react_1.default.createElement(PiaInlineAnswer_1.default, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides })),
|
|
97
|
+
currentAnswer && (react_1.default.createElement(PiaInlineAnswer_1.default, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides, onFeedback: handleFeedback, onResultClick: tracking.trackResultClick, question: currentQuestion, qnaResultId: qnaResultId })),
|
|
76
98
|
react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions }))))));
|
|
77
99
|
}
|
|
78
100
|
exports.default = CioPia;
|
|
@@ -10,10 +10,14 @@ function HtmlDescription({ product }) {
|
|
|
10
10
|
return null;
|
|
11
11
|
return (react_1.default.createElement("p", { className: 'cio-product-card-description', dangerouslySetInnerHTML: { __html: (0, contentTransformers_1.sanitizeHtml)(description) } }));
|
|
12
12
|
}
|
|
13
|
-
function PiaCustomCarousel({ items, componentOverrides, callbacks, }) {
|
|
13
|
+
function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, }) {
|
|
14
14
|
const wrapperRef = (0, react_1.useRef)(null);
|
|
15
15
|
// Determine to use user-defined click handler or default behavior
|
|
16
16
|
const productClickHandler = (0, react_1.useCallback)((item) => {
|
|
17
|
+
const position = items.findIndex((i) => i.id === item.id);
|
|
18
|
+
if (onResultClick && question) {
|
|
19
|
+
onResultClick(item, position >= 0 ? position : 0, question, qnaResultId);
|
|
20
|
+
}
|
|
17
21
|
const { onProductCardClick } = callbacks || {};
|
|
18
22
|
if (onProductCardClick) {
|
|
19
23
|
onProductCardClick(item);
|
|
@@ -21,7 +25,7 @@ function PiaCustomCarousel({ items, componentOverrides, callbacks, }) {
|
|
|
21
25
|
else if (item === null || item === void 0 ? void 0 : item.url) {
|
|
22
26
|
window.open(item.url, '_blank', 'noopener,noreferrer');
|
|
23
27
|
}
|
|
24
|
-
}, [callbacks]);
|
|
28
|
+
}, [callbacks, items, onResultClick, question, qnaResultId]);
|
|
25
29
|
// Set up event listener for product card clicks
|
|
26
30
|
(0, react_1.useEffect)(() => {
|
|
27
31
|
const el = wrapperRef.current;
|
|
@@ -8,7 +8,7 @@ const Disclaimer_1 = tslib_1.__importDefault(require("../CioPia/Disclaimer"));
|
|
|
8
8
|
const ErrorBlock_1 = tslib_1.__importDefault(require("../Error/ErrorBlock"));
|
|
9
9
|
const LoadingSkeleton_1 = tslib_1.__importDefault(require("../LoadingSkeleton/LoadingSkeleton"));
|
|
10
10
|
const PiaCustomCarousel_1 = tslib_1.__importDefault(require("../CioPia/PiaCustomCarousel"));
|
|
11
|
-
function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, }) {
|
|
11
|
+
function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, }) {
|
|
12
12
|
const scrollContainerRef = (0, react_1.useRef)(null);
|
|
13
13
|
(0, react_1.useEffect)(() => {
|
|
14
14
|
const container = scrollContainerRef.current;
|
|
@@ -34,8 +34,8 @@ function ConversationHistory({ conversationHistory, isLoading, error, currentIte
|
|
|
34
34
|
isLast && !isLoading && error && (react_1.default.createElement(ErrorBlock_1.default, { message: error.message || 'Unexpected error' })),
|
|
35
35
|
entry.answer && (react_1.default.createElement("div", { className: 'cio-pia-answer-container' },
|
|
36
36
|
react_1.default.createElement(Answer_1.default, { text: entry.answer, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.answer }),
|
|
37
|
-
carouselItems && (react_1.default.createElement(PiaCustomCarousel_1.default, { items: carouselItems, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.carousel, callbacks: callbacks })),
|
|
38
|
-
isLast && showFeedback && (react_1.default.createElement(Feedback_1.default, { translations: translations, onFeedback:
|
|
37
|
+
carouselItems && (react_1.default.createElement(PiaCustomCarousel_1.default, { items: carouselItems, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.carousel, callbacks: callbacks, onResultClick: onResultClick, question: entry.question, qnaResultId: qnaResultId })),
|
|
38
|
+
isLast && showFeedback && (react_1.default.createElement(Feedback_1.default, { translations: translations, onFeedback: handleFeedback, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.feedback }))))));
|
|
39
39
|
})),
|
|
40
40
|
disclaimerPosition === 'bottom' && disclaimer));
|
|
41
41
|
}
|
|
@@ -7,11 +7,11 @@ const SuggestedQuestionsContainer_1 = tslib_1.__importDefault(require("../Sugges
|
|
|
7
7
|
const SuggestedQuestionsSkeleton_1 = tslib_1.__importDefault(require("../SuggestedQuestionsContainer/SuggestedQuestionsSkeleton"));
|
|
8
8
|
const translate_1 = require("../../utils/translate");
|
|
9
9
|
const ConversationHistory_1 = tslib_1.__importDefault(require("../ConversationHistory/ConversationHistory"));
|
|
10
|
-
function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, onInputFocus, }) {
|
|
10
|
+
function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, handleFeedback, onResultClick, qnaResultId, onInputFocus, }) {
|
|
11
11
|
const hasHistory = conversationHistory.length > 0;
|
|
12
12
|
return (react_1.default.createElement("div", { ref: containerRef, className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
|
|
13
13
|
!hasHistory && (react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations))),
|
|
14
|
-
react_1.default.createElement(ConversationHistory_1.default, { conversationHistory: conversationHistory, isLoading: isLoading, error: error, currentItems: currentItems, showFeedback: showFeedback, showPreviousItems: showPreviousItems, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides }),
|
|
14
|
+
react_1.default.createElement(ConversationHistory_1.default, { conversationHistory: conversationHistory, isLoading: isLoading, error: error, currentItems: currentItems, showFeedback: showFeedback, showPreviousItems: showPreviousItems, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides, handleFeedback: handleFeedback, onResultClick: onResultClick, qnaResultId: qnaResultId }),
|
|
15
15
|
react_1.default.createElement("div", { className: 'cio-pia-conversation-footer' },
|
|
16
16
|
isLoading && !error && react_1.default.createElement(SuggestedQuestionsSkeleton_1.default, null),
|
|
17
17
|
!isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
|
|
@@ -6,13 +6,13 @@ const Answer_1 = tslib_1.__importDefault(require("../Answer/Answer"));
|
|
|
6
6
|
const Feedback_1 = tslib_1.__importDefault(require("../Feedback/Feedback"));
|
|
7
7
|
const Disclaimer_1 = tslib_1.__importDefault(require("../CioPia/Disclaimer"));
|
|
8
8
|
const PiaCustomCarousel_1 = tslib_1.__importDefault(require("../CioPia/PiaCustomCarousel"));
|
|
9
|
-
function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, }) {
|
|
9
|
+
function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, onFeedback, onResultClick, question, qnaResultId, }) {
|
|
10
10
|
const disclaimer = (react_1.default.createElement(Disclaimer_1.default, { learnMoreUrl: learnMoreUrl, translations: translations, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.disclaimer }));
|
|
11
11
|
return (react_1.default.createElement("div", { className: 'cio-pia-answer-container' },
|
|
12
12
|
disclaimerPosition === 'top' && disclaimer,
|
|
13
13
|
react_1.default.createElement(Answer_1.default, { text: currentAnswer, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.answer }),
|
|
14
|
-
currentItems && (react_1.default.createElement(PiaCustomCarousel_1.default, { items: currentItems, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.carousel, callbacks: callbacks })),
|
|
15
|
-
showFeedback && (react_1.default.createElement(Feedback_1.default, { translations: translations, onFeedback: callbacks === null || callbacks === void 0 ? void 0 : callbacks.onFeedback, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.feedback })),
|
|
14
|
+
currentItems && (react_1.default.createElement(PiaCustomCarousel_1.default, { items: currentItems, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.carousel, callbacks: callbacks, onResultClick: onResultClick, question: question, qnaResultId: qnaResultId })),
|
|
15
|
+
showFeedback && (react_1.default.createElement(Feedback_1.default, { translations: translations, onFeedback: onFeedback || (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onFeedback), componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.feedback })),
|
|
16
16
|
disclaimerPosition === 'bottom' && disclaimer));
|
|
17
17
|
}
|
|
18
18
|
exports.default = PiaInlineAnswer;
|
package/lib/cjs/constants.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DISCLAIMER_TEXT = exports.MOCK_QUESTIONS = exports.DEMO_QUESTION_ALTERNATIVE_PRODUCTS = exports.DEMO_QUESTION = exports.DEMO_ITEM_ID = exports.DEMO_API_KEY = void 0;
|
|
3
|
+
exports.DISCLAIMER_TEXT = exports.MOCK_QUESTIONS = exports.DEMO_QUESTION_ALTERNATIVE_PRODUCTS = exports.DEMO_QUESTION = exports.DEMO_ITEM_NAME = exports.DEMO_ITEM_ID = exports.DEMO_API_KEY = void 0;
|
|
4
4
|
exports.DEMO_API_KEY = 'key_13TO6qN9H3BP3Wrn';
|
|
5
5
|
exports.DEMO_ITEM_ID = '149100215';
|
|
6
|
+
exports.DEMO_ITEM_NAME = 'Ensure Original Nutrition Shake';
|
|
6
7
|
exports.DEMO_QUESTION = 'What is the nutritional content of this shake?';
|
|
7
8
|
exports.DEMO_QUESTION_ALTERNATIVE_PRODUCTS = 'What alternative products are available for this item?';
|
|
8
9
|
exports.MOCK_QUESTIONS = [
|
|
@@ -13,8 +13,7 @@ class MockConstructorIOClient {
|
|
|
13
13
|
this.recommendations = cioClient.recommendations;
|
|
14
14
|
this.tracker = cioClient.tracker;
|
|
15
15
|
this.quizzes = cioClient.quizzes;
|
|
16
|
-
|
|
17
|
-
this.agent = new agent_1.default(this.options);
|
|
16
|
+
this.agent = new agent_1.default(Object.assign(Object.assign({}, this.options), { clientId: options.clientId, sessionId: options.sessionId }));
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
exports.default = MockConstructorIOClient;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
// Create URL for PIA API
|
|
5
5
|
function createAgentUrl({ itemId, threadId, variationId, question, isStreaming = false, options, parameters = {}, }) {
|
|
6
|
-
const { apiKey, agentServiceUrl } = options;
|
|
6
|
+
const { apiKey, agentServiceUrl, clientId, sessionId, userId, segments, version } = options;
|
|
7
7
|
if (!agentServiceUrl)
|
|
8
8
|
throw new Error('Agent service URL is required');
|
|
9
9
|
let baseUrl = `${agentServiceUrl}/v1/item_questions`;
|
|
@@ -22,6 +22,21 @@ function createAgentUrl({ itemId, threadId, variationId, question, isStreaming =
|
|
|
22
22
|
if (variationId) {
|
|
23
23
|
url.searchParams.append('variation_id', variationId);
|
|
24
24
|
}
|
|
25
|
+
if (clientId) {
|
|
26
|
+
url.searchParams.append('i', clientId);
|
|
27
|
+
}
|
|
28
|
+
if (sessionId != null) {
|
|
29
|
+
url.searchParams.append('s', String(sessionId));
|
|
30
|
+
}
|
|
31
|
+
if (userId) {
|
|
32
|
+
url.searchParams.append('ui', userId);
|
|
33
|
+
}
|
|
34
|
+
if (version) {
|
|
35
|
+
url.searchParams.append('c', version);
|
|
36
|
+
}
|
|
37
|
+
if (segments === null || segments === void 0 ? void 0 : segments.length) {
|
|
38
|
+
segments.forEach((segment) => url.searchParams.append('us', segment));
|
|
39
|
+
}
|
|
25
40
|
// Any additional parameters
|
|
26
41
|
Object.entries(parameters).forEach(([key, value]) => {
|
|
27
42
|
if (value !== undefined) {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
+
const constructorio_client_javascript_1 = tslib_1.__importDefault(require("@constructor-io/constructorio-client-javascript"));
|
|
5
6
|
const version_1 = tslib_1.__importDefault(require("../version"));
|
|
6
|
-
const MockConstructorIOClient_1 = tslib_1.__importDefault(require("./mocks/MockConstructorIOClient"));
|
|
7
7
|
const useCioClient = ({ apiKey, cioClient, options } = {}) => {
|
|
8
8
|
if (!apiKey && !cioClient) {
|
|
9
9
|
throw new Error('Api Key or Constructor Client required');
|
|
@@ -12,7 +12,7 @@ const useCioClient = ({ apiKey, cioClient, options } = {}) => {
|
|
|
12
12
|
if (cioClient)
|
|
13
13
|
return cioClient;
|
|
14
14
|
if (apiKey) {
|
|
15
|
-
return new
|
|
15
|
+
return new constructorio_client_javascript_1.default(Object.assign({ apiKey, sendTrackingEvents: true, version: `cio-ui-pia-${version_1.default}` }, options));
|
|
16
16
|
}
|
|
17
17
|
return null;
|
|
18
18
|
}, [apiKey, cioClient, options]);
|
|
@@ -2,15 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
+
const MockConstructorIOClient_1 = tslib_1.__importDefault(require("./mocks/MockConstructorIOClient"));
|
|
5
6
|
const useAnswerResults_1 = tslib_1.__importDefault(require("./useAnswerResults"));
|
|
6
|
-
const useCioClient_1 = tslib_1.__importDefault(require("./useCioClient"));
|
|
7
7
|
const useSuggestedQuestions_1 = tslib_1.__importDefault(require("./useSuggestedQuestions"));
|
|
8
|
+
const version_1 = tslib_1.__importDefault(require("../version"));
|
|
8
9
|
function useCioPia(props) {
|
|
9
10
|
const { apiKey, itemId, variationId, threadId: providedThreadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
|
|
10
11
|
const [generatedThreadId] = (0, react_1.useState)(() => crypto.randomUUID());
|
|
11
12
|
const threadId = providedThreadId || generatedThreadId;
|
|
12
|
-
const
|
|
13
|
-
|
|
13
|
+
const client = (0, react_1.useMemo)(() => {
|
|
14
|
+
if (providedClient)
|
|
15
|
+
return providedClient;
|
|
16
|
+
return new MockConstructorIOClient_1.default({
|
|
17
|
+
apiKey,
|
|
18
|
+
sendTrackingEvents: true,
|
|
19
|
+
version: `cio-ui-pia-${version_1.default}`,
|
|
20
|
+
});
|
|
21
|
+
}, [apiKey, providedClient]);
|
|
14
22
|
const suggestedQuestions = (0, useSuggestedQuestions_1.default)({
|
|
15
23
|
itemId,
|
|
16
24
|
variationId,
|
|
@@ -26,6 +34,7 @@ function useCioPia(props) {
|
|
|
26
34
|
formatImageUrl,
|
|
27
35
|
});
|
|
28
36
|
return {
|
|
37
|
+
cioClient: client,
|
|
29
38
|
threadId,
|
|
30
39
|
suggestedQuestions,
|
|
31
40
|
answers,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const react_1 = require("react");
|
|
4
|
-
function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
4
|
+
function useConversation({ pia, itemId, isConversation, callbacks, tracking, }) {
|
|
5
5
|
var _a, _b, _c, _d;
|
|
6
6
|
const { suggestedQuestions, answers, threadId } = pia;
|
|
7
7
|
const { getAnswer } = answers;
|
|
@@ -11,8 +11,11 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
11
11
|
const [conversationHistory, setConversationHistory] = (0, react_1.useState)([]);
|
|
12
12
|
const entryIdRef = (0, react_1.useRef)(0);
|
|
13
13
|
const prevAnswerValueRef = (0, react_1.useRef)((_a = answers.data) === null || _a === void 0 ? void 0 : _a.value);
|
|
14
|
+
const hasTrackedCurrentAnswerRef = (0, react_1.useRef)(false);
|
|
15
|
+
const answersRef = (0, react_1.useRef)(answers);
|
|
14
16
|
const callbacksRef = (0, react_1.useRef)(callbacks);
|
|
15
17
|
const contextRef = (0, react_1.useRef)(context);
|
|
18
|
+
const trackingRef = (0, react_1.useRef)(tracking);
|
|
16
19
|
const lastQuestionRef = (0, react_1.useRef)('');
|
|
17
20
|
const lastSourceRef = (0, react_1.useRef)('user');
|
|
18
21
|
(0, react_1.useEffect)(() => {
|
|
@@ -21,9 +24,16 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
21
24
|
(0, react_1.useEffect)(() => {
|
|
22
25
|
contextRef.current = context;
|
|
23
26
|
}, [context]);
|
|
27
|
+
(0, react_1.useEffect)(() => {
|
|
28
|
+
trackingRef.current = tracking;
|
|
29
|
+
}, [tracking]);
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
31
|
+
answersRef.current = answers;
|
|
32
|
+
}, [answers]);
|
|
24
33
|
const submitQuestion = (0, react_1.useCallback)((question, source) => {
|
|
25
34
|
lastSourceRef.current = source;
|
|
26
35
|
lastQuestionRef.current = question;
|
|
36
|
+
hasTrackedCurrentAnswerRef.current = false;
|
|
27
37
|
setCurrentQuestion(question);
|
|
28
38
|
getAnswer(question);
|
|
29
39
|
if (isConversation) {
|
|
@@ -33,18 +43,26 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
33
43
|
}
|
|
34
44
|
}, [getAnswer, isConversation]);
|
|
35
45
|
const handleSubmitQuestion = (0, react_1.useCallback)((question) => {
|
|
36
|
-
var _a, _b;
|
|
37
|
-
(
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
(_a = trackingRef.current) === null || _a === void 0 ? void 0 : _a.trackQuestionSubmit(question);
|
|
48
|
+
(_c = (_b = callbacksRef.current) === null || _b === void 0 ? void 0 : _b.onQuestionSubmit) === null || _c === void 0 ? void 0 : _c.call(_b, question, contextRef.current, 'user');
|
|
38
49
|
submitQuestion(question, 'user');
|
|
39
50
|
}, [submitQuestion]);
|
|
40
51
|
const handleQuestionClick = (0, react_1.useCallback)((question) => {
|
|
41
|
-
var _a, _b;
|
|
42
|
-
(
|
|
52
|
+
var _a, _b, _c;
|
|
53
|
+
(_a = trackingRef.current) === null || _a === void 0 ? void 0 : _a.trackQuestionClick(question);
|
|
54
|
+
(_c = (_b = callbacksRef.current) === null || _b === void 0 ? void 0 : _b.onQuestionSubmit) === null || _c === void 0 ? void 0 : _c.call(_b, question, contextRef.current, 'suggestion');
|
|
43
55
|
submitQuestion(question, 'suggestion');
|
|
44
56
|
}, [submitQuestion]);
|
|
45
57
|
const handleInputFocus = (0, react_1.useCallback)(() => {
|
|
46
|
-
var _a, _b;
|
|
47
|
-
(
|
|
58
|
+
var _a, _b, _c;
|
|
59
|
+
(_a = trackingRef.current) === null || _a === void 0 ? void 0 : _a.trackFocus();
|
|
60
|
+
(_c = (_b = callbacksRef.current) === null || _b === void 0 ? void 0 : _b.onFocus) === null || _c === void 0 ? void 0 : _c.call(_b, contextRef.current);
|
|
61
|
+
}, []);
|
|
62
|
+
const handleFeedback = (0, react_1.useCallback)((type) => {
|
|
63
|
+
var _a, _b, _c, _d;
|
|
64
|
+
(_a = trackingRef.current) === null || _a === void 0 ? void 0 : _a.trackAnswerFeedback(type, (_b = answersRef.current.data) === null || _b === void 0 ? void 0 : _b.qna_result_id);
|
|
65
|
+
(_d = (_c = callbacksRef.current) === null || _c === void 0 ? void 0 : _c.onFeedback) === null || _d === void 0 ? void 0 : _d.call(_c, type);
|
|
48
66
|
}, []);
|
|
49
67
|
const resetState = (0, react_1.useCallback)(() => {
|
|
50
68
|
setCurrentQuestion('');
|
|
@@ -62,10 +80,14 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
62
80
|
setDisplayedQuestions(suggestedQuestions.data);
|
|
63
81
|
}, [suggestedQuestions.data]);
|
|
64
82
|
(0, react_1.useEffect)(() => {
|
|
65
|
-
var _a;
|
|
83
|
+
var _a, _b;
|
|
66
84
|
if ((_a = answers.data) === null || _a === void 0 ? void 0 : _a.follow_up_questions)
|
|
67
85
|
setDisplayedQuestions(answers.data.follow_up_questions);
|
|
68
|
-
|
|
86
|
+
if (answers.data && lastQuestionRef.current && !hasTrackedCurrentAnswerRef.current) {
|
|
87
|
+
hasTrackedCurrentAnswerRef.current = true;
|
|
88
|
+
(_b = trackingRef.current) === null || _b === void 0 ? void 0 : _b.trackAnswerView(lastQuestionRef.current, answers.data, answers.items);
|
|
89
|
+
}
|
|
90
|
+
}, [answers.data, answers.items]);
|
|
69
91
|
(0, react_1.useEffect)(() => {
|
|
70
92
|
var _a, _b, _c, _d, _e, _f;
|
|
71
93
|
const answerValue = (_b = (_a = answers.data) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
|
|
@@ -116,6 +138,7 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
116
138
|
handleSubmitQuestion,
|
|
117
139
|
handleQuestionClick,
|
|
118
140
|
handleInputFocus,
|
|
141
|
+
handleFeedback,
|
|
119
142
|
resetState,
|
|
120
143
|
};
|
|
121
144
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const react_1 = require("react");
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
function useTracking({ cioClient, itemId, itemName, variationId, threadId, }) {
|
|
6
|
+
const tracker = cioClient === null || cioClient === void 0 ? void 0 : cioClient.tracker;
|
|
7
|
+
const baseParams = (0, react_1.useMemo)(() => (Object.assign(Object.assign({ itemId,
|
|
8
|
+
itemName }, (variationId && { variationId })), (threadId && { threadId }))), [itemId, itemName, variationId, threadId]);
|
|
9
|
+
const mapQuestions = (0, react_1.useCallback)((questions) => questions.map((q) => ({ question: q.value })), []);
|
|
10
|
+
const trackViews = (0, react_1.useCallback)((questions, viewTimespans) => {
|
|
11
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentViews(Object.assign(Object.assign({}, baseParams), { questions: mapQuestions(questions), viewTimespans }));
|
|
12
|
+
}, [tracker, baseParams, mapQuestions]);
|
|
13
|
+
const trackView = (0, react_1.useCallback)((questions) => {
|
|
14
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentView(Object.assign(Object.assign({}, baseParams), { questions: mapQuestions(questions) }));
|
|
15
|
+
}, [tracker, baseParams, mapQuestions]);
|
|
16
|
+
const trackOutOfView = (0, react_1.useCallback)(() => {
|
|
17
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentOutOfView(baseParams);
|
|
18
|
+
}, [tracker, baseParams]);
|
|
19
|
+
const trackFocus = (0, react_1.useCallback)(() => {
|
|
20
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentFocus(baseParams);
|
|
21
|
+
}, [tracker, baseParams]);
|
|
22
|
+
const trackQuestionClick = (0, react_1.useCallback)((question) => {
|
|
23
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentQuestionClick(Object.assign(Object.assign({}, baseParams), { question }));
|
|
24
|
+
}, [tracker, baseParams]);
|
|
25
|
+
const trackQuestionSubmit = (0, react_1.useCallback)((question) => {
|
|
26
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentQuestionSubmit(Object.assign(Object.assign({}, baseParams), { question }));
|
|
27
|
+
}, [tracker, baseParams]);
|
|
28
|
+
const trackAnswerView = (0, react_1.useCallback)((question, answerData, items) => {
|
|
29
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentAnswerView(Object.assign(Object.assign(Object.assign(Object.assign({}, baseParams), { question, answerText: answerData.value, qnaResultId: answerData.qna_result_id }), (items &&
|
|
30
|
+
items.length > 0 && {
|
|
31
|
+
items: items.map((item) => ({
|
|
32
|
+
itemId: item.id,
|
|
33
|
+
itemName: item.name,
|
|
34
|
+
})),
|
|
35
|
+
})), (answerData.follow_up_questions &&
|
|
36
|
+
answerData.follow_up_questions.length > 0 && {
|
|
37
|
+
followUpQuestions: answerData.follow_up_questions.map((q) => ({
|
|
38
|
+
value: q.value,
|
|
39
|
+
})),
|
|
40
|
+
})));
|
|
41
|
+
}, [tracker, baseParams]);
|
|
42
|
+
const trackAnswerFeedback = (0, react_1.useCallback)((feedbackType, qnaResultId) => {
|
|
43
|
+
const feedbackLabel = feedbackType === types_1.FeedbackType.UP ? 'thumbs_up' : 'thumbs_down';
|
|
44
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentAnswerFeedback(Object.assign(Object.assign(Object.assign({}, baseParams), { feedbackLabel }), (qnaResultId && { qnaResultId })));
|
|
45
|
+
}, [tracker, baseParams]);
|
|
46
|
+
const trackResultClick = (0, react_1.useCallback)((clickedItem, position, question, qnaResultId) => {
|
|
47
|
+
tracker === null || tracker === void 0 ? void 0 : tracker.trackProductInsightsAgentResultClick(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ itemId: clickedItem.id, itemName: clickedItem.name }, (clickedItem.variationId && { variationId: clickedItem.variationId })), { question, seedItemId: itemId, seedItemName: itemName }), (variationId && { seedVariationId: variationId })), (qnaResultId && { qnaResultId })), (threadId && { threadId })), { position }));
|
|
48
|
+
}, [tracker, itemId, itemName, variationId, threadId]);
|
|
49
|
+
return (0, react_1.useMemo)(() => ({
|
|
50
|
+
trackViews,
|
|
51
|
+
trackView,
|
|
52
|
+
trackOutOfView,
|
|
53
|
+
trackFocus,
|
|
54
|
+
trackQuestionClick,
|
|
55
|
+
trackQuestionSubmit,
|
|
56
|
+
trackAnswerView,
|
|
57
|
+
trackAnswerFeedback,
|
|
58
|
+
trackResultClick,
|
|
59
|
+
}), [
|
|
60
|
+
trackViews,
|
|
61
|
+
trackView,
|
|
62
|
+
trackOutOfView,
|
|
63
|
+
trackFocus,
|
|
64
|
+
trackQuestionClick,
|
|
65
|
+
trackQuestionSubmit,
|
|
66
|
+
trackAnswerView,
|
|
67
|
+
trackAnswerFeedback,
|
|
68
|
+
trackResultClick,
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
exports.default = useTracking;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const react_1 = require("react");
|
|
4
|
+
const FLUSH_INTERVAL_MS = 5 * 60 * 1000;
|
|
5
|
+
function useViewportTracking({ tracking, questions, }) {
|
|
6
|
+
const nodeRef = (0, react_1.useRef)(null);
|
|
7
|
+
const observerRef = (0, react_1.useRef)(null);
|
|
8
|
+
const intervalRef = (0, react_1.useRef)(null);
|
|
9
|
+
const timespansRef = (0, react_1.useRef)([]);
|
|
10
|
+
const entryTimeRef = (0, react_1.useRef)(null);
|
|
11
|
+
const questionsRef = (0, react_1.useRef)(questions);
|
|
12
|
+
const trackingRef = (0, react_1.useRef)(tracking);
|
|
13
|
+
(0, react_1.useEffect)(() => {
|
|
14
|
+
const questionsJustArrived = questionsRef.current.length === 0 && questions.length > 0;
|
|
15
|
+
questionsRef.current = questions;
|
|
16
|
+
if (questionsJustArrived && entryTimeRef.current) {
|
|
17
|
+
trackingRef.current.trackView(questions);
|
|
18
|
+
}
|
|
19
|
+
}, [questions]);
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
trackingRef.current = tracking;
|
|
22
|
+
}, [tracking]);
|
|
23
|
+
// Stable: only reads refs
|
|
24
|
+
const flush = (0, react_1.useCallback)(() => {
|
|
25
|
+
if (entryTimeRef.current) {
|
|
26
|
+
timespansRef.current.push({
|
|
27
|
+
start: entryTimeRef.current,
|
|
28
|
+
end: new Date().toISOString(),
|
|
29
|
+
});
|
|
30
|
+
entryTimeRef.current = null;
|
|
31
|
+
}
|
|
32
|
+
if (timespansRef.current.length > 0 && questionsRef.current.length > 0) {
|
|
33
|
+
trackingRef.current.trackViews(questionsRef.current, [...timespansRef.current]);
|
|
34
|
+
timespansRef.current = [];
|
|
35
|
+
}
|
|
36
|
+
}, []);
|
|
37
|
+
const setupObserver = (0, react_1.useCallback)((element) => {
|
|
38
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
39
|
+
if (entry.isIntersecting) {
|
|
40
|
+
entryTimeRef.current = new Date().toISOString();
|
|
41
|
+
if (questionsRef.current.length > 0) {
|
|
42
|
+
trackingRef.current.trackView(questionsRef.current);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (entryTimeRef.current) {
|
|
46
|
+
timespansRef.current.push({
|
|
47
|
+
start: entryTimeRef.current,
|
|
48
|
+
end: new Date().toISOString(),
|
|
49
|
+
});
|
|
50
|
+
entryTimeRef.current = null;
|
|
51
|
+
trackingRef.current.trackOutOfView();
|
|
52
|
+
}
|
|
53
|
+
}, { threshold: 0.5 });
|
|
54
|
+
observer.observe(element);
|
|
55
|
+
observerRef.current = observer;
|
|
56
|
+
intervalRef.current = setInterval(flush, FLUSH_INTERVAL_MS);
|
|
57
|
+
const handleVisibilityChange = () => {
|
|
58
|
+
if (document.visibilityState === 'hidden') {
|
|
59
|
+
flush();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
63
|
+
return () => {
|
|
64
|
+
observer.disconnect();
|
|
65
|
+
if (intervalRef.current)
|
|
66
|
+
clearInterval(intervalRef.current);
|
|
67
|
+
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
68
|
+
flush();
|
|
69
|
+
};
|
|
70
|
+
}, [flush]);
|
|
71
|
+
const cleanupRef = (0, react_1.useRef)(null);
|
|
72
|
+
const containerRef = (0, react_1.useCallback)((node) => {
|
|
73
|
+
if (cleanupRef.current) {
|
|
74
|
+
cleanupRef.current();
|
|
75
|
+
cleanupRef.current = null;
|
|
76
|
+
}
|
|
77
|
+
nodeRef.current = node;
|
|
78
|
+
if (node) {
|
|
79
|
+
cleanupRef.current = setupObserver(node);
|
|
80
|
+
}
|
|
81
|
+
}, [setupObserver]);
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
83
|
+
return () => {
|
|
84
|
+
if (cleanupRef.current) {
|
|
85
|
+
cleanupRef.current();
|
|
86
|
+
cleanupRef.current = null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}, []);
|
|
90
|
+
return { containerRef };
|
|
91
|
+
}
|
|
92
|
+
exports.default = useViewportTracking;
|
package/lib/cjs/version.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
2
|
import { RenderPropsWrapper, } from '@constructor-io/constructorio-ui-components';
|
|
3
3
|
import Input from '../Input/Input';
|
|
4
4
|
import SuggestedQuestionsContainer from '../SuggestedQuestionsContainer/SuggestedQuestionsContainer';
|
|
5
5
|
import useCioPia from '../../hooks/useCioPia';
|
|
6
6
|
import useConversation from '../../hooks/useConversation';
|
|
7
|
+
import useTracking from '../../hooks/useTracking';
|
|
8
|
+
import useViewportTracking from '../../hooks/useViewportTracking';
|
|
7
9
|
import useViewportCallbacks from '../../hooks/useViewportCallbacks';
|
|
8
10
|
import ErrorBlock from '../Error/ErrorBlock';
|
|
9
11
|
import LoadingSkeleton from '../LoadingSkeleton/LoadingSkeleton';
|
|
@@ -13,7 +15,7 @@ import PiaModal from '../PiaConversation/PiaModal';
|
|
|
13
15
|
import PiaConversation from '../PiaConversation/PiaConversation';
|
|
14
16
|
// eslint-disable-next-line complexity
|
|
15
17
|
export default function CioPia(props) {
|
|
16
|
-
const { apiKey, itemId, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, children, translations, suggestedQuestionsParameters, } = props;
|
|
18
|
+
const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, children, translations, suggestedQuestionsParameters, } = props;
|
|
17
19
|
const { learnMoreUrl, showFeedback, mode = 'default', type = 'inline', showPreviousItems, disclaimerPosition = 'bottom', } = displayConfigs || {};
|
|
18
20
|
const isConversation = mode === 'conversation' || type === 'modal';
|
|
19
21
|
const pia = useCioPia({
|
|
@@ -25,8 +27,24 @@ export default function CioPia(props) {
|
|
|
25
27
|
suggestedQuestionsParameters,
|
|
26
28
|
formatImageUrl: formatters?.formatImageUrl,
|
|
27
29
|
});
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
+
const tracking = useTracking({
|
|
31
|
+
cioClient: pia.cioClient,
|
|
32
|
+
itemId,
|
|
33
|
+
itemName,
|
|
34
|
+
variationId,
|
|
35
|
+
threadId: pia.threadId,
|
|
36
|
+
});
|
|
37
|
+
const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, context, handleSubmitQuestion, handleQuestionClick, handleInputFocus, handleFeedback, resetState, } = useConversation({ pia, itemId, isConversation, callbacks, tracking });
|
|
38
|
+
const { containerRef: viewportContainerRef } = useViewportTracking({
|
|
39
|
+
tracking,
|
|
40
|
+
questions: displayedQuestions,
|
|
41
|
+
});
|
|
42
|
+
const { containerRef: callbackContainerRef } = useViewportCallbacks({ callbacks, context });
|
|
43
|
+
const containerRef = useCallback((node) => {
|
|
44
|
+
viewportContainerRef(node);
|
|
45
|
+
callbackContainerRef(node);
|
|
46
|
+
}, [viewportContainerRef, callbackContainerRef]);
|
|
47
|
+
const qnaResultId = pia.answers.data?.qna_result_id;
|
|
30
48
|
const renderProps = {
|
|
31
49
|
items: currentItems,
|
|
32
50
|
isLoading,
|
|
@@ -52,6 +70,9 @@ export default function CioPia(props) {
|
|
|
52
70
|
displayedQuestions,
|
|
53
71
|
handleSubmitQuestion,
|
|
54
72
|
handleQuestionClick,
|
|
73
|
+
handleFeedback,
|
|
74
|
+
onResultClick: tracking.trackResultClick,
|
|
75
|
+
qnaResultId,
|
|
55
76
|
containerRef,
|
|
56
77
|
onInputFocus: handleInputFocus,
|
|
57
78
|
};
|
|
@@ -69,6 +90,6 @@ export default function CioPia(props) {
|
|
|
69
90
|
isLoading && React.createElement(LoadingSkeleton, { componentOverride: componentOverrides?.loading }),
|
|
70
91
|
!isLoading && error && React.createElement(ErrorBlock, { message: error?.message || 'Unexpected error' }),
|
|
71
92
|
!isLoading && !error && (React.createElement(React.Fragment, null,
|
|
72
|
-
currentAnswer && (React.createElement(PiaInlineAnswer, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides })),
|
|
93
|
+
currentAnswer && (React.createElement(PiaInlineAnswer, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides, onFeedback: handleFeedback, onResultClick: tracking.trackResultClick, question: currentQuestion, qnaResultId: qnaResultId })),
|
|
73
94
|
React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions }))))));
|
|
74
95
|
}
|
|
@@ -7,10 +7,14 @@ function HtmlDescription({ product }) {
|
|
|
7
7
|
return null;
|
|
8
8
|
return (React.createElement("p", { className: 'cio-product-card-description', dangerouslySetInnerHTML: { __html: sanitizeHtml(description) } }));
|
|
9
9
|
}
|
|
10
|
-
export default function PiaCustomCarousel({ items, componentOverrides, callbacks, }) {
|
|
10
|
+
export default function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, }) {
|
|
11
11
|
const wrapperRef = useRef(null);
|
|
12
12
|
// Determine to use user-defined click handler or default behavior
|
|
13
13
|
const productClickHandler = useCallback((item) => {
|
|
14
|
+
const position = items.findIndex((i) => i.id === item.id);
|
|
15
|
+
if (onResultClick && question) {
|
|
16
|
+
onResultClick(item, position >= 0 ? position : 0, question, qnaResultId);
|
|
17
|
+
}
|
|
14
18
|
const { onProductCardClick } = callbacks || {};
|
|
15
19
|
if (onProductCardClick) {
|
|
16
20
|
onProductCardClick(item);
|
|
@@ -18,7 +22,7 @@ export default function PiaCustomCarousel({ items, componentOverrides, callbacks
|
|
|
18
22
|
else if (item?.url) {
|
|
19
23
|
window.open(item.url, '_blank', 'noopener,noreferrer');
|
|
20
24
|
}
|
|
21
|
-
}, [callbacks]);
|
|
25
|
+
}, [callbacks, items, onResultClick, question, qnaResultId]);
|
|
22
26
|
// Set up event listener for product card clicks
|
|
23
27
|
useEffect(() => {
|
|
24
28
|
const el = wrapperRef.current;
|