ShoppingLists reusable powers the Shopping Lists area inside the user profile. It supports:$store.modal) for confirmations and input flows.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[]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.