GlobalData.Settings.EnableMyProductMixselectItem when a product is clicked{
"items": [
{
"productId": "Product Id",
"productVariantId": "Variant Id",
"title": "Sample product title",
"sku": "Sample text",
"imageUrl": "https://example.com/media/sample.jpg",
"alias": "sample-product-alias",
"dimension1Name": "Sample text",
"dimension1Value": "Sample text",
"dimension2Name": "Sample text",
"dimension2Value": "Sample text",
"lastPurchasedPrice": 0,
"lastPurchasedQuantity": 1,
"lastPurchasedAtUtc": "2026-01-01T00:00:00.0000000+00:00",
"lastPurchasedTotal": 0,
"lastPurchasedTotalText": "Sample price text",
"currentPrice": 0,
"canOrder": false,
"minOrderQuantity": 1,
"maxOrderQuantity": 99,
"orderQuantityStep": 1,
"sellOutOfStock": true,
"stock": 0,
"quantityConstraints": {
"additive": {
"minimum": 1,
"maximum": 999999,
"step": 1,
"isValid": true
},
"absolute": {
"minimum": 1,
"maximum": 999999,
"step": 1,
"isValid": true
}
}
},
"..."
],
"currentPage": 1,
"totalPages": 2,
"totalCount": 23,
"pageSize": 20,
"name": "ProductMixList",
"view": "Default",
"section": "SectionA",
"settings": {
"id": "Component Id",
"section": "SectionA",
"type": "NoirProductMixList",
"name": "ProductMixList",
"configuredInContentApi": true,
"view": "Default",
"displayName": "",
"cssClass": ""
},
"translations": {
"myProductMix": "Sample text",
"noProducts": "Sample text",
"noProductsDescription": "Sample text",
"...": "..."
}
}settings.iditems[]currentPage, totalPages, totalCount, pageSizeimageUrl (falls back to global no-image)dimension1Name, dimension1Value, dimension2Name, dimension2ValuequantityConstraints.*minOrderQuantity, maxOrderQuantity, orderQuantitySteptranslations.*Components/ProductMixList/Default.js exposes:<section
x-data='productmixlistdefault.initComponent(items, currentPage, totalPages, totalCount, pageSize, errorMessages)'
>initComponent(items, currentPage, totalPages, totalCount, pageSize, errorMessages)init()item._qty to item.quantityConstraints.additive.minimum (or 0).getItemByVariantId(variantId)items[] by productVariantId.getQuantity(variantId)_qty for an item.sendSelectEvent(product, listName, position)selectItem when a product row is clicked.prepareListProducts([product]), so it expects the item shape to be compatible with list GA mapping.formatDate(dateValue)Intl.DateTimeFormat('el-GR').fetchList(page)servicesreusabledefault.fetchProductMixProducts(...)._qty and pagination fields from the response.updateFlag = true so the table renders using the x-for version.handleSort(value)currentSort and refetches page 1.redirectToState(newPage = null)newPage is valid → fetches that page and scrolls to topgeneratePages()<= 7 pages: show all1 2 3 4 5 ... N1 ... N-4 N-3 N-2 N-1 N1 ... (p-1) p (p+1) ... NincreaseQuantity(variantId)item._qty by step until maximum and debounces validation.decreaseQuantity(variantId)item._qty by step down to minimum and debounces validation.debounceUpdateProduct(newQuantity, variantId, delay = 800)updateQuantity(...) per item.updateQuantity(newQuantity, variantId, useDebounce = true)servicesreusabledefault.updateProductQuantity(...).axios.CancelToken.source() to prevent request races._qty with the backend-normalized additiveQuantity.value.handleAddToCart(product)servicesreusabledefault.addToCart(...)._qty and updates quantityConstraints using the returned cart item.response.data.lineFailures[] exists, it maps error types to translated messages via getLineFailureMessages(...).getLineFailureMessages(lineFailure, productTitle)errorTypes[] values to translated error messages.$store.toast (user feedback)servicesreusabledefault.fetchProductMixProducts(params)servicesreusabledefault.updateProductQuantity(data, cancelToken)servicesreusabledefault.addToCart(productId, productVariantId, quantity, currentPrice, originalPrice)prepareListProducts(...)sendGAEvent(...)toastGlobalData.Settings.EnableMyProductMix.generatePages()), so they must stay in sync.{% for item in items %}<template x-for="..."> after any fetch/update (updateFlag).errorMessages JSON string in Liquid and passes it to initComponent(...).items is empty.quantityConstraints.additive.isValid == false.GlobalData.Settings.noImage (fallback to theme Assets/images/no-image.svg).