@constructor-io/constructorio-ui-plp 1.6.4 → 1.6.5

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.
@@ -30,7 +30,10 @@ function ProductCard(props) {
30
30
  const onAddToCart = (0, callbacks_1.useOnAddToCart)(client, state.callbacks.onAddToCart);
31
31
  const { formatPrice } = state.formatters;
32
32
  const onClick = (0, callbacks_1.useOnProductCardClick)(client, state.callbacks.onProductCardClick);
33
- const cnstrcData = (0, utils_1.getProductCardCnstrcDataAttributes)(productInfo);
33
+ const cnstrcDataAttrs = (0, utils_1.getProductCardCnstrcDataAttributes)(productInfo, {
34
+ labels: item.labels,
35
+ });
36
+ const addToCartBtnAttrs = (0, utils_1.getConversionButtonCnstrcDataAttributes)('add_to_cart');
34
37
  const handleRolloverImageState = (isShown) => {
35
38
  var _a;
36
39
  setIsRolloverImageShown(isShown);
@@ -63,9 +66,9 @@ function ProductCard(props) {
63
66
  onMouseEnter,
64
67
  onMouseLeave,
65
68
  isRolloverImageShown,
66
- productCardCnstrcDataAttributes: cnstrcData,
67
- }, override: children, htmlOverride: (_a = state.renderOverrides.productCard) === null || _a === void 0 ? void 0 : _a.renderHtml, topLevelAttributes: Object.assign(Object.assign({}, cnstrcData), { className: 'cio-product-card' }) },
68
- react_1.default.createElement("a", Object.assign({}, cnstrcData, { className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => { var _a; return onClick(e, item, (_a = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _a === void 0 ? void 0 : _a.variationId); } }),
69
+ productCardCnstrcDataAttributes: cnstrcDataAttrs,
70
+ }, override: children, htmlOverride: (_a = state.renderOverrides.productCard) === null || _a === void 0 ? void 0 : _a.renderHtml, topLevelAttributes: Object.assign(Object.assign({}, cnstrcDataAttrs), { className: 'cio-product-card' }) },
71
+ react_1.default.createElement("a", Object.assign({}, cnstrcDataAttrs, { className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => { var _a; return onClick(e, item, (_a = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _a === void 0 ? void 0 : _a.variationId); } }),
69
72
  react_1.default.createElement("div", { className: 'cio-image-container', onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
70
73
  react_1.default.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' }),
71
74
  rolloverImage && (react_1.default.createElement("img", { alt: `${itemName} rollover`, src: rolloverImage, loading: 'lazy', className: (0, utils_1.concatStyles)('cio-image cio-rollover-image', isRolloverImageShown && 'is-active') }))),
@@ -75,6 +78,6 @@ function ProductCard(props) {
75
78
  Number(itemPrice) >= 0 && (react_1.default.createElement("div", { className: (0, utils_1.concatStyles)('cio-item-price', hasSalePrice && 'cio-item-price-strikethrough') }, formatPrice(itemPrice)))),
76
79
  react_1.default.createElement("div", { className: 'cio-item-name' }, itemName),
77
80
  productSwatch && react_1.default.createElement(ProductSwatch_1.default, { swatchObject: productSwatch })),
78
- react_1.default.createElement("button", { className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => { var _a; return onAddToCart(e, item, itemPrice, (_a = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _a === void 0 ? void 0 : _a.variationId); } }, "Add to Cart"))));
81
+ react_1.default.createElement("button", Object.assign({}, addToCartBtnAttrs, { className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => { var _a; return onAddToCart(e, item, itemPrice, (_a = productSwatch === null || productSwatch === void 0 ? void 0 : productSwatch.selectedVariation) === null || _a === void 0 ? void 0 : _a.variationId); } }), "Add to Cart"))));
79
82
  }
80
83
  exports.default = ProductCard;
