@constructor-io/constructorio-ui-pia 2.4.0 → 2.6.3
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 +60 -60
- package/lib/cjs/components/CioPia/CioPia.js +10 -5
- package/lib/cjs/components/Input/Input.js +2 -2
- package/lib/cjs/components/PiaConversation/PiaConversation.js +4 -4
- package/lib/cjs/components/PiaConversation/PiaModal.js +8 -4
- package/lib/cjs/hooks/useAnswerResults.js +2 -4
- package/lib/cjs/hooks/useCioPia.js +5 -1
- package/lib/cjs/hooks/useConversation.js +61 -15
- package/lib/cjs/hooks/useViewportCallbacks.js +50 -0
- package/lib/cjs/stories/assets/storybook-styles.css +89 -0
- package/lib/cjs/utils/contentTransformers.js +8 -2
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/components/CioPia/CioPia.js +10 -5
- package/lib/mjs/components/Input/Input.js +2 -2
- package/lib/mjs/components/PiaConversation/PiaConversation.js +4 -4
- package/lib/mjs/components/PiaConversation/PiaModal.js +8 -4
- package/lib/mjs/hooks/useAnswerResults.js +3 -5
- package/lib/mjs/hooks/useCioPia.js +5 -1
- package/lib/mjs/hooks/useConversation.js +60 -15
- package/lib/mjs/hooks/useViewportCallbacks.js +45 -0
- package/lib/mjs/stories/assets/storybook-styles.css +89 -0
- package/lib/mjs/utils/contentTransformers.js +7 -2
- package/lib/mjs/version.js +1 -1
- package/lib/types/components/Input/Input.d.ts +2 -1
- package/lib/types/components/PiaConversation/PiaConversation.d.ts +4 -1
- package/lib/types/components/PiaConversation/PiaModal.d.ts +4 -1
- package/lib/types/hooks/mocks/MockConstructorIOClient.d.ts +1 -1
- package/lib/types/hooks/useCioPia.d.ts +1 -0
- package/lib/types/hooks/useConversation.d.ts +4 -1
- package/lib/types/hooks/useViewportCallbacks.d.ts +9 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/types.d.ts +18 -2
- package/lib/types/utils/contentTransformers.d.ts +26 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ 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 useViewportCallbacks_1 = tslib_1.__importDefault(require("../../hooks/useViewportCallbacks"));
|
|
10
11
|
const ErrorBlock_1 = tslib_1.__importDefault(require("../Error/ErrorBlock"));
|
|
11
12
|
const LoadingSkeleton_1 = tslib_1.__importDefault(require("../LoadingSkeleton/LoadingSkeleton"));
|
|
12
13
|
const translate_1 = require("../../utils/translate");
|
|
@@ -26,7 +27,8 @@ function CioPia(props) {
|
|
|
26
27
|
suggestedQuestionsParameters,
|
|
27
28
|
formatImageUrl: formatters === null || formatters === void 0 ? void 0 : formatters.formatImageUrl,
|
|
28
29
|
});
|
|
29
|
-
const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, handleSubmitQuestion, resetState, } = (0, useConversation_1.default)({ pia, itemId, isConversation, callbacks });
|
|
30
|
+
const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, context, handleSubmitQuestion, handleQuestionClick, handleInputFocus, resetState, } = (0, useConversation_1.default)({ pia, itemId, isConversation, callbacks });
|
|
31
|
+
const { containerRef } = (0, useViewportCallbacks_1.default)({ callbacks, context });
|
|
30
32
|
const renderProps = {
|
|
31
33
|
items: currentItems,
|
|
32
34
|
isLoading,
|
|
@@ -51,22 +53,25 @@ function CioPia(props) {
|
|
|
51
53
|
componentOverrides,
|
|
52
54
|
displayedQuestions,
|
|
53
55
|
handleSubmitQuestion,
|
|
56
|
+
handleQuestionClick,
|
|
57
|
+
containerRef,
|
|
58
|
+
onInputFocus: handleInputFocus,
|
|
54
59
|
};
|
|
55
60
|
if (type === 'modal') {
|
|
56
|
-
return (react_1.default.createElement(PiaModal_1.default, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onClose: resetState },
|
|
61
|
+
return (react_1.default.createElement(PiaModal_1.default, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, handleQuestionClick: handleQuestionClick, containerRef: containerRef, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onInputFocus: handleInputFocus, onClose: resetState },
|
|
57
62
|
react_1.default.createElement(PiaConversation_1.default, Object.assign({}, conversationHistoryProps))));
|
|
58
63
|
}
|
|
59
64
|
if (isConversation)
|
|
60
65
|
return react_1.default.createElement(PiaConversation_1.default, Object.assign({}, conversationHistoryProps));
|
|
61
66
|
// Default inline mode
|
|
62
|
-
return (react_1.default.createElement("div", { className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
|
|
67
|
+
return (react_1.default.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
|
|
63
68
|
react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { props: renderProps, override: children || (componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.reactNode) },
|
|
64
69
|
react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations)),
|
|
65
|
-
react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, value: currentQuestion, translations: translations }),
|
|
70
|
+
react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, onFocus: handleInputFocus, value: currentQuestion, translations: translations }),
|
|
66
71
|
isLoading && react_1.default.createElement(LoadingSkeleton_1.default, null),
|
|
67
72
|
!isLoading && error && react_1.default.createElement(ErrorBlock_1.default, { message: (error === null || error === void 0 ? void 0 : error.message) || 'Unexpected error' }),
|
|
68
73
|
!isLoading && !error && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
69
74
|
currentAnswer && (react_1.default.createElement(PiaInlineAnswer_1.default, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides })),
|
|
70
|
-
react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick:
|
|
75
|
+
react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions }))))));
|
|
71
76
|
}
|
|
72
77
|
exports.default = CioPia;
|
|
@@ -8,7 +8,7 @@ function SendIcon() {
|
|
|
8
8
|
react_1.default.createElement("g", { id: '.icon-send' },
|
|
9
9
|
react_1.default.createElement("path", { id: 'Vector', d: 'M14.8934 7.09533L14.8884 7.09314L1.54219 1.55752C1.42993 1.51053 1.30778 1.49211 1.18666 1.50388C1.06554 1.51566 0.949225 1.55728 0.848125 1.62502C0.741311 1.69501 0.653573 1.79045 0.592805 1.90277C0.532037 2.01509 0.500145 2.14075 0.5 2.26845V5.80877C0.50006 5.98335 0.561019 6.15243 0.67237 6.28689C0.783722 6.42134 0.938491 6.51274 1.11 6.54533L8.38906 7.89127C8.41767 7.89669 8.44348 7.91193 8.46205 7.93435C8.48062 7.95677 8.49078 7.98497 8.49078 8.01408C8.49078 8.04319 8.48062 8.07139 8.46205 8.09381C8.44348 8.11623 8.41767 8.13147 8.38906 8.13689L1.11031 9.48283C0.938851 9.51533 0.784092 9.60661 0.67269 9.74094C0.561288 9.87528 0.500219 10.0443 0.5 10.2188V13.7597C0.499917 13.8816 0.530111 14.0017 0.587871 14.1091C0.645632 14.2165 0.729152 14.3079 0.830938 14.375C0.953375 14.4564 1.09706 14.4998 1.24406 14.5C1.34626 14.4999 1.4474 14.4794 1.54156 14.4397L14.8875 8.93564L14.8934 8.93283C15.0731 8.85563 15.2262 8.72745 15.3337 8.56415C15.4413 8.40086 15.4986 8.20961 15.4986 8.01408C15.4986 7.81855 15.4413 7.6273 15.3337 7.46401C15.2262 7.30071 15.0731 7.17253 14.8934 7.09533Z', fill: 'white' }))));
|
|
10
10
|
}
|
|
11
|
-
function Input({ value: providedValue, placeholder, disabled = false, onSubmit, translations, }) {
|
|
11
|
+
function Input({ value: providedValue, placeholder, disabled = false, onSubmit, onFocus, translations, }) {
|
|
12
12
|
const [value, setValue] = (0, react_1.useState)(providedValue || '');
|
|
13
13
|
(0, react_1.useEffect)(() => {
|
|
14
14
|
if (providedValue) {
|
|
@@ -32,7 +32,7 @@ function Input({ value: providedValue, placeholder, disabled = false, onSubmit,
|
|
|
32
32
|
? (0, translate_1.translate)('Ask anything', translations)
|
|
33
33
|
: (placeholder !== null && placeholder !== void 0 ? placeholder : (0, translate_1.translate)('Ask anything'));
|
|
34
34
|
return (react_1.default.createElement("div", { className: 'cio-pia-input-container' },
|
|
35
|
-
react_1.default.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
|
|
35
|
+
react_1.default.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, onFocus: onFocus, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
|
|
36
36
|
react_1.default.createElement("button", { type: 'button', onClick: handleSubmit, className: 'cio-pia-send-button', disabled: disabled },
|
|
37
37
|
(0, translate_1.translate)('Send', translations),
|
|
38
38
|
react_1.default.createElement(SendIcon, null))));
|
|
@@ -7,14 +7,14 @@ 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, }) {
|
|
10
|
+
function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, onInputFocus, }) {
|
|
11
11
|
const hasHistory = conversationHistory.length > 0;
|
|
12
|
-
return (react_1.default.createElement("div", { className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
|
|
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
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 }),
|
|
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
|
-
!isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick:
|
|
18
|
-
react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, disabled: isLoading, translations: translations }))));
|
|
17
|
+
!isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
|
|
18
|
+
react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, onFocus: onInputFocus, disabled: isLoading, translations: translations }))));
|
|
19
19
|
}
|
|
20
20
|
exports.default = PiaConversation;
|
|
@@ -10,7 +10,7 @@ function CloseIcon() {
|
|
|
10
10
|
return (react_1.default.createElement("svg", { width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
|
|
11
11
|
react_1.default.createElement("path", { d: 'M15.8334 5.34166L14.6584 4.16666L10.0001 8.82499L5.34175 4.16666L4.16675 5.34166L8.82508 9.99999L4.16675 14.6583L5.34175 15.8333L10.0001 11.175L14.6584 15.8333L15.8334 14.6583L11.1751 9.99999L15.8334 5.34166Z', fill: 'currentColor' })));
|
|
12
12
|
}
|
|
13
|
-
function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, componentOverrides, translations, onClose, children, }) {
|
|
13
|
+
function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, isLoading, componentOverrides, translations, onInputFocus, onClose, children, }) {
|
|
14
14
|
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
15
15
|
const dialogRef = (0, react_1.useRef)(null);
|
|
16
16
|
const openModal = (0, react_1.useCallback)(() => {
|
|
@@ -59,11 +59,15 @@ function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, component
|
|
|
59
59
|
handleSubmitQuestion(question);
|
|
60
60
|
openModal();
|
|
61
61
|
}, [handleSubmitQuestion, openModal]);
|
|
62
|
-
|
|
62
|
+
const handleQuestionClicked = (0, react_1.useCallback)((question) => {
|
|
63
|
+
handleQuestionClick(question);
|
|
64
|
+
openModal();
|
|
65
|
+
}, [handleQuestionClick, openModal]);
|
|
66
|
+
return (react_1.default.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
|
|
63
67
|
react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations)),
|
|
64
68
|
react_1.default.createElement("div", { className: 'cio-pia-conversation-footer' },
|
|
65
|
-
initialQuestions.length > 0 && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: initialQuestions, onQuestionClick:
|
|
66
|
-
react_1.default.createElement(Input_1.default, { onSubmit: handleQuestion, disabled: isLoading || isOpen, translations: translations })),
|
|
69
|
+
initialQuestions.length > 0 && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: initialQuestions, onQuestionClick: handleQuestionClicked, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
|
|
70
|
+
react_1.default.createElement(Input_1.default, { onSubmit: handleQuestion, onFocus: onInputFocus, disabled: isLoading || isOpen, translations: translations })),
|
|
67
71
|
react_1.default.createElement("dialog", { ref: dialogRef, className: 'cio-pia-modal', "aria-labelledby": 'cio-pia-modal-title' },
|
|
68
72
|
react_1.default.createElement("div", { className: 'cio-pia-modal-content' },
|
|
69
73
|
react_1.default.createElement("div", { className: 'cio-pia-modal-header' },
|
|
@@ -28,9 +28,9 @@ const fetchAnswerResults = ({ client, itemId, question, variationId, threadId, }
|
|
|
28
28
|
});
|
|
29
29
|
function useAnswerResults({ itemId, variationId, threadId, cioClient, formatImageUrl, }) {
|
|
30
30
|
const [answerResults, setAnswerResults] = (0, react_1.useState)(null);
|
|
31
|
-
const [items, setItems] = (0, react_1.useState)(null);
|
|
32
31
|
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
33
32
|
const [error, setError] = (0, react_1.useState)(null);
|
|
33
|
+
const items = (0, react_1.useMemo)(() => extractAndTransformItems(answerResults, formatImageUrl), [answerResults, formatImageUrl]);
|
|
34
34
|
const fetchResult = (0, react_1.useCallback)((question) => {
|
|
35
35
|
if (!cioClient)
|
|
36
36
|
return;
|
|
@@ -39,18 +39,16 @@ function useAnswerResults({ itemId, variationId, threadId, cioClient, formatImag
|
|
|
39
39
|
fetchAnswerResults({ client: cioClient, itemId, question, variationId, threadId })
|
|
40
40
|
.then((fetchedAnswerResults) => {
|
|
41
41
|
setAnswerResults(fetchedAnswerResults);
|
|
42
|
-
setItems(extractAndTransformItems(fetchedAnswerResults, formatImageUrl));
|
|
43
42
|
setError(null);
|
|
44
43
|
})
|
|
45
44
|
.catch((err) => {
|
|
46
45
|
setError(err instanceof Error ? err : new Error('Error fetching answer'));
|
|
47
46
|
setAnswerResults(null);
|
|
48
|
-
setItems(null);
|
|
49
47
|
})
|
|
50
48
|
.finally(() => {
|
|
51
49
|
setIsLoading(false);
|
|
52
50
|
});
|
|
53
|
-
}, [cioClient, itemId, variationId, threadId
|
|
51
|
+
}, [cioClient, itemId, variationId, threadId]);
|
|
54
52
|
return {
|
|
55
53
|
data: answerResults,
|
|
56
54
|
items,
|
|
@@ -1,11 +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 = require("react");
|
|
4
5
|
const useAnswerResults_1 = tslib_1.__importDefault(require("./useAnswerResults"));
|
|
5
6
|
const useCioClient_1 = tslib_1.__importDefault(require("./useCioClient"));
|
|
6
7
|
const useSuggestedQuestions_1 = tslib_1.__importDefault(require("./useSuggestedQuestions"));
|
|
7
8
|
function useCioPia(props) {
|
|
8
|
-
const { apiKey, itemId, variationId, threadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
|
|
9
|
+
const { apiKey, itemId, variationId, threadId: providedThreadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
|
|
10
|
+
const [generatedThreadId] = (0, react_1.useState)(() => crypto.randomUUID());
|
|
11
|
+
const threadId = providedThreadId || generatedThreadId;
|
|
9
12
|
const defaultClient = (0, useCioClient_1.default)({ apiKey });
|
|
10
13
|
const client = providedClient || defaultClient;
|
|
11
14
|
const suggestedQuestions = (0, useSuggestedQuestions_1.default)({
|
|
@@ -23,6 +26,7 @@ function useCioPia(props) {
|
|
|
23
26
|
formatImageUrl,
|
|
24
27
|
});
|
|
25
28
|
return {
|
|
29
|
+
threadId,
|
|
26
30
|
suggestedQuestions,
|
|
27
31
|
answers,
|
|
28
32
|
};
|
|
@@ -3,24 +3,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const react_1 = require("react");
|
|
4
4
|
function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
5
5
|
var _a, _b, _c, _d;
|
|
6
|
-
const { suggestedQuestions, answers } = pia;
|
|
6
|
+
const { suggestedQuestions, answers, threadId } = pia;
|
|
7
7
|
const { getAnswer } = answers;
|
|
8
|
+
const context = (0, react_1.useMemo)(() => ({ itemId, threadId }), [itemId, threadId]);
|
|
8
9
|
const [currentQuestion, setCurrentQuestion] = (0, react_1.useState)('');
|
|
9
10
|
const [displayedQuestions, setDisplayedQuestions] = (0, react_1.useState)([]);
|
|
10
11
|
const [conversationHistory, setConversationHistory] = (0, react_1.useState)([]);
|
|
11
12
|
const entryIdRef = (0, react_1.useRef)(0);
|
|
12
13
|
const prevAnswerValueRef = (0, react_1.useRef)((_a = answers.data) === null || _a === void 0 ? void 0 : _a.value);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const callbacksRef = (0, react_1.useRef)(callbacks);
|
|
15
|
+
const contextRef = (0, react_1.useRef)(context);
|
|
16
|
+
const lastQuestionRef = (0, react_1.useRef)('');
|
|
17
|
+
const lastSourceRef = (0, react_1.useRef)('user');
|
|
18
|
+
(0, react_1.useEffect)(() => {
|
|
19
|
+
callbacksRef.current = callbacks;
|
|
20
|
+
}, [callbacks]);
|
|
21
|
+
(0, react_1.useEffect)(() => {
|
|
22
|
+
contextRef.current = context;
|
|
23
|
+
}, [context]);
|
|
24
|
+
const submitQuestion = (0, react_1.useCallback)((question, source) => {
|
|
25
|
+
lastSourceRef.current = source;
|
|
26
|
+
lastQuestionRef.current = question;
|
|
16
27
|
setCurrentQuestion(question);
|
|
17
28
|
getAnswer(question);
|
|
18
29
|
if (isConversation) {
|
|
19
30
|
entryIdRef.current += 1;
|
|
20
31
|
const id = entryIdRef.current;
|
|
21
|
-
setConversationHistory((prev) => [...prev, { id, question, answer: '' }]);
|
|
32
|
+
setConversationHistory((prev) => [...prev, { id, question, answer: '', source }]);
|
|
22
33
|
}
|
|
23
|
-
}, [getAnswer, isConversation
|
|
34
|
+
}, [getAnswer, isConversation]);
|
|
35
|
+
const handleSubmitQuestion = (0, react_1.useCallback)((question) => {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
(_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onQuestionSubmit) === null || _b === void 0 ? void 0 : _b.call(_a, question, contextRef.current, 'user');
|
|
38
|
+
submitQuestion(question, 'user');
|
|
39
|
+
}, [submitQuestion]);
|
|
40
|
+
const handleQuestionClick = (0, react_1.useCallback)((question) => {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
(_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onQuestionSubmit) === null || _b === void 0 ? void 0 : _b.call(_a, question, contextRef.current, 'suggestion');
|
|
43
|
+
submitQuestion(question, 'suggestion');
|
|
44
|
+
}, [submitQuestion]);
|
|
45
|
+
const handleInputFocus = (0, react_1.useCallback)(() => {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
(_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, contextRef.current);
|
|
48
|
+
}, []);
|
|
24
49
|
const resetState = (0, react_1.useCallback)(() => {
|
|
25
50
|
setCurrentQuestion('');
|
|
26
51
|
setDisplayedQuestions(suggestedQuestions.data);
|
|
@@ -42,20 +67,38 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
42
67
|
setDisplayedQuestions(answers.data.follow_up_questions);
|
|
43
68
|
}, [answers.data]);
|
|
44
69
|
(0, react_1.useEffect)(() => {
|
|
45
|
-
var _a, _b;
|
|
70
|
+
var _a, _b, _c, _d, _e, _f;
|
|
46
71
|
const answerValue = (_b = (_a = answers.data) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
|
|
47
|
-
if (!
|
|
72
|
+
if (!answerValue)
|
|
48
73
|
return;
|
|
49
74
|
if (answerValue === prevAnswerValueRef.current)
|
|
50
75
|
return;
|
|
51
76
|
prevAnswerValueRef.current = answerValue;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
77
|
+
const answerThreadId = (_c = answers.data) === null || _c === void 0 ? void 0 : _c.thread_id;
|
|
78
|
+
const qnaResultId = (_d = answers.data) === null || _d === void 0 ? void 0 : _d.qna_result_id;
|
|
79
|
+
if (isConversation) {
|
|
80
|
+
setConversationHistory((prev) => {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
if (prev.length === 0)
|
|
83
|
+
return prev;
|
|
84
|
+
const updated = [...prev];
|
|
85
|
+
updated[updated.length - 1] = Object.assign(Object.assign({}, updated[updated.length - 1]), { answer: answerValue, items: answers.items, threadId: answerThreadId, qnaResultId });
|
|
86
|
+
(_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onAnswer) === null || _b === void 0 ? void 0 : _b.call(_a, updated, contextRef.current);
|
|
87
|
+
return updated;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const entry = {
|
|
92
|
+
id: entryIdRef.current,
|
|
93
|
+
question: lastQuestionRef.current,
|
|
94
|
+
answer: answerValue,
|
|
95
|
+
source: lastSourceRef.current,
|
|
96
|
+
items: answers.items,
|
|
97
|
+
threadId: answerThreadId,
|
|
98
|
+
qnaResultId,
|
|
99
|
+
};
|
|
100
|
+
(_f = (_e = callbacksRef.current) === null || _e === void 0 ? void 0 : _e.onAnswer) === null || _f === void 0 ? void 0 : _f.call(_e, [entry], contextRef.current);
|
|
101
|
+
}
|
|
59
102
|
}, [isConversation, answers.data, answers.items]);
|
|
60
103
|
const currentAnswer = (_c = (_b = answers.data) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : '';
|
|
61
104
|
const currentItems = (_d = answers.items) !== null && _d !== void 0 ? _d : null;
|
|
@@ -69,7 +112,10 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
|
69
112
|
currentItems,
|
|
70
113
|
isLoading,
|
|
71
114
|
error,
|
|
115
|
+
context,
|
|
72
116
|
handleSubmitQuestion,
|
|
117
|
+
handleQuestionClick,
|
|
118
|
+
handleInputFocus,
|
|
73
119
|
resetState,
|
|
74
120
|
};
|
|
75
121
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const react_1 = require("react");
|
|
4
|
+
function useViewportCallbacks({ callbacks, context, }) {
|
|
5
|
+
const callbacksRef = (0, react_1.useRef)(callbacks);
|
|
6
|
+
const contextRef = (0, react_1.useRef)(context);
|
|
7
|
+
const hasBeenVisibleRef = (0, react_1.useRef)(false);
|
|
8
|
+
const hasFiredOutOfViewRef = (0, react_1.useRef)(false);
|
|
9
|
+
const observerRef = (0, react_1.useRef)(null);
|
|
10
|
+
(0, react_1.useEffect)(() => {
|
|
11
|
+
callbacksRef.current = callbacks;
|
|
12
|
+
}, [callbacks]);
|
|
13
|
+
(0, react_1.useEffect)(() => {
|
|
14
|
+
contextRef.current = context;
|
|
15
|
+
}, [context]);
|
|
16
|
+
(0, react_1.useEffect)(() => {
|
|
17
|
+
return () => {
|
|
18
|
+
var _a;
|
|
19
|
+
(_a = observerRef.current) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
20
|
+
};
|
|
21
|
+
}, []);
|
|
22
|
+
const containerRef = (0, react_1.useCallback)((node) => {
|
|
23
|
+
if (observerRef.current) {
|
|
24
|
+
observerRef.current.disconnect();
|
|
25
|
+
observerRef.current = null;
|
|
26
|
+
}
|
|
27
|
+
if (!node)
|
|
28
|
+
return;
|
|
29
|
+
hasBeenVisibleRef.current = false;
|
|
30
|
+
hasFiredOutOfViewRef.current = false;
|
|
31
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
32
|
+
var _a, _b, _c, _d;
|
|
33
|
+
if (entry.isIntersecting && !hasBeenVisibleRef.current) {
|
|
34
|
+
hasBeenVisibleRef.current = true;
|
|
35
|
+
(_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onView) === null || _b === void 0 ? void 0 : _b.call(_a, contextRef.current);
|
|
36
|
+
}
|
|
37
|
+
else if (!entry.isIntersecting &&
|
|
38
|
+
hasBeenVisibleRef.current &&
|
|
39
|
+
!hasFiredOutOfViewRef.current) {
|
|
40
|
+
hasFiredOutOfViewRef.current = true;
|
|
41
|
+
(_d = (_c = callbacksRef.current) === null || _c === void 0 ? void 0 : _c.onOutOfView) === null || _d === void 0 ? void 0 : _d.call(_c, contextRef.current);
|
|
42
|
+
observer.disconnect();
|
|
43
|
+
}
|
|
44
|
+
}, { threshold: 0.5 });
|
|
45
|
+
observer.observe(node);
|
|
46
|
+
observerRef.current = observer;
|
|
47
|
+
}, []);
|
|
48
|
+
return { containerRef };
|
|
49
|
+
}
|
|
50
|
+
exports.default = useViewportCallbacks;
|
|
@@ -110,3 +110,92 @@ div.badge-wrapper code {
|
|
|
110
110
|
background: #d8e8fd;
|
|
111
111
|
color: #3c70bf;
|
|
112
112
|
}
|
|
113
|
+
|
|
114
|
+
.cio-flow-diagram {
|
|
115
|
+
display: flex;
|
|
116
|
+
flex-direction: column;
|
|
117
|
+
gap: 4px;
|
|
118
|
+
margin: 24px 0 0;
|
|
119
|
+
font-family: system-ui, sans-serif;
|
|
120
|
+
font-size: 14px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.cio-flow-diagram .flow-step {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: 12px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.cio-flow-diagram .flow-box {
|
|
130
|
+
padding: 10px 16px;
|
|
131
|
+
border-radius: 8px;
|
|
132
|
+
min-width: 220px;
|
|
133
|
+
text-align: center;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.cio-flow-diagram .flow-box--consumer {
|
|
137
|
+
background: #eff6ff;
|
|
138
|
+
border: 1px solid #bfdbfe;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.cio-flow-diagram .flow-box--internal {
|
|
142
|
+
background: #f5f3ff;
|
|
143
|
+
border: 1px solid #ddd6fe;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.cio-flow-diagram .flow-box--output {
|
|
147
|
+
background: #f0fdf4;
|
|
148
|
+
border: 1px solid #bbf7d0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.cio-flow-diagram .flow-arrow {
|
|
152
|
+
margin-left: 110px;
|
|
153
|
+
color: #9ca3af;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.cio-flow-diagram .flow-label {
|
|
157
|
+
font-size: 12px;
|
|
158
|
+
color: #9ca3af;
|
|
159
|
+
font-style: italic;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.cio-flow-diagram .flow-callback {
|
|
163
|
+
font-size: 12px;
|
|
164
|
+
color: #059669;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.cio-flow-diagram .flow-box-subtitle {
|
|
168
|
+
font-size: 12px;
|
|
169
|
+
color: #6b7280;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.cio-flow-legend {
|
|
173
|
+
display: flex;
|
|
174
|
+
gap: 16px;
|
|
175
|
+
margin: 32px 0 16px;
|
|
176
|
+
font-size: 12px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.cio-flow-legend .legend-swatch {
|
|
180
|
+
display: inline-block;
|
|
181
|
+
width: 12px;
|
|
182
|
+
height: 12px;
|
|
183
|
+
border-radius: 3px;
|
|
184
|
+
margin-right: 4px;
|
|
185
|
+
vertical-align: middle;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.cio-flow-legend .legend-swatch--consumer {
|
|
189
|
+
background: #eff6ff;
|
|
190
|
+
border: 1px solid #bfdbfe;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.cio-flow-legend .legend-swatch--internal {
|
|
194
|
+
background: #f5f3ff;
|
|
195
|
+
border: 1px solid #ddd6fe;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.cio-flow-legend .legend-swatch--output {
|
|
199
|
+
background: #f0fdf4;
|
|
200
|
+
border: 1px solid #bbf7d0;
|
|
201
|
+
}
|
|
@@ -13,10 +13,16 @@ function sanitizeHtml(html) {
|
|
|
13
13
|
return dompurify_1.default.sanitize(html, purifyConfig);
|
|
14
14
|
}
|
|
15
15
|
exports.sanitizeHtml = sanitizeHtml;
|
|
16
|
-
function renderMarkdown(content) {
|
|
16
|
+
function renderMarkdown(content, options) {
|
|
17
|
+
var _a;
|
|
17
18
|
if (!content)
|
|
18
19
|
return '';
|
|
19
|
-
const html = marked_1.marked.parse(content, { async: false });
|
|
20
|
+
const html = marked_1.marked.parse(content, { async: false, breaks: true });
|
|
21
|
+
if (options === null || options === void 0 ? void 0 : options.sanitize) {
|
|
22
|
+
const purifier = (0, dompurify_1.default)(window);
|
|
23
|
+
const config = Object.assign(Object.assign({}, purifyConfig), { FORBID_TAGS: [...((_a = purifyConfig.FORBID_TAGS) !== null && _a !== void 0 ? _a : [])] });
|
|
24
|
+
return options.sanitize(purifier, html, { config });
|
|
25
|
+
}
|
|
20
26
|
return dompurify_1.default.sanitize(html, purifyConfig);
|
|
21
27
|
}
|
|
22
28
|
exports.renderMarkdown = renderMarkdown;
|
package/lib/cjs/version.js
CHANGED
|
@@ -4,6 +4,7 @@ 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 useViewportCallbacks from '../../hooks/useViewportCallbacks';
|
|
7
8
|
import ErrorBlock from '../Error/ErrorBlock';
|
|
8
9
|
import LoadingSkeleton from '../LoadingSkeleton/LoadingSkeleton';
|
|
9
10
|
import { translate } from '../../utils/translate';
|
|
@@ -23,7 +24,8 @@ export default function CioPia(props) {
|
|
|
23
24
|
suggestedQuestionsParameters,
|
|
24
25
|
formatImageUrl: formatters?.formatImageUrl,
|
|
25
26
|
});
|
|
26
|
-
const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, handleSubmitQuestion, resetState, } = useConversation({ pia, itemId, isConversation, callbacks });
|
|
27
|
+
const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, context, handleSubmitQuestion, handleQuestionClick, handleInputFocus, resetState, } = useConversation({ pia, itemId, isConversation, callbacks });
|
|
28
|
+
const { containerRef } = useViewportCallbacks({ callbacks, context });
|
|
27
29
|
const renderProps = {
|
|
28
30
|
items: currentItems,
|
|
29
31
|
isLoading,
|
|
@@ -48,21 +50,24 @@ export default function CioPia(props) {
|
|
|
48
50
|
componentOverrides,
|
|
49
51
|
displayedQuestions,
|
|
50
52
|
handleSubmitQuestion,
|
|
53
|
+
handleQuestionClick,
|
|
54
|
+
containerRef,
|
|
55
|
+
onInputFocus: handleInputFocus,
|
|
51
56
|
};
|
|
52
57
|
if (type === 'modal') {
|
|
53
|
-
return (React.createElement(PiaModal, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onClose: resetState },
|
|
58
|
+
return (React.createElement(PiaModal, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, handleQuestionClick: handleQuestionClick, containerRef: containerRef, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onInputFocus: handleInputFocus, onClose: resetState },
|
|
54
59
|
React.createElement(PiaConversation, { ...conversationHistoryProps })));
|
|
55
60
|
}
|
|
56
61
|
if (isConversation)
|
|
57
62
|
return React.createElement(PiaConversation, { ...conversationHistoryProps });
|
|
58
63
|
// Default inline mode
|
|
59
|
-
return (React.createElement("div", { className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
|
|
64
|
+
return (React.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
|
|
60
65
|
React.createElement(RenderPropsWrapper, { props: renderProps, override: children || componentOverrides?.reactNode },
|
|
61
66
|
React.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, translate('Any questions about this product?', translations)),
|
|
62
|
-
React.createElement(Input, { onSubmit: handleSubmitQuestion, value: currentQuestion, translations: translations }),
|
|
67
|
+
React.createElement(Input, { onSubmit: handleSubmitQuestion, onFocus: handleInputFocus, value: currentQuestion, translations: translations }),
|
|
63
68
|
isLoading && React.createElement(LoadingSkeleton, null),
|
|
64
69
|
!isLoading && error && React.createElement(ErrorBlock, { message: error?.message || 'Unexpected error' }),
|
|
65
70
|
!isLoading && !error && (React.createElement(React.Fragment, null,
|
|
66
71
|
currentAnswer && (React.createElement(PiaInlineAnswer, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides })),
|
|
67
|
-
React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick:
|
|
72
|
+
React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions }))))));
|
|
68
73
|
}
|
|
@@ -5,7 +5,7 @@ function SendIcon() {
|
|
|
5
5
|
React.createElement("g", { id: '.icon-send' },
|
|
6
6
|
React.createElement("path", { id: 'Vector', d: 'M14.8934 7.09533L14.8884 7.09314L1.54219 1.55752C1.42993 1.51053 1.30778 1.49211 1.18666 1.50388C1.06554 1.51566 0.949225 1.55728 0.848125 1.62502C0.741311 1.69501 0.653573 1.79045 0.592805 1.90277C0.532037 2.01509 0.500145 2.14075 0.5 2.26845V5.80877C0.50006 5.98335 0.561019 6.15243 0.67237 6.28689C0.783722 6.42134 0.938491 6.51274 1.11 6.54533L8.38906 7.89127C8.41767 7.89669 8.44348 7.91193 8.46205 7.93435C8.48062 7.95677 8.49078 7.98497 8.49078 8.01408C8.49078 8.04319 8.48062 8.07139 8.46205 8.09381C8.44348 8.11623 8.41767 8.13147 8.38906 8.13689L1.11031 9.48283C0.938851 9.51533 0.784092 9.60661 0.67269 9.74094C0.561288 9.87528 0.500219 10.0443 0.5 10.2188V13.7597C0.499917 13.8816 0.530111 14.0017 0.587871 14.1091C0.645632 14.2165 0.729152 14.3079 0.830938 14.375C0.953375 14.4564 1.09706 14.4998 1.24406 14.5C1.34626 14.4999 1.4474 14.4794 1.54156 14.4397L14.8875 8.93564L14.8934 8.93283C15.0731 8.85563 15.2262 8.72745 15.3337 8.56415C15.4413 8.40086 15.4986 8.20961 15.4986 8.01408C15.4986 7.81855 15.4413 7.6273 15.3337 7.46401C15.2262 7.30071 15.0731 7.17253 14.8934 7.09533Z', fill: 'white' }))));
|
|
7
7
|
}
|
|
8
|
-
function Input({ value: providedValue, placeholder, disabled = false, onSubmit, translations, }) {
|
|
8
|
+
function Input({ value: providedValue, placeholder, disabled = false, onSubmit, onFocus, translations, }) {
|
|
9
9
|
const [value, setValue] = useState(providedValue || '');
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
if (providedValue) {
|
|
@@ -29,7 +29,7 @@ function Input({ value: providedValue, placeholder, disabled = false, onSubmit,
|
|
|
29
29
|
? translate('Ask anything', translations)
|
|
30
30
|
: (placeholder ?? translate('Ask anything'));
|
|
31
31
|
return (React.createElement("div", { className: 'cio-pia-input-container' },
|
|
32
|
-
React.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
|
|
32
|
+
React.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, onFocus: onFocus, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
|
|
33
33
|
React.createElement("button", { type: 'button', onClick: handleSubmit, className: 'cio-pia-send-button', disabled: disabled },
|
|
34
34
|
translate('Send', translations),
|
|
35
35
|
React.createElement(SendIcon, null))));
|
|
@@ -4,13 +4,13 @@ import SuggestedQuestionsContainer from '../SuggestedQuestionsContainer/Suggeste
|
|
|
4
4
|
import SuggestedQuestionsSkeleton from '../SuggestedQuestionsContainer/SuggestedQuestionsSkeleton';
|
|
5
5
|
import { translate } from '../../utils/translate';
|
|
6
6
|
import ConversationHistory from '../ConversationHistory/ConversationHistory';
|
|
7
|
-
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, }) {
|
|
7
|
+
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, onInputFocus, }) {
|
|
8
8
|
const hasHistory = conversationHistory.length > 0;
|
|
9
|
-
return (React.createElement("div", { className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
|
|
9
|
+
return (React.createElement("div", { ref: containerRef, className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
|
|
10
10
|
!hasHistory && (React.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, translate('Any questions about this product?', translations))),
|
|
11
11
|
React.createElement(ConversationHistory, { conversationHistory: conversationHistory, isLoading: isLoading, error: error, currentItems: currentItems, showFeedback: showFeedback, showPreviousItems: showPreviousItems, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides }),
|
|
12
12
|
React.createElement("div", { className: 'cio-pia-conversation-footer' },
|
|
13
13
|
isLoading && !error && React.createElement(SuggestedQuestionsSkeleton, null),
|
|
14
|
-
!isLoading && !error && (React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick:
|
|
15
|
-
React.createElement(Input, { onSubmit: handleSubmitQuestion, disabled: isLoading, translations: translations }))));
|
|
14
|
+
!isLoading && !error && (React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions })),
|
|
15
|
+
React.createElement(Input, { onSubmit: handleSubmitQuestion, onFocus: onInputFocus, disabled: isLoading, translations: translations }))));
|
|
16
16
|
}
|
|
@@ -7,7 +7,7 @@ function CloseIcon() {
|
|
|
7
7
|
return (React.createElement("svg", { width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
|
|
8
8
|
React.createElement("path", { d: 'M15.8334 5.34166L14.6584 4.16666L10.0001 8.82499L5.34175 4.16666L4.16675 5.34166L8.82508 9.99999L4.16675 14.6583L5.34175 15.8333L10.0001 11.175L14.6584 15.8333L15.8334 14.6583L11.1751 9.99999L15.8334 5.34166Z', fill: 'currentColor' })));
|
|
9
9
|
}
|
|
10
|
-
export default function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, componentOverrides, translations, onClose, children, }) {
|
|
10
|
+
export default function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, isLoading, componentOverrides, translations, onInputFocus, onClose, children, }) {
|
|
11
11
|
const [isOpen, setIsOpen] = useState(false);
|
|
12
12
|
const dialogRef = useRef(null);
|
|
13
13
|
const openModal = useCallback(() => {
|
|
@@ -56,11 +56,15 @@ export default function PiaModal({ initialQuestions, handleSubmitQuestion, isLoa
|
|
|
56
56
|
handleSubmitQuestion(question);
|
|
57
57
|
openModal();
|
|
58
58
|
}, [handleSubmitQuestion, openModal]);
|
|
59
|
-
|
|
59
|
+
const handleQuestionClicked = useCallback((question) => {
|
|
60
|
+
handleQuestionClick(question);
|
|
61
|
+
openModal();
|
|
62
|
+
}, [handleQuestionClick, openModal]);
|
|
63
|
+
return (React.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
|
|
60
64
|
React.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, translate('Any questions about this product?', translations)),
|
|
61
65
|
React.createElement("div", { className: 'cio-pia-conversation-footer' },
|
|
62
|
-
initialQuestions.length > 0 && (React.createElement(SuggestedQuestionsContainer, { questions: initialQuestions, onQuestionClick:
|
|
63
|
-
React.createElement(Input, { onSubmit: handleQuestion, disabled: isLoading || isOpen, translations: translations })),
|
|
66
|
+
initialQuestions.length > 0 && (React.createElement(SuggestedQuestionsContainer, { questions: initialQuestions, onQuestionClick: handleQuestionClicked, componentOverride: componentOverrides?.suggestedQuestions })),
|
|
67
|
+
React.createElement(Input, { onSubmit: handleQuestion, onFocus: onInputFocus, disabled: isLoading || isOpen, translations: translations })),
|
|
64
68
|
React.createElement("dialog", { ref: dialogRef, className: 'cio-pia-modal', "aria-labelledby": 'cio-pia-modal-title' },
|
|
65
69
|
React.createElement("div", { className: 'cio-pia-modal-content' },
|
|
66
70
|
React.createElement("div", { className: 'cio-pia-modal-header' },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useState } from 'react';
|
|
1
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
2
2
|
import { transformResultItem } from '../utils/transformers';
|
|
3
3
|
const extractAndTransformItems = (data, formatImageUrl) => {
|
|
4
4
|
if (!data?.item_results?.response?.results) {
|
|
@@ -24,9 +24,9 @@ const fetchAnswerResults = async ({ client, itemId, question, variationId, threa
|
|
|
24
24
|
};
|
|
25
25
|
export default function useAnswerResults({ itemId, variationId, threadId, cioClient, formatImageUrl, }) {
|
|
26
26
|
const [answerResults, setAnswerResults] = useState(null);
|
|
27
|
-
const [items, setItems] = useState(null);
|
|
28
27
|
const [isLoading, setIsLoading] = useState(false);
|
|
29
28
|
const [error, setError] = useState(null);
|
|
29
|
+
const items = useMemo(() => extractAndTransformItems(answerResults, formatImageUrl), [answerResults, formatImageUrl]);
|
|
30
30
|
const fetchResult = useCallback((question) => {
|
|
31
31
|
if (!cioClient)
|
|
32
32
|
return;
|
|
@@ -35,18 +35,16 @@ export default function useAnswerResults({ itemId, variationId, threadId, cioCli
|
|
|
35
35
|
fetchAnswerResults({ client: cioClient, itemId, question, variationId, threadId })
|
|
36
36
|
.then((fetchedAnswerResults) => {
|
|
37
37
|
setAnswerResults(fetchedAnswerResults);
|
|
38
|
-
setItems(extractAndTransformItems(fetchedAnswerResults, formatImageUrl));
|
|
39
38
|
setError(null);
|
|
40
39
|
})
|
|
41
40
|
.catch((err) => {
|
|
42
41
|
setError(err instanceof Error ? err : new Error('Error fetching answer'));
|
|
43
42
|
setAnswerResults(null);
|
|
44
|
-
setItems(null);
|
|
45
43
|
})
|
|
46
44
|
.finally(() => {
|
|
47
45
|
setIsLoading(false);
|
|
48
46
|
});
|
|
49
|
-
}, [cioClient, itemId, variationId, threadId
|
|
47
|
+
}, [cioClient, itemId, variationId, threadId]);
|
|
50
48
|
return {
|
|
51
49
|
data: answerResults,
|
|
52
50
|
items,
|