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, pageSizesettings.cssClassimageUrl (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()_qty) so quantity inputs work even though the API payload doesn’t contain “current UI quantity”.item._qty to a computed start quantity (getStartQuantity(item)).getItemByVariantId(variantId)items[] by productVariantId.getQuantity(variantId)_qty for an item.sendSelectEvent(product, listName, position)selectItem).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)fetch() from /api/product-mix/my-list._qty and pagination fields from the response.error = true and clears items.handleSort(value)currentSort and refetches page 1.goToPage(page)visiblePages (getter)currentPage.increaseQuantity(item)item._qty by orderQuantityStep up to maxOrderQuantity.decreaseQuantity(item)item._qty by orderQuantityStep down to minOrderQuantity.updateQuantity(value, item)[minOrderQuantity, maxOrderQuantity].item._qty.addToCart(item)servicesreusabledefault.addToCart(...).Alpine.store("toast") for error feedback.response.data.lineFailures[] exists, it maps error types to translated messages via getLineFailureMessages(...).getLineFailureMessages(lineFailure, productTitle)errorTypes[] values to translated error messages.Alpine.store("toast") (user feedback)GET /api/product-mix/my-list?page=<n>&pageSize=<n>&orderBy=<sort>servicesreusabledefault.addToCart(productId, productVariantId, quantity, currentPrice, originalPrice)fetch (for list paging)prepareListProducts(...)sendGAEvent(...)toastservicesreusabledefault.addToCart(...) for add-to-cart.GlobalData.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).