@@ -34,9 +34,12 @@ function ProductSwatch(props) {
34
34
  const color = (0, utils_1.isHexColor)(swatch === null || swatch === void 0 ? void 0 : swatch.swatchPreview)
35
35
  ? swatch === null || swatch === void 0 ? void 0 : swatch.swatchPreview
36
36
  : `url(${swatch === null || swatch === void 0 ? void 0 : swatch.swatchPreview})`;
37
- return (react_1.default.createElement("button", { type: 'button', key: swatch.variationId, "data-cnstrc-variation-id": swatch.variationId, "data-testid": `cio-swatch-${swatch.variationId}`, className: 'cio-swatch-button cio-swatch-item', onClick: (e) => swatchClickHandler(e, swatch), style: {
37
+ const variationIdAttr = {
38
+ [utils_1.cnstrcDataAttrs.common.variationId]: swatch.variationId,
39
+ };
40
+ return (react_1.default.createElement("button", Object.assign({ type: 'button', key: swatch.variationId, "data-testid": `cio-swatch-${swatch.variationId}`, className: 'cio-swatch-button cio-swatch-item', onClick: (e) => swatchClickHandler(e, swatch), style: {
38
41
  background: color,
39
- } }, isSelected && (react_1.default.createElement("div", { "data-cnstrc-variation-id": swatch.variationId, className: 'cio-swatch-selected', style: { outline: `3px solid ${color}` } }))));
42
+ } }, variationIdAttr), isSelected && (react_1.default.createElement("div", Object.assign({ className: 'cio-swatch-selected', style: { outline: `3px solid ${color}` } }, variationIdAttr)))));
40
43
  }))))));
41
44
  }
42
45
  exports.default = ProductSwatch;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EMITTED_EVENTS = exports.DEMO_API_KEY = void 0;
4
- // eslint-disable-next-line import/prefer-default-export
5
4
  exports.DEMO_API_KEY = 'key_M57QS8SMPdLdLx4x';
