@constructor-io/constructorio-ui-pia 2.9.0 → 2.10.1
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/README.md +1 -0
- package/dist/constructorio-ui-pia-bundled.js +51 -51
- package/lib/cjs/components/CioPia/CioPia.js +4 -2
- package/lib/cjs/components/CioPia/PiaCustomCarousel.js +51 -6
- package/lib/cjs/components/ConversationHistory/ConversationHistory.js +2 -2
- package/lib/cjs/components/PiaConversation/PiaConversation.js +2 -2
- package/lib/cjs/components/PiaInlineAnswer/PiaInlineAnswer.js +2 -2
- package/lib/cjs/hooks/mocks/MockConstructorIOClient.js +8 -3
- package/lib/cjs/utils/translate.js +1 -0
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/components/CioPia/CioPia.js +4 -2
- package/lib/mjs/components/CioPia/PiaCustomCarousel.js +66 -12
- package/lib/mjs/components/ConversationHistory/ConversationHistory.js +2 -2
- package/lib/mjs/components/PiaConversation/PiaConversation.js +2 -2
- package/lib/mjs/components/PiaInlineAnswer/PiaInlineAnswer.js +2 -2
- package/lib/mjs/hooks/mocks/MockConstructorIOClient.js +9 -9
- package/lib/mjs/utils/translate.js +1 -0
- package/lib/mjs/version.js +1 -1
- package/lib/types/components/CioPia/CioPia.d.ts +3 -1
- package/lib/types/components/CioPia/PiaCustomCarousel.d.ts +4 -2
- package/lib/types/components/ConversationHistory/ConversationHistory.d.ts +2 -1
- package/lib/types/components/PiaConversation/PiaConversation.d.ts +1 -1
- package/lib/types/components/PiaInlineAnswer/PiaInlineAnswer.d.ts +2 -1
- package/lib/types/types.d.ts +15 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +4 -2
|
@@ -19,9 +19,10 @@ const PiaConversation_1 = tslib_1.__importDefault(require("../PiaConversation/Pi
|
|
|
19
19
|
// eslint-disable-next-line complexity
|
|
20
20
|
function CioPia(props) {
|
|
21
21
|
var _a;
|
|
22
|
-
const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, children, translations, suggestedQuestionsParameters, } = props;
|
|
22
|
+
const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, productCardProps, children, translations, suggestedQuestionsParameters, } = props;
|
|
23
23
|
const { learnMoreUrl, showFeedback, mode = 'default', type = 'inline', showPreviousItems, disclaimerPosition = 'bottom', } = displayConfigs || {};
|
|
24
24
|
const isConversation = mode === 'conversation' || type === 'modal';
|
|
25
|
+
const { priceCurrency } = productCardProps || {};
|
|
25
26
|
const pia = (0, useCioPia_1.default)({
|
|
26
27
|
apiKey,
|
|
27
28
|
itemId,
|
|
@@ -79,6 +80,7 @@ function CioPia(props) {
|
|
|
79
80
|
qnaResultId,
|
|
80
81
|
containerRef,
|
|
81
82
|
onInputFocus: handleInputFocus,
|
|
83
|
+
priceCurrency,
|
|
82
84
|
};
|
|
83
85
|
if (type === 'modal') {
|
|
84
86
|
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 },
|
|
@@ -94,7 +96,7 @@ function CioPia(props) {
|
|
|
94
96
|
isLoading && react_1.default.createElement(LoadingSkeleton_1.default, { componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.loading }),
|
|
95
97
|
!isLoading && error && react_1.default.createElement(ErrorBlock_1.default, { message: (error === null || error === void 0 ? void 0 : error.message) || 'Unexpected error' }),
|
|
96
98
|
!isLoading && !error && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
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 })),
|
|
99
|
+
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, priceCurrency: priceCurrency })),
|
|
98
100
|
react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions }))))));
|
|
99
101
|
}
|
|
100
102
|
exports.default = CioPia;
|
|
@@ -4,14 +4,53 @@ const tslib_1 = require("tslib");
|
|
|
4
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 contentTransformers_1 = require("../../utils/contentTransformers");
|
|
7
|
+
const translate_1 = require("../../utils/translate");
|
|
7
8
|
function HtmlDescription({ product }) {
|
|
8
9
|
const { description } = product;
|
|
9
10
|
if (!description)
|
|
10
11
|
return null;
|
|
11
12
|
return (react_1.default.createElement("p", { className: 'cio-product-card-description', dangerouslySetInnerHTML: { __html: (0, contentTransformers_1.sanitizeHtml)(description) } }));
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
+
function createPriceSectionOverride(priceCurrency) {
|
|
15
|
+
return function PriceSectionOverride({ product }) {
|
|
16
|
+
const { price, salePrice } = product;
|
|
17
|
+
if (price == null)
|
|
18
|
+
return null;
|
|
19
|
+
return (react_1.default.createElement("div", { className: 'cio-product-card-price-section flex items-baseline gap-2' },
|
|
20
|
+
react_1.default.createElement("span", { className: 'text-lg font-bold' },
|
|
21
|
+
priceCurrency,
|
|
22
|
+
"\u00A0", salePrice !== null && salePrice !== void 0 ? salePrice : price),
|
|
23
|
+
salePrice != null && (react_1.default.createElement("span", { className: 'text-sm text-gray-400 line-through' },
|
|
24
|
+
priceCurrency,
|
|
25
|
+
"\u00A0",
|
|
26
|
+
price))));
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function getContentDefaults(content, priceSectionOverride) {
|
|
30
|
+
const defaults = {};
|
|
31
|
+
if (!(content === null || content === void 0 ? void 0 : content.description)) {
|
|
32
|
+
defaults.description = { reactNode: HtmlDescription };
|
|
33
|
+
}
|
|
34
|
+
if (!(content === null || content === void 0 ? void 0 : content.price) && priceSectionOverride) {
|
|
35
|
+
defaults.price = { reactNode: priceSectionOverride };
|
|
36
|
+
}
|
|
37
|
+
return defaults;
|
|
38
|
+
}
|
|
39
|
+
function buildMergedOverrides(componentOverrides, priceSectionOverride) {
|
|
40
|
+
var _a, _b, _c;
|
|
41
|
+
const content = (_b = (_a = componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.item) === null || _a === void 0 ? void 0 : _a.productCard) === null || _b === void 0 ? void 0 : _b.content;
|
|
42
|
+
const defaults = getContentDefaults(content, priceSectionOverride);
|
|
43
|
+
if (Object.keys(defaults).length === 0) {
|
|
44
|
+
return componentOverrides || {};
|
|
45
|
+
}
|
|
46
|
+
return Object.assign(Object.assign({}, componentOverrides), { item: Object.assign(Object.assign({}, componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.item), { productCard: Object.assign(Object.assign({}, (_c = componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.item) === null || _c === void 0 ? void 0 : _c.productCard), { content: Object.assign(Object.assign({}, content), defaults) }) }) });
|
|
47
|
+
}
|
|
48
|
+
function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, translations, priceCurrency, }) {
|
|
14
49
|
const wrapperRef = (0, react_1.useRef)(null);
|
|
50
|
+
const { onAddToCart } = callbacks || {};
|
|
51
|
+
const addToCartHandler = (0, react_1.useCallback)((event, product) => {
|
|
52
|
+
onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product, event);
|
|
53
|
+
}, [onAddToCart]);
|
|
15
54
|
// Determine to use user-defined click handler or default behavior
|
|
16
55
|
const productClickHandler = (0, react_1.useCallback)((item) => {
|
|
17
56
|
const position = items.findIndex((i) => i.id === item.id);
|
|
@@ -42,13 +81,19 @@ function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick
|
|
|
42
81
|
el.removeEventListener(constructorio_ui_components_1.CIO_EVENTS.productCard.click, handleClick);
|
|
43
82
|
};
|
|
44
83
|
}, [productClickHandler]);
|
|
84
|
+
const priceSectionOverride = (0, react_1.useMemo)(() => (priceCurrency ? createPriceSectionOverride(priceCurrency) : undefined), [priceCurrency]);
|
|
45
85
|
const mergedOverrides = (0, react_1.useMemo)(() => {
|
|
46
|
-
var _a
|
|
47
|
-
|
|
48
|
-
|
|
86
|
+
var _a;
|
|
87
|
+
const baseOverrides = buildMergedOverrides(componentOverrides, priceSectionOverride);
|
|
88
|
+
const cardOverrides = (_a = baseOverrides.item) === null || _a === void 0 ? void 0 : _a.productCard;
|
|
89
|
+
// The carousel never passes onAddToCart down and the card hides the button without it, so
|
|
90
|
+
// re-render the card with the handler. A full card override owns its own layout - skip it.
|
|
91
|
+
if (!onAddToCart || (cardOverrides === null || cardOverrides === void 0 ? void 0 : cardOverrides.reactNode)) {
|
|
92
|
+
return baseOverrides;
|
|
49
93
|
}
|
|
50
|
-
|
|
51
|
-
|
|
94
|
+
const addToCartText = (0, translate_1.translate)('Add to Cart', translations);
|
|
95
|
+
return Object.assign(Object.assign({}, baseOverrides), { item: Object.assign(Object.assign({}, baseOverrides.item), { productCard: Object.assign(Object.assign({}, cardOverrides), { reactNode: ({ product }) => (react_1.default.createElement(constructorio_ui_components_1.ProductCard, { product: product, className: 'w-full h-full', addToCartText: addToCartText, onAddToCart: addToCartHandler, componentOverrides: cardOverrides })) }) }) });
|
|
96
|
+
}, [componentOverrides, priceSectionOverride, onAddToCart, translations, addToCartHandler]);
|
|
52
97
|
// If there are no items, do not render the carousel
|
|
53
98
|
if (items.length === 0) {
|
|
54
99
|
return null;
|
|
@@ -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, handleFeedback, onResultClick, qnaResultId, }) {
|
|
11
|
+
function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, priceCurrency, }) {
|
|
12
12
|
const scrollContainerRef = (0, react_1.useRef)(null);
|
|
13
13
|
(0, react_1.useEffect)(() => {
|
|
14
14
|
const container = scrollContainerRef.current;
|
|
@@ -34,7 +34,7 @@ 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, onResultClick: onResultClick, question: entry.question, qnaResultId: qnaResultId })),
|
|
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, translations: translations, priceCurrency: priceCurrency })),
|
|
38
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));
|
|
@@ -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, handleFeedback, onResultClick, qnaResultId, onInputFocus, }) {
|
|
10
|
+
function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, handleFeedback, onResultClick, qnaResultId, onInputFocus, priceCurrency, }) {
|
|
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, handleFeedback: handleFeedback, onResultClick: onResultClick, qnaResultId: qnaResultId }),
|
|
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, priceCurrency: priceCurrency }),
|
|
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,12 +6,12 @@ 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, onFeedback, onResultClick, question, qnaResultId, }) {
|
|
9
|
+
function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, onFeedback, onResultClick, question, qnaResultId, priceCurrency, }) {
|
|
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, onResultClick: onResultClick, question: question, qnaResultId: qnaResultId })),
|
|
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, translations: translations, priceCurrency: priceCurrency })),
|
|
15
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
|
}
|
|
@@ -6,14 +6,19 @@ const agent_1 = tslib_1.__importDefault(require("./agent"));
|
|
|
6
6
|
const version_1 = tslib_1.__importDefault(require("../../version"));
|
|
7
7
|
class MockConstructorIOClient {
|
|
8
8
|
constructor(options) {
|
|
9
|
-
|
|
10
|
-
const
|
|
9
|
+
const isServer = typeof window === 'undefined' || typeof document === 'undefined';
|
|
10
|
+
const clientOptions = Object.assign(Object.assign(Object.assign({ version: options.version || `cio-ui-pia-${version_1.default}`, serviceUrl: options.serviceUrl || 'https://ac.cnstrc.com', quizzesServiceUrl: options.quizzesServiceUrl || 'https://quizzes.cnstrc.com', agentServiceUrl: options.agentServiceUrl || 'https://agent.cnstrc.com' }, (isServer && {
|
|
11
|
+
clientId: options.clientId || 'this-is-a-random-client-id',
|
|
12
|
+
})), { sendTrackingEvents: options.sendTrackingEvents !== undefined ? options.sendTrackingEvents : true, beaconMode: options.beaconMode !== undefined ? options.beaconMode : true, networkParameters: options.networkParameters || {} }), options);
|
|
13
|
+
const cioClient = new constructorio_client_javascript_1.default(clientOptions);
|
|
14
|
+
const { clientId, sessionId } = cioClient.agent.options;
|
|
15
|
+
this.options = Object.assign(Object.assign({}, clientOptions), { clientId, sessionId });
|
|
11
16
|
this.search = cioClient.search;
|
|
12
17
|
this.browse = cioClient.browse;
|
|
13
18
|
this.recommendations = cioClient.recommendations;
|
|
14
19
|
this.tracker = cioClient.tracker;
|
|
15
20
|
this.quizzes = cioClient.quizzes;
|
|
16
|
-
this.agent = new agent_1.default(
|
|
21
|
+
this.agent = new agent_1.default(this.options);
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
24
|
exports.default = MockConstructorIOClient;
|
|
@@ -10,6 +10,7 @@ const defaultTranslations = {
|
|
|
10
10
|
'Is this answer useful?': 'Is this answer useful?',
|
|
11
11
|
'Learn More.': 'Learn More.',
|
|
12
12
|
'Ask about this product': 'Ask about this product',
|
|
13
|
+
'Add to Cart': 'Add to Cart',
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
16
|
* Translates a word using the provided translations object.
|
package/lib/cjs/version.js
CHANGED
|
@@ -15,9 +15,10 @@ import PiaModal from '../PiaConversation/PiaModal';
|
|
|
15
15
|
import PiaConversation from '../PiaConversation/PiaConversation';
|
|
16
16
|
// eslint-disable-next-line complexity
|
|
17
17
|
export default function CioPia(props) {
|
|
18
|
-
const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, children, translations, suggestedQuestionsParameters, } = props;
|
|
18
|
+
const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, productCardProps, children, translations, suggestedQuestionsParameters, } = props;
|
|
19
19
|
const { learnMoreUrl, showFeedback, mode = 'default', type = 'inline', showPreviousItems, disclaimerPosition = 'bottom', } = displayConfigs || {};
|
|
20
20
|
const isConversation = mode === 'conversation' || type === 'modal';
|
|
21
|
+
const { priceCurrency } = productCardProps || {};
|
|
21
22
|
const pia = useCioPia({
|
|
22
23
|
apiKey,
|
|
23
24
|
itemId,
|
|
@@ -75,6 +76,7 @@ export default function CioPia(props) {
|
|
|
75
76
|
qnaResultId,
|
|
76
77
|
containerRef,
|
|
77
78
|
onInputFocus: handleInputFocus,
|
|
79
|
+
priceCurrency,
|
|
78
80
|
};
|
|
79
81
|
if (type === 'modal') {
|
|
80
82
|
return (React.createElement(PiaModal, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, handleQuestionClick: handleQuestionClick, containerRef: containerRef, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onInputFocus: handleInputFocus, onClose: resetState },
|
|
@@ -90,6 +92,6 @@ export default function CioPia(props) {
|
|
|
90
92
|
isLoading && React.createElement(LoadingSkeleton, { componentOverride: componentOverrides?.loading }),
|
|
91
93
|
!isLoading && error && React.createElement(ErrorBlock, { message: error?.message || 'Unexpected error' }),
|
|
92
94
|
!isLoading && !error && (React.createElement(React.Fragment, null,
|
|
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 })),
|
|
95
|
+
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, priceCurrency: priceCurrency })),
|
|
94
96
|
React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions }))))));
|
|
95
97
|
}
|
|
@@ -1,14 +1,65 @@
|
|
|
1
1
|
import React, { useCallback, useRef, useEffect, useMemo } from 'react';
|
|
2
|
-
import { Carousel, CIO_EVENTS, } from '@constructor-io/constructorio-ui-components';
|
|
2
|
+
import { Carousel, ProductCard, CIO_EVENTS, } from '@constructor-io/constructorio-ui-components';
|
|
3
3
|
import { sanitizeHtml } from '../../utils/contentTransformers';
|
|
4
|
+
import { translate } from '../../utils/translate';
|
|
4
5
|
function HtmlDescription({ product }) {
|
|
5
6
|
const { description } = product;
|
|
6
7
|
if (!description)
|
|
7
8
|
return null;
|
|
8
9
|
return (React.createElement("p", { className: 'cio-product-card-description', dangerouslySetInnerHTML: { __html: sanitizeHtml(description) } }));
|
|
9
10
|
}
|
|
10
|
-
|
|
11
|
+
function createPriceSectionOverride(priceCurrency) {
|
|
12
|
+
return function PriceSectionOverride({ product }) {
|
|
13
|
+
const { price, salePrice } = product;
|
|
14
|
+
if (price == null)
|
|
15
|
+
return null;
|
|
16
|
+
return (React.createElement("div", { className: 'cio-product-card-price-section flex items-baseline gap-2' },
|
|
17
|
+
React.createElement("span", { className: 'text-lg font-bold' },
|
|
18
|
+
priceCurrency,
|
|
19
|
+
"\u00A0",
|
|
20
|
+
salePrice ?? price),
|
|
21
|
+
salePrice != null && (React.createElement("span", { className: 'text-sm text-gray-400 line-through' },
|
|
22
|
+
priceCurrency,
|
|
23
|
+
"\u00A0",
|
|
24
|
+
price))));
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function getContentDefaults(content, priceSectionOverride) {
|
|
28
|
+
const defaults = {};
|
|
29
|
+
if (!content?.description) {
|
|
30
|
+
defaults.description = { reactNode: HtmlDescription };
|
|
31
|
+
}
|
|
32
|
+
if (!content?.price && priceSectionOverride) {
|
|
33
|
+
defaults.price = { reactNode: priceSectionOverride };
|
|
34
|
+
}
|
|
35
|
+
return defaults;
|
|
36
|
+
}
|
|
37
|
+
function buildMergedOverrides(componentOverrides, priceSectionOverride) {
|
|
38
|
+
const content = componentOverrides?.item?.productCard?.content;
|
|
39
|
+
const defaults = getContentDefaults(content, priceSectionOverride);
|
|
40
|
+
if (Object.keys(defaults).length === 0) {
|
|
41
|
+
return componentOverrides || {};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
...componentOverrides,
|
|
45
|
+
item: {
|
|
46
|
+
...componentOverrides?.item,
|
|
47
|
+
productCard: {
|
|
48
|
+
...componentOverrides?.item?.productCard,
|
|
49
|
+
content: {
|
|
50
|
+
...content,
|
|
51
|
+
...defaults,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export default function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, translations, priceCurrency, }) {
|
|
11
58
|
const wrapperRef = useRef(null);
|
|
59
|
+
const { onAddToCart } = callbacks || {};
|
|
60
|
+
const addToCartHandler = useCallback((event, product) => {
|
|
61
|
+
onAddToCart?.(product, event);
|
|
62
|
+
}, [onAddToCart]);
|
|
12
63
|
// Determine to use user-defined click handler or default behavior
|
|
13
64
|
const productClickHandler = useCallback((item) => {
|
|
14
65
|
const position = items.findIndex((i) => i.id === item.id);
|
|
@@ -39,24 +90,27 @@ export default function PiaCustomCarousel({ items, componentOverrides, callbacks
|
|
|
39
90
|
el.removeEventListener(CIO_EVENTS.productCard.click, handleClick);
|
|
40
91
|
};
|
|
41
92
|
}, [productClickHandler]);
|
|
93
|
+
const priceSectionOverride = useMemo(() => (priceCurrency ? createPriceSectionOverride(priceCurrency) : undefined), [priceCurrency]);
|
|
42
94
|
const mergedOverrides = useMemo(() => {
|
|
43
|
-
|
|
44
|
-
|
|
95
|
+
const baseOverrides = buildMergedOverrides(componentOverrides, priceSectionOverride);
|
|
96
|
+
const cardOverrides = baseOverrides.item?.productCard;
|
|
97
|
+
// The carousel never passes onAddToCart down and the card hides the button without it, so
|
|
98
|
+
// re-render the card with the handler. A full card override owns its own layout - skip it.
|
|
99
|
+
if (!onAddToCart || cardOverrides?.reactNode) {
|
|
100
|
+
return baseOverrides;
|
|
45
101
|
}
|
|
102
|
+
const addToCartText = translate('Add to Cart', translations);
|
|
46
103
|
return {
|
|
47
|
-
...
|
|
104
|
+
...baseOverrides,
|
|
48
105
|
item: {
|
|
49
|
-
...
|
|
106
|
+
...baseOverrides.item,
|
|
50
107
|
productCard: {
|
|
51
|
-
...
|
|
52
|
-
|
|
53
|
-
...componentOverrides?.item?.productCard?.content,
|
|
54
|
-
description: { reactNode: HtmlDescription },
|
|
55
|
-
},
|
|
108
|
+
...cardOverrides,
|
|
109
|
+
reactNode: ({ product }) => (React.createElement(ProductCard, { product: product, className: 'w-full h-full', addToCartText: addToCartText, onAddToCart: addToCartHandler, componentOverrides: cardOverrides })),
|
|
56
110
|
},
|
|
57
111
|
},
|
|
58
112
|
};
|
|
59
|
-
}, [componentOverrides]);
|
|
113
|
+
}, [componentOverrides, priceSectionOverride, onAddToCart, translations, addToCartHandler]);
|
|
60
114
|
// If there are no items, do not render the carousel
|
|
61
115
|
if (items.length === 0) {
|
|
62
116
|
return null;
|
|
@@ -5,7 +5,7 @@ import Disclaimer from '../CioPia/Disclaimer';
|
|
|
5
5
|
import ErrorBlock from '../Error/ErrorBlock';
|
|
6
6
|
import LoadingSkeleton from '../LoadingSkeleton/LoadingSkeleton';
|
|
7
7
|
import PiaCustomCarousel from '../CioPia/PiaCustomCarousel';
|
|
8
|
-
export default function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, }) {
|
|
8
|
+
export default function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, priceCurrency, }) {
|
|
9
9
|
const scrollContainerRef = useRef(null);
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
const container = scrollContainerRef.current;
|
|
@@ -31,7 +31,7 @@ export default function ConversationHistory({ conversationHistory, isLoading, er
|
|
|
31
31
|
isLast && !isLoading && error && (React.createElement(ErrorBlock, { message: error.message || 'Unexpected error' })),
|
|
32
32
|
entry.answer && (React.createElement("div", { className: 'cio-pia-answer-container' },
|
|
33
33
|
React.createElement(Answer, { text: entry.answer, componentOverride: componentOverrides?.answer }),
|
|
34
|
-
carouselItems && (React.createElement(PiaCustomCarousel, { items: carouselItems, componentOverrides: componentOverrides?.carousel, callbacks: callbacks, onResultClick: onResultClick, question: entry.question, qnaResultId: qnaResultId })),
|
|
34
|
+
carouselItems && (React.createElement(PiaCustomCarousel, { items: carouselItems, componentOverrides: componentOverrides?.carousel, callbacks: callbacks, onResultClick: onResultClick, question: entry.question, qnaResultId: qnaResultId, translations: translations, priceCurrency: priceCurrency })),
|
|
35
35
|
isLast && showFeedback && (React.createElement(Feedback, { translations: translations, onFeedback: handleFeedback, componentOverride: componentOverrides?.feedback }))))));
|
|
36
36
|
})),
|
|
37
37
|
disclaimerPosition === 'bottom' && disclaimer));
|
|
@@ -4,11 +4,11 @@ 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, handleQuestionClick, containerRef, handleFeedback, onResultClick, qnaResultId, onInputFocus, }) {
|
|
7
|
+
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, handleFeedback, onResultClick, qnaResultId, onInputFocus, priceCurrency, }) {
|
|
8
8
|
const hasHistory = conversationHistory.length > 0;
|
|
9
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
|
-
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, handleFeedback: handleFeedback, onResultClick: onResultClick, qnaResultId: qnaResultId }),
|
|
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, handleFeedback: handleFeedback, onResultClick: onResultClick, qnaResultId: qnaResultId, priceCurrency: priceCurrency }),
|
|
12
12
|
React.createElement("div", { className: 'cio-pia-conversation-footer' },
|
|
13
13
|
isLoading && !error && React.createElement(SuggestedQuestionsSkeleton, null),
|
|
14
14
|
!isLoading && !error && (React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions })),
|
|
@@ -3,12 +3,12 @@ import Answer from '../Answer/Answer';
|
|
|
3
3
|
import Feedback from '../Feedback/Feedback';
|
|
4
4
|
import Disclaimer from '../CioPia/Disclaimer';
|
|
5
5
|
import PiaCustomCarousel from '../CioPia/PiaCustomCarousel';
|
|
6
|
-
export default function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, onFeedback, onResultClick, question, qnaResultId, }) {
|
|
6
|
+
export default function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, onFeedback, onResultClick, question, qnaResultId, priceCurrency, }) {
|
|
7
7
|
const disclaimer = (React.createElement(Disclaimer, { learnMoreUrl: learnMoreUrl, translations: translations, componentOverride: componentOverrides?.disclaimer }));
|
|
8
8
|
return (React.createElement("div", { className: 'cio-pia-answer-container' },
|
|
9
9
|
disclaimerPosition === 'top' && disclaimer,
|
|
10
10
|
React.createElement(Answer, { text: currentAnswer, componentOverride: componentOverrides?.answer }),
|
|
11
|
-
currentItems && (React.createElement(PiaCustomCarousel, { items: currentItems, componentOverrides: componentOverrides?.carousel, callbacks: callbacks, onResultClick: onResultClick, question: question, qnaResultId: qnaResultId })),
|
|
11
|
+
currentItems && (React.createElement(PiaCustomCarousel, { items: currentItems, componentOverrides: componentOverrides?.carousel, callbacks: callbacks, onResultClick: onResultClick, question: question, qnaResultId: qnaResultId, translations: translations, priceCurrency: priceCurrency })),
|
|
12
12
|
showFeedback && (React.createElement(Feedback, { translations: translations, onFeedback: onFeedback || callbacks?.onFeedback, componentOverride: componentOverrides?.feedback })),
|
|
13
13
|
disclaimerPosition === 'bottom' && disclaimer));
|
|
14
14
|
}
|
|
@@ -10,29 +10,29 @@ class MockConstructorIOClient {
|
|
|
10
10
|
quizzes;
|
|
11
11
|
agent;
|
|
12
12
|
constructor(options) {
|
|
13
|
-
|
|
13
|
+
const isServer = typeof window === 'undefined' || typeof document === 'undefined';
|
|
14
|
+
const clientOptions = {
|
|
14
15
|
version: options.version || `cio-ui-pia-${version}`,
|
|
15
16
|
serviceUrl: options.serviceUrl || 'https://ac.cnstrc.com',
|
|
16
17
|
quizzesServiceUrl: options.quizzesServiceUrl || 'https://quizzes.cnstrc.com',
|
|
17
18
|
agentServiceUrl: options.agentServiceUrl || 'https://agent.cnstrc.com',
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
...(isServer && {
|
|
20
|
+
clientId: options.clientId || 'this-is-a-random-client-id',
|
|
21
|
+
}),
|
|
20
22
|
sendTrackingEvents: options.sendTrackingEvents !== undefined ? options.sendTrackingEvents : true,
|
|
21
23
|
beaconMode: options.beaconMode !== undefined ? options.beaconMode : true,
|
|
22
24
|
networkParameters: options.networkParameters || {},
|
|
23
25
|
...options,
|
|
24
26
|
};
|
|
25
|
-
const cioClient = new ConstructorioClient(
|
|
27
|
+
const cioClient = new ConstructorioClient(clientOptions);
|
|
28
|
+
const { clientId, sessionId } = cioClient.agent.options;
|
|
29
|
+
this.options = { ...clientOptions, clientId, sessionId };
|
|
26
30
|
this.search = cioClient.search;
|
|
27
31
|
this.browse = cioClient.browse;
|
|
28
32
|
this.recommendations = cioClient.recommendations;
|
|
29
33
|
this.tracker = cioClient.tracker;
|
|
30
34
|
this.quizzes = cioClient.quizzes;
|
|
31
|
-
this.agent = new MockAgent(
|
|
32
|
-
...this.options,
|
|
33
|
-
clientId: options.clientId,
|
|
34
|
-
sessionId: options.sessionId,
|
|
35
|
-
});
|
|
35
|
+
this.agent = new MockAgent(this.options);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
export default MockConstructorIOClient;
|
|
@@ -7,6 +7,7 @@ const defaultTranslations = {
|
|
|
7
7
|
'Is this answer useful?': 'Is this answer useful?',
|
|
8
8
|
'Learn More.': 'Learn More.',
|
|
9
9
|
'Ask about this product': 'Ask about this product',
|
|
10
|
+
'Add to Cart': 'Add to Cart',
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* Translates a word using the provided translations object.
|
package/lib/mjs/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '2.
|
|
1
|
+
export default '2.10.1';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { IncludeComponentOverrides, IncludeRenderProps } from '@constructor-io/constructorio-ui-components';
|
|
3
3
|
import MockConstructorIOClient from '../../hooks/mocks/MockConstructorIOClient';
|
|
4
|
-
import { CioPiaRenderProps, CioPiaComponentOverrides, Callbacks, CioPiaDisplayConfigs, Translations, SuggestedQuestionsParameters, Formatters } from '../../types';
|
|
4
|
+
import { CioPiaRenderProps, CioPiaComponentOverrides, Callbacks, CioPiaDisplayConfigs, Translations, SuggestedQuestionsParameters, Formatters, ProductCardDisplayProps } from '../../types';
|
|
5
5
|
export interface CioPiaProps extends IncludeRenderProps<CioPiaRenderProps>, IncludeComponentOverrides<CioPiaComponentOverrides> {
|
|
6
6
|
/** Your Constructor.io API key. */
|
|
7
7
|
apiKey: string;
|
|
@@ -23,6 +23,8 @@ export interface CioPiaProps extends IncludeRenderProps<CioPiaRenderProps>, Incl
|
|
|
23
23
|
componentOverrides?: CioPiaComponentOverrides;
|
|
24
24
|
/** Formatter functions for transforming data before display. */
|
|
25
25
|
formatters?: Formatters;
|
|
26
|
+
/** Props forwarded to the ProductCard rendered inside the carousel. */
|
|
27
|
+
productCardProps?: ProductCardDisplayProps;
|
|
26
28
|
/** UI string translations for internationalization. */
|
|
27
29
|
translations?: Translations;
|
|
28
30
|
/** Parameters for the suggested questions request. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { CarouselOverrides } from '@constructor-io/constructorio-ui-components';
|
|
3
|
-
import { Callbacks, Item } from '../../types';
|
|
3
|
+
import { Callbacks, Item, Translations } from '../../types';
|
|
4
4
|
interface PiaCustomCarouselProps {
|
|
5
5
|
items: Array<Item>;
|
|
6
6
|
componentOverrides?: CarouselOverrides<Item>;
|
|
@@ -8,6 +8,8 @@ interface PiaCustomCarouselProps {
|
|
|
8
8
|
onResultClick?: (item: Item, position: number, question: string, qnaResultId?: string) => void;
|
|
9
9
|
question?: string;
|
|
10
10
|
qnaResultId?: string;
|
|
11
|
+
translations?: Translations;
|
|
12
|
+
priceCurrency?: string;
|
|
11
13
|
}
|
|
12
|
-
export default function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, }: PiaCustomCarouselProps): React.JSX.Element | null;
|
|
14
|
+
export default function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, translations, priceCurrency, }: PiaCustomCarouselProps): React.JSX.Element | null;
|
|
13
15
|
export {};
|
|
@@ -25,5 +25,6 @@ export interface ConversationHistoryProps {
|
|
|
25
25
|
handleFeedback?: (type: FeedbackType) => void;
|
|
26
26
|
onResultClick?: (item: Item, position: number, question: string, qnaResultId?: string) => void;
|
|
27
27
|
qnaResultId?: string;
|
|
28
|
+
priceCurrency?: string;
|
|
28
29
|
}
|
|
29
|
-
export default function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, }: ConversationHistoryProps): React.JSX.Element;
|
|
30
|
+
export default function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, priceCurrency, }: ConversationHistoryProps): React.JSX.Element;
|
|
@@ -11,4 +11,4 @@ export interface PiaConversationProps extends ConversationHistoryProps {
|
|
|
11
11
|
qnaResultId?: string;
|
|
12
12
|
onInputFocus?: () => void;
|
|
13
13
|
}
|
|
14
|
-
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, handleFeedback, onResultClick, qnaResultId, onInputFocus, }: PiaConversationProps): React.JSX.Element;
|
|
14
|
+
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, handleFeedback, onResultClick, qnaResultId, onInputFocus, priceCurrency, }: PiaConversationProps): React.JSX.Element;
|
|
@@ -13,6 +13,7 @@ interface PiaInlineAnswerProps {
|
|
|
13
13
|
onResultClick?: (item: Item, position: number, question: string, qnaResultId?: string) => void;
|
|
14
14
|
question?: string;
|
|
15
15
|
qnaResultId?: string;
|
|
16
|
+
priceCurrency?: string;
|
|
16
17
|
}
|
|
17
|
-
export default function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, onFeedback, onResultClick, question, qnaResultId, }: PiaInlineAnswerProps): React.JSX.Element;
|
|
18
|
+
export default function PiaInlineAnswer({ currentAnswer, currentItems, showFeedback, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, onFeedback, onResultClick, question, qnaResultId, priceCurrency, }: PiaInlineAnswerProps): React.JSX.Element;
|
|
18
19
|
export {};
|
package/lib/types/types.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export type Translations = {
|
|
|
59
59
|
'Is this answer useful?'?: string;
|
|
60
60
|
'Learn More.'?: string;
|
|
61
61
|
'Ask about this product'?: string;
|
|
62
|
+
'Add to Cart'?: string;
|
|
62
63
|
};
|
|
63
64
|
export type QuestionSource = 'user' | 'suggestion';
|
|
64
65
|
export interface PiaCallbackContext {
|
|
@@ -70,6 +71,12 @@ export interface Callbacks {
|
|
|
70
71
|
onQuestionSubmit?: (question: string, context: PiaCallbackContext, source: QuestionSource) => void;
|
|
71
72
|
/** Called when a product card in the carousel is clicked. */
|
|
72
73
|
onProductCardClick?: (item: Item) => void;
|
|
74
|
+
/**
|
|
75
|
+
* Called when the "Add to Cart" button on a product card is clicked.
|
|
76
|
+
* Providing this callback is what renders the button.
|
|
77
|
+
* Clicking the button does not fire `onProductCardClick`.
|
|
78
|
+
*/
|
|
79
|
+
onAddToCart?: (item: Item, event: React.MouseEvent) => void;
|
|
73
80
|
/** Called when the user submits positive or negative feedback on an answer. */
|
|
74
81
|
onFeedback?: (type: FeedbackType) => void;
|
|
75
82
|
/** Called when a new answer is received. Passes the full conversation history. */
|
|
@@ -86,6 +93,14 @@ export interface Formatters {
|
|
|
86
93
|
/** Transforms image URLs before rendering (e.g., prepend a CDN base URL). */
|
|
87
94
|
formatImageUrl?: (url: string) => string;
|
|
88
95
|
}
|
|
96
|
+
/** Props forwarded to the ProductCard rendered inside the carousel. */
|
|
97
|
+
export interface ProductCardDisplayProps {
|
|
98
|
+
/**
|
|
99
|
+
* Currency symbol to display next to product prices (e.g., "€", "£").
|
|
100
|
+
* When omitted, the default ProductCard price rendering is used.
|
|
101
|
+
*/
|
|
102
|
+
priceCurrency?: string;
|
|
103
|
+
}
|
|
89
104
|
/** Extends Product type to include PIA-specific fields */
|
|
90
105
|
export interface Item extends Product, Record<string, any> {
|
|
91
106
|
url?: string;
|
package/lib/types/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "2.
|
|
1
|
+
declare const _default: "2.10.1";
|
|
2
2
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructor-io/constructorio-ui-pia",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1",
|
|
4
4
|
"description": "Constructor.io AI Product Insights Agent UI library for web applications",
|
|
5
5
|
"author": "Constructor.io Corporation",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,8 +26,10 @@
|
|
|
26
26
|
"module": "lib/mjs/index.js",
|
|
27
27
|
"exports": {
|
|
28
28
|
"./styles.css": {
|
|
29
|
+
"style": "./lib/mjs/styles.css",
|
|
29
30
|
"import": "./lib/mjs/styles.css",
|
|
30
|
-
"require": "./lib/cjs/styles.css"
|
|
31
|
+
"require": "./lib/cjs/styles.css",
|
|
32
|
+
"default": "./lib/mjs/styles.css"
|
|
31
33
|
},
|
|
32
34
|
"./constructorio-ui-pia-bundled": {
|
|
33
35
|
"import": "./dist/constructorio-ui-pia-bundled.js",
|