ShoppingLists is the reusable that manages shopping-list collection views and list-level actions.Components/Profile/Default.liquid:{% render 'Reusables\\ShoppingLists\\Default', shoppingLists: shoppingLists %}shoppingLists (array)shoppinglistsreusabledefault.initComponent(...).[
{
"id": "Shopping List Id",
"title": "Sample text",
"alias": "sample",
"items": [
{
"productId": "Product Id",
"productVariantId": "Product Variant Id",
"quantity": 1,
"product": {
"id": "Product Id",
"title": "Sample text",
"alias": "sample",
"link": "product/sample",
"mediaItems": [
{
"id": "Media Id",
"link": "https://example.com/sample",
"position": 0,
"alt": "Sample text",
"mediaType": "Image"
},
...
],
"productVariants": [
{
"id": "Product Variant Id",
"quantityConstraints": {
"additive": {
"minimum": 1,
"maximum": 999999,
"step": 1,
"isValid": true
},
"absolute": {
"minimum": 1,
"maximum": 999999,
"step": 1,
"isValid": true
}
},
"dimension1ItemId": "Dimension Item Id",
"dimension2ItemId": "Dimension Item Id",
"sku": "Sample text",
"canOrder": true,
"sellOutOfStock": true,
"startQuantity": 1
},
...
],
"dimension1": {
"id": "Dimension Id",
"name": "Sample text",
"type": "Color",
"items": [
{
"id": "Dimension Item Id",
"value": "Sample text",
"textColor": "#000000"
},
...
]
},
"dimension2": {
"id": "Dimension Id",
"name": "Sample text",
"type": "Size",
"items": [
{
"id": "Dimension Item Id",
"value": "Sample text"
},
...
]
}
}
},
...
]
},
...
]idtitlealiasitems[]productIdproductVariantIdquantityproductid, title, aliasmediaItems[] (optional but used for previews)productVariants[] (used for mapping dimensions/variant data)GlobalData.Settings.EnableShoppingLists is truthy.x-data='shoppinglistsreusabledefault.initComponent(shoppingLists, translationErrors)'shoppingLists is the Liquid parametertranslationErrors is a JSON string built from Reusables.ShoppingLists.Translations.*selectedShoppingListIndex == null)selectedShoppingListIndex != null)$store.modal.open(...) and relies on:promptmodalreusabledefault.isDataValid(modalData)shoppinglistsreusabledefault (in Reusables/ShoppingLists/Default.js).initComponent(shoppingLists, translationErrors)shoppingListsselectedShoppingListIndex, selectedShoppingListisLoadingLists, isShoppingListChanging, isUpdatingopenPopup (per-list actions popover)isRenaming[]originalTitles[]draftTitles[]pendingDeleteIndexdebounceMapcancelTokenMap/shoppingLists/{alias}, auto-opens the matching shopping list.{ link, alt } using variant media first, then product media.selectItem using prepareListProducts(...)./.../shoppingLists (no alias)/.../shoppingLists/{alias}dimension1, dimension2) by:variant.dimension1ItemId / variant.dimension2ItemIdproduct.dimensionX.items[]isOutOfStock(item) returns true when the item's variant is missing or its quantityConstraints.additive.isValid is false.isNotifyState(item) returns true when Stock Alerts is active and the item's variant exists but is out of stock. The template then shows the shared Reusables/ProductAvailabilityAction "Notify me" button instead of the quantity stepper/add-to-cart button.hydrateItemsConstraints(items = []) hydrates personalized quantity constraints for the products of the opened list via servicesreusabledefault.hydrateProductConstraints(product), so the notify/cart decision reflects real per-visitor stock.hydrateItemsPrices(items = []) replaces Shopranos prices with ERP prices for products flagged pricePending, via servicesreusabledefault.hydrateProductPrices(product).pricePending per product, and logs a console error on failure.item.selected for all items in selectedShoppingList.newShoppingList input.promptmodalreusabledefault.isDataValid(modalData).servicesreusabledefault.createShoppingList({ title }).Alpine.store('shoppingLists').fetch() and replaces local shoppingLists.servicesreusabledefault.updateShoppingList(list).shoppingLists and the global Alpine.store('shoppingLists').list.deleteShoppingList(...).servicesreusabledefault.deleteShoppingList(alias).Alpine.store('shoppingLists').fetch().servicesreusabledefault.addToCart(...).response.data.lineFailures[] by mapping error types to translated messages.servicesreusabledefault.addMultipleToCart(variations).lineFailures similarly to single add.updateShoppingList service call.servicesreusabledefault.updateShoppingList(...), and syncs local + global state.servicesreusabledefault.updateShoppingList(this.selectedShoppingList).shoppingLists[listIndex].items to Alpine.store('shoppingLists').list.updateShoppingList(..., true) (debounced).#importFile and calls importShoppingList(alias, file).servicesreusabledefault.importShoppingList(alias, file).servicesreusabledefault.exportShoppingList(alias).$store.shoppingListslistfetch()$store.modalopen(...)close()$store.toastremoveAll()add(...)servicesreusabledefault):createShoppingList({ title })updateShoppingList(list)deleteShoppingList(alias)addToCart(productId, variantId, quantity, finalPrice, originalPrice, showToast)addMultipleToCart(variations)importShoppingList(alias, file)exportShoppingList(alias)Reusables/ShoppingLists/Default.liquidReusables/ShoppingLists/Default.jsReusables/ShoppingLists/Default.jsonComponents/Profile/Default.liquidReusables/PromptModal/Default.* (via $store.modal + promptmodalreusabledefault.isDataValid)shoppingLists array is kept in sync with Alpine.store('shoppingLists').list after create/update/delete/import.slice(0, -1) after fetching.