6
5
  exports.EMITTED_EVENTS = {
7
6
  PRODUCT_CARD_IMAGE_ROLLOVER: 'cio.ui-plp.productCardImageRollover',
@@ -69,14 +69,15 @@ function useCioPlp(props = {}) {
69
69
  const pagination = (0, usePagination_1.default)(Object.assign({ totalNumResults }, paginationConfigs));
70
70
  const groups = (0, useGroups_1.default)(Object.assign({ groups: rawGroups }, groupsConfigs));
71
71
  const data = isSearchPage ? search.data : browse.data;
72
- const plpContainerCnstrcDataAttributes = (0, utils_1.getPlpContainerCnstrcDataAttributes)(data, requestConfigs);
72
+ const status = isSearchPage ? search.status : browse.status;
73
+ const plpContainerCnstrcDataAttributes = (0, utils_1.getPlpContainerCnstrcDataAttributes)(data, requestConfigs, status === 'fetching');
73
74
  return {
74
75
  isSearchPage,
75
76
  isBrowsePage,
76
77
  searchQuery: search.query,
77
78
  browseFilterName: browse.filterName,
78
79
  browseFilterValue: browse.filterValue,
79
- status: isSearchPage ? search.status : browse.status,
80
+ status,
80
81
  data,
81
82
  refetch,
82
83
  filters,
@@ -1,42 +1,85 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPlpContainerCnstrcDataAttributes = exports.getProductCardCnstrcDataAttributes = void 0;
3
+ exports.getConversionButtonCnstrcDataAttributes = exports.getPlpContainerCnstrcDataAttributes = exports.getProductCardCnstrcDataAttributes = exports.cnstrcDataAttrs = void 0;
4
4
  const typeHelpers_1 = require("./typeHelpers");
5
5
  const requestConfigsHelpers_1 = require("./requestConfigsHelpers");
6
- function getProductCardCnstrcDataAttributes(productInfo) {
7
- let dataCnstrc = {};
6
+ exports.cnstrcDataAttrs = {
7
+ common: {
8
+ itemId: 'data-cnstrc-item-id',
9
+ itemName: 'data-cnstrc-item-name',
10
+ itemPrice: 'data-cnstrc-item-price',
11
+ variationId: 'data-cnstrc-item-variation-id',
12
+ numResults: 'data-cnstrc-num-results',
13
+ conversionBtn: 'data-cnstrc-btn',
14
+ resultId: 'data-cnstrc-result-id',
15
+ section: 'data-cnstrc-section',
16
+ zeroResults: 'data-cnstrc-zero-result',
17
+ slCampaignId: 'data-cnstrc-sl-campaign-id',
18
+ slCampaignOwner: 'data-cnstrc-sl-campaign-owner',
19
+ },
20
+ search: {
21
+ searchContainer: 'data-cnstrc-search',
22
+ searchTerm: 'data-cnstrc-search-term',
23
+ },
24
+ browse: {
25
+ browseContainer: 'data-cnstrc-browse',
26
+ filterName: 'data-cnstrc-filter-name',
27
+ filterValue: 'data-cnstrc-filter-value',
28
+ },
29
+ };
30
+ function getProductCardCnstrcDataAttributes(productInfo, options) {
31
+ var _a, _b;
8
32
  const { itemId, itemPrice, itemName, variationId } = productInfo;
9
- dataCnstrc = {
10
- 'data-cnstrc-item-id': itemId,
11
- 'data-cnstrc-item-name': itemName,
12
- 'data-cnstrc-item-price': itemPrice,
13
- 'data-cnstrc-item-variation-id': variationId,
33
+ const dataCnstrc = {
34
+ [exports.cnstrcDataAttrs.common.itemId]: itemId,
35
+ [exports.cnstrcDataAttrs.common.itemName]: itemName,
14
36
  };
37
+ // Only include variation ID if it exists
38
+ if (variationId) {
39
+ dataCnstrc[exports.cnstrcDataAttrs.common.variationId] = variationId;
40
+ }
41
+ // Only include price if it exists
42
+ if (itemPrice !== undefined && itemPrice !== null) {
43
+ dataCnstrc[exports.cnstrcDataAttrs.common.itemPrice] = itemPrice;
44
+ }
45
+ // Add sponsored listing data if available
46
+ if ((_a = options === null || options === void 0 ? void 0 : options.labels) === null || _a === void 0 ? void 0 : _a.sl_campaign_id) {
47
+ dataCnstrc[exports.cnstrcDataAttrs.common.slCampaignId] = String(options.labels.sl_campaign_id);
48
+ }
49
+ if ((_b = options === null || options === void 0 ? void 0 : options.labels) === null || _b === void 0 ? void 0 : _b.sl_campaign_owner) {
50
+ dataCnstrc[exports.cnstrcDataAttrs.common.slCampaignOwner] = String(options.labels.sl_campaign_owner);
51
+ }
15
52
  return dataCnstrc;
16
53
  }
17
54
  exports.getProductCardCnstrcDataAttributes = getProductCardCnstrcDataAttributes;
18
- function getPlpContainerCnstrcDataAttributes(data, requestConfigs) {
55
+ function getPlpContainerCnstrcDataAttributes(data, requestConfigs, isLoading = false) {
56
+ var _a, _b;
19
57
  if (!data || (!(0, typeHelpers_1.isPlpSearchDataResults)(data) && !(0, typeHelpers_1.isPlpBrowseDataResults)(data)))
20
58
  return {};
21
59
  const { filterName, filterValue } = requestConfigs;
22
60
  const pageType = (0, requestConfigsHelpers_1.getPageType)(requestConfigs);
61
+ const isZeroResults = data.response.totalNumResults === 0;
23
62
  let dataCnstrc = {};
24
63
  switch (pageType) {
25
64
  case 'browse':
26
65
  dataCnstrc = {
27
- 'data-cnstrc-browse': true,
28
- 'data-cnstrc-num-results': data.response.totalNumResults,
29
- 'data-cnstrc-result-id': data.resultId,
30
- 'data-cnstrc-filter-name': filterName,
31
- 'data-cnstrc-filter-value': filterValue,
66
+ [exports.cnstrcDataAttrs.browse.browseContainer]: true,
67
+ [exports.cnstrcDataAttrs.common.numResults]: data.response.totalNumResults,
68
+ [exports.cnstrcDataAttrs.common.resultId]: data.resultId,
69
+ [exports.cnstrcDataAttrs.browse.filterName]: filterName,
70
+ [exports.cnstrcDataAttrs.browse.filterValue]: filterValue,
32
71
  };
33
72
  break;
34
73
  case 'search':
35
74
  dataCnstrc = {
36
- 'data-cnstrc-search': true,
37
- 'data-cnstrc-result-id': data.resultId,
38
- 'data-cnstrc-num-results': data.response.totalNumResults,
75
+ [exports.cnstrcDataAttrs.search.searchContainer]: true,
76
+ [exports.cnstrcDataAttrs.common.resultId]: data.resultId,
77
+ [exports.cnstrcDataAttrs.common.numResults]: data.response.totalNumResults,
39
78
  };
79
+ // Add search term
80
+ if ((_a = data.request) === null || _a === void 0 ? void 0 : _a.term) {
81
+ dataCnstrc[exports.cnstrcDataAttrs.search.searchTerm] = data.request.term;
82
+ }
40
83
  break;
41
84
  case 'unknown':
42
85
  dataCnstrc = {};
@@ -44,6 +87,23 @@ function getPlpContainerCnstrcDataAttributes(data, requestConfigs) {
44
87
  default:
45
88
  break;
46
89
  }
90
+ // Add common conditional attributes (applies to both search and browse)
91
+ if (pageType === 'search' || pageType === 'browse') {
92
+ // Add zero-result attribute only if not loading and there are no results
93
+ if (isZeroResults && !isLoading) {
94
+ dataCnstrc[exports.cnstrcDataAttrs.common.zeroResults] = true;
95
+ }
96
+ // Add section if it's not "Products"
97
+ if (((_b = data.request) === null || _b === void 0 ? void 0 : _b.section) && data.request.section !== 'Products') {
98
+ dataCnstrc[exports.cnstrcDataAttrs.common.section] = data.request.section;
99
+ }
100
+ }
47
101
  return dataCnstrc;
48
102
  }
49
103
  exports.getPlpContainerCnstrcDataAttributes = getPlpContainerCnstrcDataAttributes;
104
+ function getConversionButtonCnstrcDataAttributes(conversionType) {
105
+ return {
106
+ [exports.cnstrcDataAttrs.common.conversionBtn]: conversionType,
107
+ };
108
+ }
109
+ exports.getConversionButtonCnstrcDataAttributes = getConversionButtonCnstrcDataAttributes;
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = '1.6.4';
3
+ exports.default = '1.6.5';
@@ -3,7 +3,7 @@ import { useCioPlpContext } from '../../hooks/useCioPlpContext';
3
3
  import { useOnAddToCart, useOnProductCardClick } from '../../hooks/callbacks';
4
4
  import ProductSwatch from '../ProductSwatch';
5
5
  import useProductInfo from '../../hooks/useProduct';
6
- import { concatStyles, getProductCardCnstrcDataAttributes } from '../../utils';
6
+ import { concatStyles, getProductCardCnstrcDataAttributes, getConversionButtonCnstrcDataAttributes, } from '../../utils';
7
7
  import RenderPropsWrapper from '../RenderPropsWrapper/RenderPropsWrapper';
8
8
  import { EMITTED_EVENTS } from '../../constants';
9
9
  /**
@@ -26,7 +26,10 @@ export default function ProductCard(props) {
26
26
  const onAddToCart = useOnAddToCart(client, state.callbacks.onAddToCart);
27
27
  const { formatPrice } = state.formatters;
28
28
  const onClick = useOnProductCardClick(client, state.callbacks.onProductCardClick);
29
- const cnstrcData = getProductCardCnstrcDataAttributes(productInfo);
29
+ const cnstrcDataAttrs = getProductCardCnstrcDataAttributes(productInfo, {
30
+ labels: item.labels,
31
+ });
32
+ const addToCartBtnAttrs = getConversionButtonCnstrcDataAttributes('add_to_cart');
30
33
  const handleRolloverImageState = (isShown) => {
31
34
  setIsRolloverImageShown(isShown);
32
35
  if (isShown && rolloverImage) {
@@ -58,9 +61,9 @@ export default function ProductCard(props) {
58
61
  onMouseEnter,
59
62
  onMouseLeave,
60
63
  isRolloverImageShown,
61
- productCardCnstrcDataAttributes: cnstrcData,
62
- }, override: children, htmlOverride: state.renderOverrides.productCard?.renderHtml, topLevelAttributes: { ...cnstrcData, className: 'cio-product-card' } },
63
- React.createElement("a", { ...cnstrcData, className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => onClick(e, item, productSwatch?.selectedVariation?.variationId) },
64
+ productCardCnstrcDataAttributes: cnstrcDataAttrs,
65
+ }, override: children, htmlOverride: state.renderOverrides.productCard?.renderHtml, topLevelAttributes: { ...cnstrcDataAttrs, className: 'cio-product-card' } },
66
+ React.createElement("a", { ...cnstrcDataAttrs, className: 'cio-product-card', href: itemUrl, ref: cardRef, onClick: (e) => onClick(e, item, productSwatch?.selectedVariation?.variationId) },
64
67
  React.createElement("div", { className: 'cio-image-container', onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
65
68
  React.createElement("img", { alt: itemName, src: itemImageUrl, className: 'cio-image' }),
66
69
  rolloverImage && (React.createElement("img", { alt: `${itemName} rollover`, src: rolloverImage, loading: 'lazy', className: concatStyles('cio-image cio-rollover-image', isRolloverImageShown && 'is-active') }))),
@@ -70,5 +73,5 @@ export default function ProductCard(props) {
70
73
  Number(itemPrice) >= 0 && (React.createElement("div", { className: concatStyles('cio-item-price', hasSalePrice && 'cio-item-price-strikethrough') }, formatPrice(itemPrice)))),
71
74
  React.createElement("div", { className: 'cio-item-name' }, itemName),
72
75
  productSwatch && React.createElement(ProductSwatch, { swatchObject: productSwatch })),
73
- React.createElement("button", { className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => onAddToCart(e, item, itemPrice, productSwatch?.selectedVariation?.variationId) }, "Add to Cart"))));
76
+ React.createElement("button", { ...addToCartBtnAttrs, className: 'cio-add-to-cart-button', type: 'button', onClick: (e) => onAddToCart(e, item, itemPrice, productSwatch?.selectedVariation?.variationId) }, "Add to Cart"))));
74
77
  }
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable jsx-a11y/click-events-have-key-events */
2
2
  import React from 'react';
3
3
  import { useCioPlpContext } from '../../hooks/useCioPlpContext';
4
- import { isHexColor } from '../../utils';
4
+ import { isHexColor, cnstrcDataAttrs } from '../../utils';
5
5
  export default function ProductSwatch(props) {
6
6
  const context = useCioPlpContext();
7
7
  const { swatchObject, children } = props;
@@ -31,8 +31,11 @@ export default function ProductSwatch(props) {
31
31
  const color = isHexColor(swatch?.swatchPreview)
32
32
  ? swatch?.swatchPreview
33
33
  : `url(${swatch?.swatchPreview})`;
34
- return (React.createElement("button", { type: 'button', key: swatch.variationId, "data-cnstrc-variation-id": swatch.variationId, "data-testid": `cio-swatch-${swatch.variationId}`, className: 'cio-swatch-button cio-swatch-item', onClick: (e) => swatchClickHandler(e, swatch), style: {
34
+ const variationIdAttr = {
35
+ [cnstrcDataAttrs.common.variationId]: swatch.variationId,
36
+ };
37
+ return (React.createElement("button", { type: 'button', key: swatch.variationId, "data-testid": `cio-swatch-${swatch.variationId}`, className: 'cio-swatch-button cio-swatch-item', onClick: (e) => swatchClickHandler(e, swatch), style: {
35
38
  background: color,
36
- } }, isSelected && (React.createElement("div", { "data-cnstrc-variation-id": swatch.variationId, className: 'cio-swatch-selected', style: { outline: `3px solid ${color}` } }))));
39
+ }, ...variationIdAttr }, isSelected && (React.createElement("div", { className: 'cio-swatch-selected', style: { outline: `3px solid ${color}` }, ...variationIdAttr }))));
37
40
  }))))));
38
41
  }
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line import/prefer-default-export
2
1
  export const DEMO_API_KEY = 'key_M57QS8SMPdLdLx4x';
3
2
  export const EMITTED_EVENTS = {
4
3
  PRODUCT_CARD_IMAGE_ROLLOVER: 'cio.ui-plp.productCardImageRollover',
@@ -65,14 +65,15 @@ export default function useCioPlp(props = {}) {
65
65
  const pagination = usePagination({ totalNumResults, ...paginationConfigs });
66
66
  const groups = useGroups({ groups: rawGroups, ...groupsConfigs });
67
67
  const data = isSearchPage ? search.data : browse.data;
68
- const plpContainerCnstrcDataAttributes = getPlpContainerCnstrcDataAttributes(data, requestConfigs);
68
+ const status = isSearchPage ? search.status : browse.status;
69
+ const plpContainerCnstrcDataAttributes = getPlpContainerCnstrcDataAttributes(data, requestConfigs, status === 'fetching');
69
70
  return {
70
71
  isSearchPage,
71
72
  isBrowsePage,
72
73
  searchQuery: search.query,
73
74
  browseFilterName: browse.filterName,
74
75
  browseFilterValue: browse.filterValue,
75
- status: isSearchPage ? search.status : browse.status,
76
+ status,
76
77
  data,
77
78
  refetch,
78
79
  filters,
@@ -1,38 +1,79 @@
1
1
  import { isPlpBrowseDataResults, isPlpSearchDataResults } from './typeHelpers';
2
2
  import { getPageType } from './requestConfigsHelpers';
3
- export function getProductCardCnstrcDataAttributes(productInfo) {
4
- let dataCnstrc = {};
3
+ export const cnstrcDataAttrs = {
4
+ common: {
5
+ itemId: 'data-cnstrc-item-id',
6
+ itemName: 'data-cnstrc-item-name',
7
+ itemPrice: 'data-cnstrc-item-price',
8
+ variationId: 'data-cnstrc-item-variation-id',
9
+ numResults: 'data-cnstrc-num-results',
10
+ conversionBtn: 'data-cnstrc-btn',
11
+ resultId: 'data-cnstrc-result-id',
12
+ section: 'data-cnstrc-section',
13
+ zeroResults: 'data-cnstrc-zero-result',
14
+ slCampaignId: 'data-cnstrc-sl-campaign-id',
15
+ slCampaignOwner: 'data-cnstrc-sl-campaign-owner',
16
+ },
17
+ search: {
18
+ searchContainer: 'data-cnstrc-search',
19
+ searchTerm: 'data-cnstrc-search-term',
20
+ },
21
+ browse: {
22
+ browseContainer: 'data-cnstrc-browse',
23
+ filterName: 'data-cnstrc-filter-name',
24
+ filterValue: 'data-cnstrc-filter-value',
25
+ },
26
+ };
27
+ export function getProductCardCnstrcDataAttributes(productInfo, options) {
5
28
  const { itemId, itemPrice, itemName, variationId } = productInfo;
6
- dataCnstrc = {
7
- 'data-cnstrc-item-id': itemId,
8
- 'data-cnstrc-item-name': itemName,
9
- 'data-cnstrc-item-price': itemPrice,
10
- 'data-cnstrc-item-variation-id': variationId,
29
+ const dataCnstrc = {
30
+ [cnstrcDataAttrs.common.itemId]: itemId,
31
+ [cnstrcDataAttrs.common.itemName]: itemName,
11
32
  };
33
+ // Only include variation ID if it exists
34
+ if (variationId) {
35
+ dataCnstrc[cnstrcDataAttrs.common.variationId] = variationId;
36
+ }
37
+ // Only include price if it exists
38
+ if (itemPrice !== undefined && itemPrice !== null) {
39
+ dataCnstrc[cnstrcDataAttrs.common.itemPrice] = itemPrice;
40
+ }
41
+ // Add sponsored listing data if available
42
+ if (options?.labels?.sl_campaign_id) {
43
+ dataCnstrc[cnstrcDataAttrs.common.slCampaignId] = String(options.labels.sl_campaign_id);
44
+ }
45
+ if (options?.labels?.sl_campaign_owner) {
46
+ dataCnstrc[cnstrcDataAttrs.common.slCampaignOwner] = String(options.labels.sl_campaign_owner);
47
+ }
12
48
  return dataCnstrc;
13
49
  }
14
- export function getPlpContainerCnstrcDataAttributes(data, requestConfigs) {
50
+ export function getPlpContainerCnstrcDataAttributes(data, requestConfigs, isLoading = false) {
15
51
  if (!data || (!isPlpSearchDataResults(data) && !isPlpBrowseDataResults(data)))
16
52
  return {};
17
53
  const { filterName, filterValue } = requestConfigs;
18
54
  const pageType = getPageType(requestConfigs);
55
+ const isZeroResults = data.response.totalNumResults === 0;
19
56
  let dataCnstrc = {};
20
57
  switch (pageType) {
21
58
  case 'browse':
22
59
  dataCnstrc = {
23
- 'data-cnstrc-browse': true,
24
- 'data-cnstrc-num-results': data.response.totalNumResults,
25
- 'data-cnstrc-result-id': data.resultId,
26
- 'data-cnstrc-filter-name': filterName,
27
- 'data-cnstrc-filter-value': filterValue,
60
+ [cnstrcDataAttrs.browse.browseContainer]: true,
61
+ [cnstrcDataAttrs.common.numResults]: data.response.totalNumResults,
62
+ [cnstrcDataAttrs.common.resultId]: data.resultId,
63
+ [cnstrcDataAttrs.browse.filterName]: filterName,
64
+ [cnstrcDataAttrs.browse.filterValue]: filterValue,
28
65
  };
29
66
  break;
30
67
  case 'search':
31
68
  dataCnstrc = {
32
- 'data-cnstrc-search': true,
33
- 'data-cnstrc-result-id': data.resultId,
34
- 'data-cnstrc-num-results': data.response.totalNumResults,
69
+ [cnstrcDataAttrs.search.searchContainer]: true,
70
+ [cnstrcDataAttrs.common.resultId]: data.resultId,
71
+ [cnstrcDataAttrs.common.numResults]: data.response.totalNumResults,
35
72
  };
73
+ // Add search term
74
+ if (data.request?.term) {
75
+ dataCnstrc[cnstrcDataAttrs.search.searchTerm] = data.request.term;
76
+ }
36
77
  break;
37
78
  case 'unknown':
38
79
  dataCnstrc = {};
@@ -40,5 +81,21 @@ export function getPlpContainerCnstrcDataAttributes(data, requestConfigs) {
40
81
  default:
41
82
  break;
42
83
  }
84
+ // Add common conditional attributes (applies to both search and browse)
85
+ if (pageType === 'search' || pageType === 'browse') {
86
+ // Add zero-result attribute only if not loading and there are no results
87
+ if (isZeroResults && !isLoading) {
88
+ dataCnstrc[cnstrcDataAttrs.common.zeroResults] = true;
89
+ }
90
+ // Add section if it's not "Products"
91
+ if (data.request?.section && data.request.section !== 'Products') {
92
+ dataCnstrc[cnstrcDataAttrs.common.section] = data.request.section;
93
+ }
94
+ }
43
95
  return dataCnstrc;
44
96
  }
97
+ export function getConversionButtonCnstrcDataAttributes(conversionType) {
98
+ return {
99
+ [cnstrcDataAttrs.common.conversionBtn]: conversionType,
100
+ };
101
+ }
@@ -1 +1 @@
1
- export default '1.6.4';
1
+ export default '1.6.5';
@@ -59,5 +59,5 @@ export default function useCioPlp(props?: UseCioPlpProps): {
59
59
  optionsToRender: PlpItemGroup[];
60
60
  setOptionsToRender: import("react").Dispatch<import("react").SetStateAction<PlpItemGroup[]>>;
61
61
  };
62
- plpContainerCnstrcDataAttributes: Record<`data-cnstrc-${string}`, string | number | boolean>;
62
+ plpContainerCnstrcDataAttributes: import("../types").CnstrcDataAttrs;
63
63
  };
@@ -75,7 +75,7 @@ export interface ProductCardRenderProps extends ProductCardProps {
75
75
  /**
76
76
  * Data Attributes to surface on parent div of product card.
77
77
  */
78
- productCardCnstrcDataAttributes: CnstrcData;
78
+ productCardCnstrcDataAttributes: CnstrcDataAttrs;
79
79
  }
80
80
  export type ProductCardProps = IncludeRenderProps<ProductCardBaseProps, ProductCardRenderProps>;
81
81
  export interface RenderOverrides {
@@ -295,7 +295,7 @@ export interface PlpItemGroup {
295
295
  children: Array<PlpItemGroup>;
296
296
  parents: Pick<PlpItemGroup, 'groupId' | 'displayName'>[];
297
297
  }
298
- export type CnstrcData = Record<`data-cnstrc-${string}`, string | number | boolean>;
298
+ export type CnstrcDataAttrs = Record<`data-cnstrc-${string}` | string, string | number | boolean>;
299
299
  export type PropsWithChildren<P> = P & {
300
300
  children?: ReactNode;
301
301
  };
@@ -1,3 +1,37 @@
1
- import { RequestConfigs, PlpSearchDataResults, PlpSearchDataRedirect, PlpBrowseData, CnstrcData, ProductInfoObject } from '../types';
2
- export declare function getProductCardCnstrcDataAttributes(productInfo: ProductInfoObject): CnstrcData;
3
- export declare function getPlpContainerCnstrcDataAttributes(data: PlpSearchDataResults | PlpSearchDataRedirect | PlpBrowseData | null, requestConfigs: RequestConfigs): Record<`data-cnstrc-${string}`, string | number | boolean>;
1
+ import { RequestConfigs, PlpSearchDataResults, PlpSearchDataRedirect, PlpBrowseData, CnstrcDataAttrs, ProductInfoObject } from '../types';
2
+ export interface ProductCardDataAttributeOptions {
3
+ labels?: {
4
+ sl_campaign_id?: string | number;
5
+ sl_campaign_owner?: string | number;
6
+ };
7
+ }
8
+ export declare const cnstrcDataAttrs: {
9
+ common: {
10
+ itemId: string;
11
+ itemName: string;
12
+ itemPrice: string;
13
+ variationId: string;
14
+ numResults: string;
15
+ conversionBtn: string;
16
+ resultId: string;
17
+ section: string;
18
+ zeroResults: string;
19
+ slCampaignId: string;
20
+ slCampaignOwner: string;
21
+ };
22
+ search: {
23
+ searchContainer: string;
24
+ searchTerm: string;
25
+ };
26
+ browse: {
27
+ browseContainer: string;
28
+ filterName: string;
29
+ filterValue: string;
30
+ };
31
+ };
32
+ export declare function getProductCardCnstrcDataAttributes(productInfo: ProductInfoObject, options?: ProductCardDataAttributeOptions): CnstrcDataAttrs;
33
+ export declare function getPlpContainerCnstrcDataAttributes(data: PlpSearchDataResults | PlpSearchDataRedirect | PlpBrowseData | null, requestConfigs: RequestConfigs, isLoading?: boolean): CnstrcDataAttrs;
34
+ export type ConversionType = 'add_to_cart' | 'add_to_wishlist' | 'like' | 'message' | 'make_offer' | 'read' | string;
35
+ export declare function getConversionButtonCnstrcDataAttributes(conversionType: ConversionType): {
36
+ [x: string]: string;
37
+ };
@@ -1,2 +1,2 @@
1
- declare const _default: "1.6.4";
1
+ declare const _default: "1.6.5";
2
2
  export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-ui-plp",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "description": "Constructor PLP UI library for web applications",
5
5
  "author": "Constructor.io Corporation",
6
6
  "license": "MIT",