/*! Copyright (c) Safe As Milk. All rights reserved. */import{produce}from"immer";import{createStore}from"zustand";import plugins from"cart-plugins";const ALLOWED_STORE_KEYS=["cart","giftWrapping","latestAddedProduct","lineItemsBeingUpdated","noteBeingUpdated","productVariantsBeingAdded","recommendations"];class CartStore{#additionalFields={};#rootRoute;#store;static#instantiated=!1;constructor(fields={}){if(CartStore.#instantiated)throw new Error("Cart store instance already exists");CartStore.#instantiated=!0,this.#rootRoute=window.Shopify?.routes?.root??"/",this.#store=null,this.#additionalFields=Object.entries(fields).reduce((acc,[key,value])=>({...acc,...typeof value!="function"?{[key]:value}:{}}),{}),this.#init(),this.#store.getState().cart.total_price===0&&localStorage.removeItem("freeShippingAnimationShown")}static async getCart(){try{return await(await fetch(`${window.Shopify?.routes?.root??"/"}cart.js`)).json()}catch(e){throw new Error(`Could not get cart data: "${e}"`)}}static async clearCart(){try{return await(await fetch(`${window.Shopify?.routes?.root??"/"}cart/clear.js`,{method:"POST"})).json()}catch(e){throw new Error(`Could not clear cart: "${e}"`)}}static async addVariantsToCart(variants){if(!variants)throw new Error("Variant(s) must be specified");const items=(Array.isArray(variants)?variants:[variants]).map(item=>Object.keys(item).find(key=>key.includes("properties"))?Object.entries(item).reduce((newItem,[key,value])=>key.includes("properties")&&value!==""?{...newItem,properties:{...newItem.properties||{},[key.replace("properties[","").replace("]","")]:value}}:{...newItem,[key]:value},{}):item),response=await(await fetch(`${window.Shopify?.routes?.root??"/"}cart/add.js`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items})})).json();if(response.status)throw new Error(response.description);return response.items}static async changeCartLineItem(requestBody={},signal=null){const{id,quantity,properties}=requestBody;if(!id)throw new Error("Line item id must be present in request body");const response=await(await fetch(`${window.Shopify?.routes?.root??"/"}cart/change.js`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id,quantity,properties}),signal})).json();if(response.status)throw new Error(response.description);return response}static async updateCart(requestBody={},signal=null){if(!requestBody.hasOwnProperty("attributes")&&!requestBody.hasOwnProperty("updates")&&!requestBody.hasOwnProperty("note"))throw new Error("Cart 'attributes' or 'updates' must be specified");const response=await(await fetch(`${window.Shopify?.routes?.root??"/"}cart/update.js`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(requestBody),signal})).json();if(response.status)throw new Error(response.description);return response}getState(){return Object.fromEntries(Object.entries(this.#store.getState()).filter(([key])=>[...ALLOWED_STORE_KEYS,...Object.keys(this.#additionalFields)].includes(key)))}setState(field,value){if(field==="cart")throw new Error("Cannot set cart field directly");this.#store.getState().setFieldState(field,value)}subscribe(callback){if(!callback)throw new Error("Callback function must be provided");const filteredCallback=(state,prevState)=>{const filteredState=Object.fromEntries(Object.entries(state).filter(([key])=>[...ALLOWED_STORE_KEYS,...Object.keys(this.#additionalFields)].includes(key))),filteredPrevState=Object.fromEntries(Object.entries(prevState).filter(([key])=>[...ALLOWED_STORE_KEYS,...Object.keys(this.#additionalFields)].includes(key)));return callback.call(this,filteredState,filteredPrevState)};return this.#store.subscribe(filteredCallback)}async clear(){document.dispatchEvent(new CustomEvent("on:cart:loading",{detail:{type:"CLEAR"}}));try{const cart=await this.#store.getState().clear();return document.dispatchEvent(new CustomEvent("on:cart:loaded",{detail:{cart,type:"CLEAR"}})),cart}catch(error){throw document.dispatchEvent(new CustomEvent("on:cart:failed",{detail:{error,type:"CLEAR"}})),error}}async add(variants){document.dispatchEvent(new CustomEvent("on:cart:loading",{detail:{type:"ADD"}}));try{const cart=await this.#store.getState().add(variants),items=(Array.isArray(variants)?variants:[variants]).map(v=>({id:v.id,quantity:Number(v.quantity)}));return document.dispatchEvent(new CustomEvent("on:cart:loaded",{detail:{items,cart,type:"ADD"}})),cart}catch(error){throw document.dispatchEvent(new CustomEvent("on:cart:failed",{detail:{error,type:"ADD"}})),error}}async change(requestBody){const{id,quantity,properties}=requestBody;document.dispatchEvent(new CustomEvent("on:cart:loading",{detail:{type:"CHANGE"}}));try{const cart=await this.#store.getState().change(id,quantity,properties);return document.dispatchEvent(new CustomEvent("on:cart:loaded",{detail:{cart,type:"CHANGE"}})),cart}catch(error){throw document.dispatchEvent(new CustomEvent("on:cart:failed",{detail:{error,type:"CHANGE"}})),error}}async update(cartUpdates,operationId="cartUpdate"){const{attributes,updates,note}=cartUpdates;document.dispatchEvent(new CustomEvent("on:cart:loading",{detail:{type:"UPDATE"}}));try{const cart=await this.#store.getState().update({attributes,updates,note},operationId);return document.dispatchEvent(new CustomEvent("on:cart:loaded",{detail:{cart,type:"UPDATE"}})),cart}catch(error){throw document.dispatchEvent(new CustomEvent("on:cart:failed",{detail:{error,type:"UPDATE"}})),error}}async refresh(){document.dispatchEvent(new CustomEvent("on:cart:loading",{detail:{type:"REFRESH"}}));try{const cart=await this.#store.getState().refresh();return document.dispatchEvent(new CustomEvent("on:cart:loaded",{detail:{cart,type:"REFRESH"}})),cart}catch(error){throw document.dispatchEvent(new CustomEvent("on:cart:failed",{detail:{error,type:"REFRESH"}})),error}}async enableCartRecommendations(intent="related"){if(intent!=="related"&&intent!=="complementary")throw new Error('Recommendations intent must be set to either "related" or "complementary"');this.cartRecommendationsIntent=intent,await this.#store.getState().enableRecommendations(intent)}async disableCartRecommendations(){this.cartRecommendationsIntent=null,await this.#store.getState().disableRecommendations()}async resetLatestAddedProduct(){await this.#store.getState().resetLatestAddedProduct()}async resetVariantsBeingAdded(id=""){await this.#store.getState().resetVariantsBeingAdded(id)}async setGiftWrapping(enable=!0){return await this.#store.getState().setGiftWrapping(enable)}async syncGiftWrapping(){await this.#store.getState().syncGiftWrapping()}async updateGiftWrappingMessage(message=""){return this.#store.getState().updateGiftWrappingMessage(message)}async updateCartNote(note=""){return this.#store.getState().updateNote(note)}#init(){const initialCartDataJson=document.getElementById("cart-data"),initialCartData=initialCartDataJson?JSON.parse(initialCartDataJson.textContent):{},giftWrappingDataJson=document.getElementById("cart-gift-wrapping-data"),giftWrappingData={giftWrapping:{...giftWrappingDataJson?{...JSON.parse(giftWrappingDataJson.textContent)}:{productId:null,wrapIndividually:!1},statusBeingUpdated:!1,messageBeingUpdated:!1}};this.#store=createStore((set,get)=>({...this.#additionalFields,...giftWrappingData,lineItemsBeingUpdated:[],latestAddedProduct:null,noteBeingUpdated:!1,ongoingUpdates:{items:{},note:null,giftWrappingMessage:null},cart:initialCartData,recommendations:{enabled:!1,intent:"related",items:{}},productVariantsBeingAdded:[],setFieldState:async(field,value)=>{set(produce(draft=>{draft[field]=value}))},clear:async()=>{const cart=await CartStore.clearCart();return set(produce(draft=>{draft.lineItemsBeingUpdated=[],draft.latestAddedProduct=null,draft.cart={},draft.recommendations={},draft.productVariantsBeingAdded=[]})),cart},add:async variants=>{if(!variants)throw new Error("Variant(s) must be specified");set(produce(draft=>{draft.productVariantsBeingAdded=(Array.isArray(variants)?variants:[variants]).map(v=>v.id)}));let error=null;try{const addedItems=await CartStore.addVariantsToCart(variants);set(produce(draft=>{draft.latestAddedProduct=addedItems?addedItems[0]:null}))}catch(e){error=e}const prevItemsCount=get().cart.item_count,cart=await CartStore.getCart();if(set(produce(draft=>{draft.cart=cart})),prevItemsCount!==cart.item_count&&await get().updateGiftWrapping(),await get().updateRecommendations(),error)throw error;return get().cart},change:async(key,quantity,properties)=>{if(!key)throw new Error("Line item key must be specified");get().ongoingUpdates.items[key]&&(get().ongoingUpdates.items[key].abort(),set(produce(draft=>{draft.ongoingUpdates.items[key]=null})));const controller=new AbortController,{signal}=controller;set(produce(draft=>{get().lineItemsBeingUpdated.includes(key)||draft.lineItemsBeingUpdated.push(key),draft.ongoingUpdates.items[key]=controller}));let cart,error=null;try{await CartStore.changeCartLineItem({quantity,properties,id:key},signal)}catch(e){error=e}cart=await CartStore.getCart();const prevItemsCount=get().cart.item_count;if(cart={...cart,items:cart.items.filter(item=>item.quantity>0)},set(produce(draft=>{draft.lineItemsBeingUpdated=draft.lineItemsBeingUpdated.filter(k=>k!==key),draft.cart=cart,draft.ongoingUpdates.items[key]=null})),prevItemsCount!==cart.item_count&&await get().updateGiftWrapping(),await get().updateRecommendations(),error)throw error;return cart},update:async({attributes,updates,note},operationId)=>{if(!attributes&&!updates&&!note)throw new Error("At least one of 'attributes', 'updates' or 'note must be specified");if(operationId==="items")throw new Error("'items' operation id is reserved");get().ongoingUpdates[operationId]&&(get().ongoingUpdates[operationId].abort(),set(produce(draft=>{draft.ongoingUpdates[operationId]=null})));const controller=new AbortController,{signal}=controller;set(produce(draft=>{draft.ongoingUpdates[operationId]=controller})),await CartStore.updateCart({attributes,updates,note},signal);const cart=await CartStore.getCart();return set(produce(draft=>{draft.cart=cart,draft.ongoingUpdates[operationId]=null})),cart},refresh:async()=>{const cart=await CartStore.getCart(),prevItemsCount=get().cart.item_count;return set(produce(draft=>{draft.cart=cart})),prevItemsCount!==cart.item_count&&await get().updateGiftWrapping(),await get().updateRecommendations(),cart},enableRecommendations:async(intent="related")=>{get().recommendations.enabled||(set(produce(draft=>{draft.recommendations.enabled=!0,draft.recommendations.intent=intent})),await get().updateRecommendations())},disableRecommendations:async()=>{get().recommendations.enabled&&(set(produce(draft=>{draft.recommendations.enabled=!1})),await get().updateRecommendations())},resetLatestAddedProduct:()=>{set(produce(draft=>{draft.latestAddedProduct=null}))},resetVariantsBeingAdded:(variantId="")=>{set(produce(draft=>{draft.productVariantsBeingAdded=variantId?draft.productVariantsBeingAdded.filter(id=>id!==variantId):[]}))},setGiftWrapping:async(enable=!0)=>{const giftWrappingProductId=get().giftWrapping.productId;if(!giftWrappingProductId)return null;let cart;const oldCart=get().cart,giftWrappingIndividual=get().giftWrapping.wrapIndividually;if(enable){set(produce(draft=>{draft.giftWrapping.statusBeingUpdated=!0}));const savedGiftWrappingProductId=get().cart.attributes["_gift-wrapping-product-id"];await CartStore.updateCart({attributes:{...savedGiftWrappingProductId!==giftWrappingProductId?{"_gift-wrapping-product-id":giftWrappingProductId}:{},"gift-wrapping":enable,"gift-wrapping-message":""},updates:{[giftWrappingProductId]:giftWrappingIndividual?oldCart.items.reduce((nonGiftWrappingQuantity,item)=>item.variant_id!==giftWrappingProductId?nonGiftWrappingQuantity+item.quantity:nonGiftWrappingQuantity,0):1}}),cart=await CartStore.getCart(),set(produce(draft=>{draft.giftWrapping.statusBeingUpdated=!1,draft.cart=cart}))}else{let signal=null,key=null;const giftWrappingItem=get().cart.items.find(item=>item.variant_id===giftWrappingProductId);if(set(produce(draft=>{draft.giftWrapping.statusBeingUpdated=!0})),giftWrappingItem){key=giftWrappingItem.key,get().ongoingUpdates.items[key]&&(get().ongoingUpdates.items[key].abort(),set(produce(draft=>{draft.ongoingUpdates.items[key]=null})));const controller=new AbortController;signal=controller.signal,set(produce(draft=>{get().lineItemsBeingUpdated.includes(key)||draft.lineItemsBeingUpdated.push(key),draft.ongoingUpdates.items[key]=controller}))}await CartStore.updateCart({attributes:{"_gift-wrapping-product-id":null,"gift-wrapping":enable,"gift-wrapping-message":""},updates:{[giftWrappingProductId]:0}},signal),cart=await CartStore.getCart(),set(produce(draft=>{key&&(draft.lineItemsBeingUpdated=draft.lineItemsBeingUpdated.filter(k=>k!==key)),draft.giftWrapping.statusBeingUpdated=!1,draft.cart=cart}))}return cart},syncGiftWrapping:async()=>{const giftWrappingProductId=get().giftWrapping.productId,savedGiftWrappingProductId=get().cart.attributes["_gift-wrapping-product-id"];if(savedGiftWrappingProductId&&savedGiftWrappingProductId!==giftWrappingProductId){const savedGiftWrappingProduct=get().cart.items.find(item=>item.id===savedGiftWrappingProductId);if(savedGiftWrappingProduct){get().ongoingUpdates.items[savedGiftWrappingProduct.key]&&(get().ongoingUpdates.items[savedGiftWrappingProduct.key].abort(),set(produce(draft=>{draft.ongoingUpdates.items[savedGiftWrappingProduct.key]=null})));const controller=new AbortController,{signal}=controller;set(produce(draft=>{get().lineItemsBeingUpdated.includes(savedGiftWrappingProduct.key)||draft.lineItemsBeingUpdated.push(savedGiftWrappingProduct.key),draft.ongoingUpdates.items[savedGiftWrappingProduct.key]=controller})),await CartStore.updateCart({attributes:{"_gift-wrapping-product-id":null},updates:{[savedGiftWrappingProductId]:0}},signal);const cart=await CartStore.getCart();set(produce(draft=>{draft.lineItemsBeingUpdated=draft.lineItemsBeingUpdated.filter(k=>k!==savedGiftWrappingProduct.key),draft.giftWrapping.statusBeingUpdated=!1,draft.cart=cart}))}}if(!giftWrappingProductId)return;const giftWrappingEnabled=!!(get().cart.attributes["gift-wrapping"]!=="false"&&get().cart.attributes["gift-wrapping"]),giftWrappingIndividual=get().giftWrapping.wrapIndividually,giftWrappingItem=get().cart.items.find(item=>item.variant_id===giftWrappingProductId);!giftWrappingEnabled&&giftWrappingItem&&await get().setGiftWrapping(!1),giftWrappingEnabled&&!giftWrappingItem&&await get().setGiftWrapping(!0),giftWrappingEnabled&&giftWrappingItem&&giftWrappingIndividual&&giftWrappingItem.quantity===1&&await get().updateGiftWrapping(),giftWrappingEnabled&&giftWrappingItem&&!giftWrappingIndividual&&giftWrappingItem.quantity>1&&await get().updateGiftWrapping()},updateGiftWrapping:async()=>{const giftWrappingProductId=get().giftWrapping.productId;if(!giftWrappingProductId)return;const giftWrappingIndividual=get().giftWrapping.wrapIndividually,giftWrappingItem=get().cart.items.find(item=>item.variant_id===giftWrappingProductId);if(!giftWrappingItem||get().cart.items_count>1&&!giftWrappingIndividual&&giftWrappingItem)return;const{key}=giftWrappingItem;get().ongoingUpdates.items[key]&&(get().ongoingUpdates.items[key].abort(),set(produce(draft=>{draft.ongoingUpdates.items[key]=null})));const controller=new AbortController,{signal}=controller;set(produce(draft=>{get().lineItemsBeingUpdated.includes(key)||draft.lineItemsBeingUpdated.push(key),draft.ongoingUpdates.items[key]=controller}));let giftWrappingQuantity=giftWrappingIndividual?get().cart.items.reduce((nonGiftWrappingQuantity,item)=>item.variant_id!==giftWrappingProductId?nonGiftWrappingQuantity+item.quantity:nonGiftWrappingQuantity,0):1;giftWrappingItem&&get().cart.items.filter(i=>i.id!==giftWrappingProductId).length===0&&(giftWrappingQuantity=0);const giftWrappingAttributeUpdate=giftWrappingQuantity===0?{attributes:{"gift-wrapping":!1,"gift-wrapping-message":""}}:{};await CartStore.updateCart({...giftWrappingAttributeUpdate,updates:{[giftWrappingProductId]:giftWrappingQuantity}},signal);const cart=await CartStore.getCart();set(produce(draft=>{draft.lineItemsBeingUpdated=draft.lineItemsBeingUpdated.filter(k=>k!==key),draft.cart=cart}))},updateGiftWrappingMessage:async message=>{get().giftWrapping.messageBeingUpdated&&get().ongoingUpdates.giftWrappingMessage&&(get().ongoingUpdates.giftWrappingMessage.abort(),set(produce(draft=>{draft.ongoingUpdates.giftWrappingMessage=null,draft.giftWrapping.messageBeingUpdated=!1})));const controller=new AbortController,{signal}=controller;set(produce(draft=>{draft.ongoingUpdates.giftWrappingMessage=controller,draft.giftWrapping.messageBeingUpdated=!0})),await CartStore.updateCart({attributes:{"gift-wrapping-message":message}},signal);const cart=await CartStore.getCart();return set(produce(draft=>{draft.ongoingUpdates.giftWrappingMessage=null,draft.giftWrapping.messageBeingUpdated=!1,draft.cart=cart})),cart},updateNote:async note=>{get().noteBeingUpdated&&get().ongoingUpdates.note&&(get().ongoingUpdates.note.abort(),set(produce(draft=>{draft.ongoingUpdates.note=null,draft.noteBeingUpdated=!1})));const controller=new AbortController,{signal}=controller;set(produce(draft=>{draft.ongoingUpdates.note=controller,draft.noteBeingUpdated=!0})),await CartStore.updateCart({note},signal);const cart=await CartStore.getCart();return set(produce(draft=>{draft.ongoingUpdates.note=null,draft.noteBeingUpdated=!1,draft.cart=cart})),cart},updateRecommendations:async()=>{if(!get().recommendations.enabled)return;const weightDistribution="equal",{intent,items:existingRecommendations}=get().recommendations,newRecommendations={},existingRecommendationsIds=Object.keys(existingRecommendations),productIds=get().cart.items.reduce((ids,item)=>(!item.gift_card&&!ids.includes(item.product_id.toString())&&ids.push(item.product_id.toString()),ids),[]),remainingProductIds=existingRecommendationsIds.filter(productId=>productIds.includes(productId)),remainingRecommendations=remainingProductIds.reduce((recommendations,productId)=>({...recommendations,[productId]:existingRecommendations[productId]}),{}),newProductIds=productIds.filter(productId=>!existingRecommendationsIds.includes(productId));await Promise.all([...remainingProductIds.length{const recommendations=await(await fetch(`${this.#rootRoute}recommendations/products.json?product_id=${productId}&intent=${intent}`)).json();remainingProductIds.includes(productId)?remainingRecommendations[productId]=recommendations:newRecommendations[productId]=recommendations}));const finalRecommendations={...remainingRecommendations,...newRecommendations},calculateWeight=productId=>get().cart.items.filter(item=>item.product_id.toString()===productId).reduce((total,item)=>total+item.line_price,0)/get().cart.total_price;set(produce(draft=>{draft.recommendations.items=Object.keys(finalRecommendations).reduce((recommendations,productId)=>({...recommendations,[productId]:{weight:weightDistribution==="proportional"?calculateWeight(productId):1/get().cart.items.reduce((items,item)=>(items.includes(item.id)||items.push(item.id),items),[]).length,products:finalRecommendations[productId].products}}),{})}))}}))}}const Cart=new CartStore(plugins.reduce((allFields,plugin)=>({...allFields,...plugin.fields?plugin.fields:{}}),{}));Cart.syncGiftWrapping();export{CartStore};export default Cart; //# sourceMappingURL=/cdn/shop/t/100/assets/cart-store.js.map?v=118117448832980791111751575323