| | |
| | | window.jvbCheckout=class{constructor(t={}){this.config=t,this.isInitialized=!1,this.cartItems=new Map,this.checkout=document.querySelector("aside#cart"),this.provider=this.checkout?.querySelector("form")?.dataset.provider||"",this.isOpen="1"===this.config.isOpen||!1,this.isOpen=!0,this.isLoggedIn=this.config.is_logged_in||!1,this.userEmail=this.config.user_email||"",this.savedCards=[],this.selectedCardId=null,this.cartId=null,this.stepMultiplier=1,this.cache=new window.jvbCache("cart",{TTL:864e5}),this.a11y=window.jvbA11y,this.T=window.jvbTemplates,this.initCart(),this.checkout&&(this.initElements(),this.init(),this.initListeners(),this.defineTemplates(),this.isLoggedIn&&this.loadSavedCards()),this.isOpen||this.closeShop(),this.popup=window.jvbPopup.registerPopup({popup:this.checkout,toggle:this.ui.toggle.btn,name:"Cart",onOpen:this.maybeAddEmptyState.bind(this),onClose:this.toggleButton.bind(this)})}closeShop(){document.querySelectorAll("[data-add-to-cart]").forEach(t=>{t.querySelectorAll("button, input").forEach(t=>{t.disabled=!0,t.title="Sorry, we are currently closed."})})}async init(){throw new Error("init() must be implemented by subclass")}async processPayment(t){throw new Error("processPayment() must be implemented by subclass")}async submitToServer(t,e){throw new Error("submitToServer() must be implemented by subclass")}async loadSavedCards(){}async initCart(){let t=await this.cache.get("cart")??new Map;t.size>0&&(this.cartItems=t,this.updateToggle(),this.notifyRestoredCart())}saveCart(){this.updateTotal(),this.updateToggle(),this.cache.set("cart",this.cartItems)}clearCart(){for(let[t,e]of this.cartItems.entries())this.removeFromCart(t);this.cartItems.clear(),Array.from(this.ui.cart.table.children).forEach(t=>{"TBODY"===t.tagName&&t.remove()}),this.saveCart()}getCartId(){return this.cartId||(this.cartId=crypto.randomUUID(),this.cache.set("cart_id",this.cartId)),this.cartId}defineTemplates(){this.T.define("mainCartItem",{refs:{header:".header th"},setup({el:t,refs:e,manyRefs:a,data:i}){e.header.textContent=i.label,t.dataset.label=i.label,t.dataset.id=i.parentId}}),this.T.define("childCartItem",{refs:{quantity:".quantity",label:"label",price:"span.price",button:"[data-remove-from-cart]"},manyRefs:{},setup({el:t,refs:e,manyRefs:a,data:i}){[e.quantity.dataset.id,e.quantity.dataset.price,e.quantity.dataset.catalogId,e.label.textContent,e.price.textContent,e.button.dataset.id]=[i.id,i.price,i.catalogId||"",i.name,window.formatPrice(i.price),i.id]}}),this.T.define("emptyCart")}initElements(){this.restoreElement=!1,this.selectors={toggle:{btn:".toggle-cart",count:".toggle-cart .count",icon:".toggle-cart .icon"},panels:{checkout:{toggle:'button[data-tab="checkout"]',form:"#cart form"}},cart:{wrap:"#cart .cart-items",empty:"#cart .cart-items .empty",table:"#cart .cart-items table",body:"#cart .cart-items tbody",total:"#cart .cart-total",foot:{foot:"#cart tfoot",total:"#cart tfoot .total",tax:"#cart tfoot .tax"},grandTotal:"#cart .total span",tax:"#cart .cart-total .tax span"}},this.ui=window.uiFromSelectors(this.selectors),this.ui.cart.items=new Map,this.isOpen||(this.ui.toggle.btn.disabled=!0,this.ui.toggle.btn.title="Currently closed for online ordering"),this.checkoutForm=this.checkout.querySelector("form"),this.tabs=window.jvbTabs.registerTab(this.checkoutForm,{updateURL:!1})}initListeners(){this.clickHandler=this.handleClick.bind(this),this.keyHandler=this.handleEscape.bind(this),this.changeHandler=this.handleChange.bind(this),this.checkoutForm.addEventListener("submit",t=>this.handleFormSubmit(t)),document.addEventListener("click",this.clickHandler),document.addEventListener("change",this.changeHandler)}handleClick(t){if(window.targetCheck(t,"button")&&window.targetCheck(t,"div.quantity")){let e=window.targetCheck(t,"div.quantity");this.handleNumberClick(t,e)}else if(window.targetCheck(t,"[data-add-to-cart]")&&window.targetCheck(t,"button")){let e=window.targetCheck(t,"[data-add-to-cart]");this.handleAddToCart(e)}else if(window.targetCheck(t,"[data-remove-from-cart]")){let e=window.targetCheck(t,"[data-remove-from-cart]");this.handleRemoveFromCart(e)}else window.targetCheck(t,"[data-clear-cart]")?(this.clearCart(),document.querySelector(".restored")?.remove()):window.targetCheck(t,"[data-dismiss]")&&window.targetCheck(t,"[data-dismiss]").closest(".restored")?.remove()}handleChange(t){if(window.targetCheck(t,".quantity-input")){let e=t.target.closest(".quantity");t.target.value>0?this.handleAddToCart(e):this.handleRemoveFromCart(e)}}handleEscape(t){"Escape"===t.key?(this.restoreElement&&(this.restoreElement.classList.remove("show"),this.restoreElement=!1),this.stepMultiplier=1):t.ctrlKey&&t.shiftKey?this.stepMultiplier=Math.max(100*parseInt(this.stepMultiplier),1e3):t.shiftKey&&(this.stepMultiplier=Math.max(10*parseInt(this.stepMultiplier),1e3))}handleAddToCart(t){let e=t.dataset.id,a=parseFloat(t.dataset.price),i=parseInt(t.querySelector(".quantity input")?.value)??1,r=parseFloat(a*i);this.createItemElement(t);let s=this.determineParent(t),n={};this.cartItems.has(e)&&(n=this.cartItems.get(e));let o={post_id:e,name:n.name??t.dataset.name,label:n.label??s.dataset.label??"",parentId:n.parentId??s.dataset.id??"",price:a,quantity:i,total:r,catalog_id:n.catalogId??t.dataset.catalogId??""};this.cartItems.set(e,o),this.saveCart()}handleRemoveFromCart(t){if(console.log(t),confirm("This will remove this item from the cart. Continue?")){let e=t.dataset.id??t.id??!1;e||console.error("No ID found.."),this.removeFromCart(e),this.maybeAddEmptyState(),this.saveCart()}}removeFromCart(t){let e=this.findParentItem(t);if(e){let a=e.items.get(t);a.el.remove(),e.items.delete(t),a.reference&&(a.reference.value=0),0===e.items.size&&(console.log("Removing parent item"),e.el.remove(),this.ui.cart.items.delete(e.id))}this.cartItems.delete(t)}handleNumberClick(t,e){t.preventDefault();let a=0;if(t.target.closest(".increase")?a+=1:t.target.closest(".decrease")&&(a-=1),0!==a){let t=e.querySelector("input"),i=parseInt(t.step),r=""===t.value?0:parseInt(t.value);if(0===r&&a<0)return;let s=r+i*a*this.stepMultiplier;t.value=Math.max(s,0),t.dispatchEvent(new Event("change",{bubbles:!0})),this.handleNumberLimits(e)}}handleNumberLimits(t){let e=t.dataset.min,a=t.dataset.max,i=t.querySelector("input"),r=t.querySelector(".increase"),s=t.querySelector(".decrease"),n=parseInt(i.value);void 0!==e&&n<=e?(console.log("Resetting to minimum value"),i.value=e,s.disabled=!0):void 0!==a&&n>=a?(console.log("Resetting to maximum value"),i.value=a,r.disabled=!0):(r.disabled=!1,s.disabled=!1)}createItemElement(t){let e=this.maybeCreateCartItem(t),a=void 0===t.tagName?t.quantity:t.querySelector("input").value??1,i=void 0===t.tagName?t.price:t.dataset.price;e.quantity.value=a,e.total.textContent=window.formatPrice(a*i),e.reference&&(e.reference.value=a)}maybeCreateCartItem(t){let e={};if(void 0===t.tagName)e={id:String(t.post_id),name:t.name,price:t.price,catalogId:t.catalog_id||"",quantity:t.quantity,label:t.label,parentId:String(t.parentId)};else if(t.closest("#cart")){let e=t.dataset.id,a=this.findParentItem(e);if(a)return a.items.get(e);console.warn("Cart quantity changed but no existing row found for id:",e)}else{e={id:t.dataset.id,name:t.dataset.name,price:t.dataset.price,catalogId:t.dataset.catalogId||""};let a=this.determineParent(t);e.parentId=a.dataset.id??a.id,e.label=a.dataset.label??a.label}if(!this.ui.cart.items.has(e.parentId)){let t=this.T.create("mainCartItem",e);this.ui.cart.items.set(e.parentId,{el:t,id:e.parentId,label:e.label,items:new Map}),this.ui.cart.table.insertBefore(t,this.ui.cart.foot.foot)}let a=this.ui.cart.items.get(e.parentId);if(!a.items.has(e.id)){let t=this.T.create("childCartItem",e);a.items.set(e.id,{el:t,quantity:t.querySelector('[name="quantity"]'),total:t.querySelector(".total"),reference:document.querySelector(`.menu-items [data-id="${e.id}"] input`)}),a.el.append(t)}return a.items.get(e.id)}determineParent(t){if(void 0!==t.tagName)return this.parentFromHTML(t)}parentFromHTML(t){let e=t.closest(".menu-item");if(e)return e;let a=t.dataset.id;return this.findParentItem(a).el??!1}findParentItem(t){let e=!1;for(let[a,i]of this.ui.cart.items.entries())i.items.has(t)&&(e=this.ui.cart.items.get(a));return e}toggleButton(t=!1){this.ui.toggle.icon.hidden=t}maybeAddEmptyState(){this.toggleButton(!0),this.findEmpty(),0===this.cartItems.size?(this.ui.panels.checkout.toggle.disabled=!0,this.ui.panels.checkout.toggle.title="Add some things to your cart first!",this.ui.cart.empty.hidden=!1,this.ui.cart.table.hidden=!0,this.ui.cart.total.hidden=!0,this.a11y.announce("Nothing in Cart")):(this.ui.cart.empty.hidden=!0,this.ui.panels.checkout.toggle.disabled=!1,this.ui.cart.table.hidden=!1,this.ui.cart.total.hidden=!1,this.ui.panels.checkout.toggle.title="Checkout")}findEmpty(){this.ui.cart.empty||(this.ui.cart.empty=this.T.create("emptyCart"),this.ui.cart.wrap.append(this.ui.cart.empty))}notifyRestoredCart(){let t=window.getTemplate("restoredCart");document.body.append(t),t.classList.toggle("show"),this.restoreElement=t,this.cartItems.forEach(t=>{this.createItemElement(t)}),this.updateTotal()}updateToggle(){this.cartItems.size>0&&this.ui.toggle.btn.classList.contains("empty")&&this.ui.toggle.btn.classList.remove("empty"),0!==this.cartItems.size||this.ui.toggle.btn.classList.contains("empty")||this.ui.toggle.btn.classList.add("empty");let t=0;for(let[e,a]of this.cartItems.entries())t+=a.quantity;this.ui.toggle.count.textContent=0===this.cartItems.size?"":t}updateTotal(){let t=0;this.cartItems.forEach(e=>t+=e.total);let e=.05*t;window.eraseText(this.ui.cart.tax),window.eraseText(this.ui.cart.foot.tax),window.eraseText(this.ui.cart.foot.total),window.typeText(this.ui.cart.foot.tax,window.formatPrice(e)),window.typeText(this.ui.cart.grandTotal,window.formatPrice(t+e)),window.typeText(this.ui.cart.foot.total,window.formatPrice(t+e)),this.ui.cart.tax.classList.remove("typeText")}extractOrderData(t){const e=Array.from(this.cartItems.values()).map(t=>({catalog_id:t.catalog_id,quantity:String(t.quantity),price:t.price,note:t.note||""})),a=e.reduce((t,e)=>t+e.price*e.quantity,0);return{total:Math.round(100*a),items:e,customer:{email:this.isLoggedIn?this.userEmail:t.querySelector('[name="cart_email"]')?.value||"",name:t.querySelector('[name="cart_name"]')?.value||"",phone:t.querySelector('[name="cart_phone"]')?.value||""},note:t.querySelector('[name="special_instructions"]')?.value||"",pickup_time:t.querySelector('[name="pickup_time"]')?.value||""}}async handleFormSubmit(t){if(!this.isOpen)return;if(t.preventDefault(),!this.isInitialized)return void this.handleError("Checkout not initialized");const e=t.target,a=this.extractOrderData(e);try{window.jvbLoading?.showLoading?.("Processing payment...");const t=await this.processPayment(a);this.handleSuccess(t,e)}catch(t){this.handleError(t)}finally{window.jvbLoading?.hideLoading?.()}}trackOrder(t){this.orderId=t,this.scheduleOrderCheck(),this.checkout.querySelector("button[data-tab=order]").hidden=!1}scheduleOrderCheck(){window.debouncer.schedule("order",()=>this.checkOrderStatus(),3e4)}async checkOrderStatus(){const t=await fetch(`${this.config.api_url}order-status/${this.orderId}`,{headers:{"X-WP-Nonce":this.config.nonce}}),e=await t.json();"ready"!==e.status&&this.scheduleOrderCheck(),this.updateOrderStatus(e)}updateOrderStatus(t){this.checkout.querySelectorAll(".status-item").forEach(e=>{e.dataset.status===t.status&&e.classList.add("active")}),this.checkout.querySelector("#eta").textContent=t.eta||"In progress"}renderSavedCards(){const t=document.getElementById("saved-cards");if(!t||0===this.savedCards.length)return;const e=`\n\t\t\t<div class="saved-cards-section">\n\t\t\t\t<h4>Saved Payment Methods</h4>\n\t\t\t\t${this.savedCards.map(t=>`\n\t\t\t\t\t<label class="saved-card">\n\t\t\t\t\t\t<input type="radio" name="payment-method" value="saved" data-card-id="${t.id}">\n\t\t\t\t\t\t<span class="card-info">\n\t\t\t\t\t\t\t<strong>${t.card_brand}</strong> ending in ${t.last_4}\n\t\t\t\t\t\t\t<small>Exp: ${t.exp_month}/${t.exp_year}</small>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t`).join("")}\n\t\t\t\t<label class="saved-card">\n\t\t\t\t\t<input type="radio" name="payment-method" value="new" checked>\n\t\t\t\t\t<span>Use a new card</span>\n\t\t\t\t</label>\n\t\t\t</div>\n\t\t`;t.innerHTML=e,t.querySelectorAll('input[name="payment-method"]').forEach(t=>{t.addEventListener("change",t=>{const e="new"===t.target.value,a=document.getElementById("payment-container");a&&(a.style.display=e?"block":"none"),this.selectedCardId=e?null:t.target.dataset.cardId})})}handleSuccess(t,e){document.dispatchEvent(new CustomEvent("checkoutSuccess",{detail:{result:t,form:e,provider:this.provider}}));const a=e.dataset.successUrl||`/order-confirmation/?order=${t.order_id||t.wp_order_id}`;window.location.href=a}handleError(t){console.error(`${this.provider} checkout error:`,t),document.dispatchEvent(new CustomEvent("checkoutError",{detail:{error:t,provider:this.provider}})),window.jvbNotifications?.show?.(t.message||t||"Payment failed","error")}}; |
| | | window.jvbCheckout=class{constructor(t={}){this.config=t,this.isActive=!1,this.isInitialized=!1,this.cartItems=new Map,this.checkout=document.querySelector("aside#cart"),this.provider=this.checkout?.querySelector("form")?.dataset.provider||"",this.isOpen="1"===this.config.isOpen||!1,this.isOpen=!0,this.api=`${jvbSettings.api}${this.provider}/`,this.isLoggedIn=this.config.is_logged_in||!1,this.userEmail=this.config.user_email||"",this.savedCards=[],this.selectedCardId=null,this.cartId=null,this.stepMultiplier=1,this.cache=new window.jvbCache("cart",{TTL:864e5}),this.a11y=window.jvbA11y,this.T=window.jvbTemplates,this.initCart(),this.checkout&&(this.initElements(),this.init(),this.initListeners(),this.defineTemplates(),this.isLoggedIn&&this.isActive&&(console.log("Loading saved cards"),this.loadSavedCards())),this.isOpen||this.closeShop(),this.popup=window.jvbPopup.registerPopup({popup:this.checkout,toggle:this.ui.toggle.btn,name:"Cart",onOpen:this.maybeAddEmptyState.bind(this),onClose:this.toggleButton.bind(this)})}closeShop(){document.querySelectorAll("[data-add-to-cart]").forEach(t=>{t.querySelectorAll("button, input").forEach(t=>{t.disabled=!0,t.title="Sorry, we are currently closed."})})}async init(){throw new Error("init() must be implemented by subclass")}async processPayment(t){throw new Error("processPayment() must be implemented by subclass")}async submitToServer(t,e){throw new Error("submitToServer() must be implemented by subclass")}async loadSavedCards(){}async initCart(){let t=await this.cache.get("cart")??new Map;t.size>0&&(this.cartItems=t,this.updateToggle(),this.notifyRestoredCart())}saveCart(){this.updateTotal(),this.updateToggle(),this.cache.set("cart",this.cartItems)}clearCart(){for(let[t,e]of this.cartItems.entries())this.removeFromCart(t);this.cartItems.clear(),Array.from(this.ui.cart.table.children).forEach(t=>{"TBODY"===t.tagName&&t.remove()}),this.saveCart()}getCartId(){return this.cartId||(this.cartId=crypto.randomUUID(),this.cache.set("cart_id",this.cartId)),this.cartId}defineTemplates(){this.T.define("mainCartItem",{refs:{header:".header th"},setup({el:t,refs:e,manyRefs:a,data:i}){e.header.textContent=i.label,t.dataset.label=i.label,t.dataset.id=i.parentId}}),this.T.define("childCartItem",{refs:{quantity:".quantity",label:"label",price:"span.price",button:"[data-remove-from-cart]"},manyRefs:{},setup({el:t,refs:e,manyRefs:a,data:i}){[e.quantity.dataset.id,e.quantity.dataset.price,e.quantity.dataset.catalogId,e.label.textContent,e.price.textContent,e.button.dataset.id]=[i.id,i.price,i.catalogId||"",i.name,window.formatPrice(i.price),i.id]}}),this.T.define("emptyCart")}initElements(){this.restoreElement=!1,this.selectors={pass:"#magic-link-form a[data-tab]",toggle:{btn:".toggle-cart",count:".toggle-cart .count",icon:".toggle-cart .icon"},panels:{checkout:{toggle:'button[data-tab="checkout"]',form:"form#checkout"},order:{toggle:'button[data-tab="order"]'},login:{pass:'button[data-tab="login"]'}},cart:{wrap:"#cart .cart-items",empty:"#cart .cart-items .empty",table:"#cart .cart-items table",body:"#cart .cart-items tbody",total:"#cart .cart-total",foot:{foot:"#cart tfoot",total:"#cart tfoot .total",tax:"#cart tfoot .tax"}}},this.ui=window.uiFromSelectors(this.selectors),this.ui.cart.items=new Map,this.isOpen||(this.ui.toggle.btn.disabled=!0,this.ui.toggle.btn.title="Currently closed for online ordering"),this.tabs=window.jvbTabs.registerTab(this.checkout,{updateURL:!1})}initListeners(){this.clickHandler=this.handleClick.bind(this),this.keyHandler=this.handleEscape.bind(this),this.changeHandler=this.handleChange.bind(this),this.ui.panels.checkout.form?.addEventListener("submit",t=>this.handleFormSubmit(t)),document.addEventListener("click",this.clickHandler),document.addEventListener("change",this.changeHandler)}handleClick(t){if(t.target===this.ui.pass)t.preventDefault(),window.jvbTabs.switchTab("login",window.jvbTabs.getConfig(this.ui.panels.login.pass));else if(window.targetCheck(t,"button")&&window.targetCheck(t,"div.quantity")){let e=window.targetCheck(t,"div.quantity");this.handleNumberClick(t,e)}else if(window.targetCheck(t,"[data-add-to-cart]")&&window.targetCheck(t,"button")){let e=window.targetCheck(t,"[data-add-to-cart]");this.handleAddToCart(e)}else if(window.targetCheck(t,"[data-remove-from-cart]")){let e=window.targetCheck(t,"[data-remove-from-cart]");this.handleRemoveFromCart(e)}else window.targetCheck(t,"[data-clear-cart]")?(this.clearCart(),document.querySelector(".restored")?.remove()):window.targetCheck(t,"[data-dismiss]")&&window.targetCheck(t,"[data-dismiss]").closest(".restored")?.remove()}handleChange(t){if(window.targetCheck(t,".quantity-input")){let e=t.target.closest(".quantity");t.target.value>0?this.handleAddToCart(e):this.handleRemoveFromCart(e)}}handleEscape(t){"Escape"===t.key?(this.restoreElement&&(this.restoreElement.classList.remove("show"),this.restoreElement=!1),this.stepMultiplier=1):t.ctrlKey&&t.shiftKey?this.stepMultiplier=Math.max(100*parseInt(this.stepMultiplier),1e3):t.shiftKey&&(this.stepMultiplier=Math.max(10*parseInt(this.stepMultiplier),1e3))}handleAddToCart(t){let e=t.dataset.id,a=parseFloat(t.dataset.price),i=parseInt(t.querySelector(".quantity input")?.value)??1,s=parseFloat(a*i);this.createItemElement(t);let r=this.determineParent(t),n={};this.cartItems.has(e)&&(n=this.cartItems.get(e));let o={post_id:e,name:n.name??t.dataset.name,label:n.label??r.dataset.label??"",parentId:n.parentId??r.dataset.id??"",price:a,quantity:i,total:s,catalog_id:n.catalogId??t.dataset.catalogId??""};this.cartItems.set(e,o),this.saveCart()}handleRemoveFromCart(t){if(console.log(t),confirm("This will remove this item from the cart. Continue?")){let e=t.dataset.id??t.id??!1;e||console.error("No ID found.."),this.removeFromCart(e),this.maybeAddEmptyState(),this.saveCart()}}removeFromCart(t){let e=this.findParentItem(t);if(e){let a=e.items.get(t);a.el.remove(),e.items.delete(t),a.reference&&(a.reference.value=0),0===e.items.size&&(console.log("Removing parent item"),e.el.remove(),this.ui.cart.items.delete(e.id))}this.cartItems.delete(t)}handleNumberClick(t,e){t.preventDefault();let a=0;if(t.target.closest(".increase")?a+=1:t.target.closest(".decrease")&&(a-=1),0!==a){let t=e.querySelector("input"),i=parseInt(t.step),s=""===t.value?0:parseInt(t.value);if(0===s&&a<0)return;let r=s+i*a*this.stepMultiplier;t.value=Math.max(r,0),t.dispatchEvent(new Event("change",{bubbles:!0})),this.handleNumberLimits(e)}}handleNumberLimits(t){let e=t.dataset.min,a=t.dataset.max,i=t.querySelector("input"),s=t.querySelector(".increase"),r=t.querySelector(".decrease"),n=parseInt(i.value);void 0!==e&&n<=e?(console.log("Resetting to minimum value"),i.value=e,r.disabled=!0):void 0!==a&&n>=a?(console.log("Resetting to maximum value"),i.value=a,s.disabled=!0):(s.disabled=!1,r.disabled=!1)}createItemElement(t){let e=this.maybeCreateCartItem(t),a=void 0===t.tagName?t.quantity:t.querySelector("input").value??1,i=void 0===t.tagName?t.price:t.dataset.price;e.quantity.value=a,e.total.textContent=window.formatPrice(a*i),e.reference&&(e.reference.value=a)}maybeCreateCartItem(t){let e={};if(void 0===t.tagName)e={id:String(t.post_id),name:t.name,price:t.price,catalogId:t.catalog_id||"",quantity:t.quantity,label:t.label,parentId:String(t.parentId)};else if(t.closest("#cart")){let e=t.dataset.id,a=this.findParentItem(e);if(a)return a.items.get(e);console.warn("Cart quantity changed but no existing row found for id:",e)}else{e={id:t.dataset.id,name:t.dataset.name,price:t.dataset.price,catalogId:t.dataset.catalogId||""};let a=this.determineParent(t);e.parentId=a.dataset.id??a.id,e.label=a.dataset.label??a.label}if(!this.ui.cart.items.has(e.parentId)){let t=this.T.create("mainCartItem",e);this.ui.cart.items.set(e.parentId,{el:t,id:e.parentId,label:e.label,items:new Map}),this.ui.cart.table.insertBefore(t,this.ui.cart.foot.foot)}let a=this.ui.cart.items.get(e.parentId);if(!a.items.has(e.id)){let t=this.T.create("childCartItem",e);a.items.set(e.id,{el:t,quantity:t.querySelector('[name="quantity"]'),total:t.querySelector(".total"),reference:document.querySelector(`.menu-items [data-id="${e.id}"] input`)}),a.el.append(t)}return a.items.get(e.id)}determineParent(t){if(void 0!==t.tagName)return this.parentFromHTML(t)}parentFromHTML(t){let e=t.closest(".menu-item");if(e)return e;let a=t.dataset.id;return this.findParentItem(a).el??!1}findParentItem(t){let e=!1;for(let[a,i]of this.ui.cart.items.entries())i.items.has(t)&&(e=this.ui.cart.items.get(a));return e}toggleButton(t=!1){this.ui.toggle.icon.hidden=t}maybeAddEmptyState(){this.toggleButton(!0),this.findEmpty(),0===this.cartItems.size?(this.ui.panels.checkout.toggle.disabled=!0,this.ui.panels.checkout.toggle.title="Add some things to your cart first!",this.ui.cart.empty.hidden=!1,this.ui.cart.table.hidden=!0,this.a11y.announce("Nothing in Cart")):(this.ui.cart.empty.hidden=!0,this.ui.panels.checkout.toggle.disabled=!this.isActive,this.isActive||(this.ui.panels.checkout.toggle.title="We're experiencing technical difficulties. Try calling or coming in person."),this.ui.cart.table.hidden=!1,this.ui.panels.checkout.toggle.title="Checkout")}findEmpty(){this.ui.cart.empty||(this.ui.cart.empty=this.T.create("emptyCart"),this.ui.cart.wrap.append(this.ui.cart.empty))}notifyRestoredCart(){let t=window.getTemplate("restoredCart");document.body.append(t),t.classList.toggle("show"),this.restoreElement=t,this.cartItems.forEach(t=>{this.createItemElement(t)}),this.updateTotal()}updateToggle(){this.cartItems.size>0&&this.ui.toggle.btn.classList.contains("empty")&&this.ui.toggle.btn.classList.remove("empty"),0!==this.cartItems.size||this.ui.toggle.btn.classList.contains("empty")||this.ui.toggle.btn.classList.add("empty");let t=0;for(let[e,a]of this.cartItems.entries())t+=a.quantity;this.ui.toggle.count.textContent=0===this.cartItems.size?"":t}updateTotal(){let t=0;this.cartItems.forEach(e=>t+=e.total);let e=.05*t;window.eraseText(this.ui.cart.foot.tax),window.eraseText(this.ui.cart.foot.total),window.typeText(this.ui.cart.foot.tax,window.formatPrice(e)),window.typeText(this.ui.cart.foot.total,window.formatPrice(t+e)),this.ui.cart.foot.tax.classList.remove("typeText"),this.ui.cart.foot.total.classList.remove("typeText")}extractOrderData(t){const e=Array.from(this.cartItems.values()).map(t=>({catalog_id:t.catalog_id,quantity:String(t.quantity),price:t.price,note:t.note||""})),a=e.reduce((t,e)=>t+e.price*e.quantity,0);return{total:Math.round(100*a),items:e,customer:{email:this.isLoggedIn?this.userEmail:t.querySelector('[name="cart_email"]')?.value||"",name:t.querySelector('[name="cart_name"]')?.value||"",phone:t.querySelector('[name="cart_phone"]')?.value||""},note:t.querySelector('[name="special_instructions"]')?.value||"",pickup_time:t.querySelector('[name="pickup_time"]')?.value||""}}async handleFormSubmit(t){if(!this.isOpen)return;if(t.preventDefault(),!this.isInitialized)return void this.handleError("Checkout not initialized");const e=t.target,a=this.extractOrderData(e);try{const t=await this.processPayment(a);this.handleSuccess(t,e)}catch(t){this.handleError(t)}}trackOrder(t){this.orderId=t,this.scheduleOrderCheck(),this.ui.panels.order.toggle.hidden=!1}scheduleOrderCheck(){window.debouncer.schedule("order",()=>this.checkOrderStatus(),3e4)}async checkOrderStatus(){const t=await window.auth.fetch(`${this.api}order-status/${this.orderId}`),e=await t.json();"ready"!==e.status&&this.scheduleOrderCheck(),this.updateOrderStatus(e)}updateOrderStatus(t){this.checkout.querySelectorAll(".status-item").forEach(e=>{e.dataset.status===t.status&&e.classList.add("active")}),this.checkout.querySelector("#eta").textContent=t.eta||"In progress"}renderSavedCards(){const t=document.getElementById("saved-cards");if(!t||0===this.savedCards.length)return;console.log("Yup");const e=`\n\t\t\t<div class="saved-cards-section">\n\t\t\t\t<h4>Saved Payment Methods</h4>\n\t\t\t\t${this.savedCards.map(t=>`\n\t\t\t\t\t<label class="saved-card">\n\t\t\t\t\t\t<input type="radio" name="payment-method" value="saved" data-card-id="${t.id}">\n\t\t\t\t\t\t<span class="card-info">\n\t\t\t\t\t\t\t<strong>${t.card_brand}</strong> ending in ${t.last_4}\n\t\t\t\t\t\t\t<small>Exp: ${t.exp_month}/${t.exp_year}</small>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t`).join("")}\n\t\t\t\t<label class="saved-card">\n\t\t\t\t\t<input type="radio" name="payment-method" value="new" checked>\n\t\t\t\t\t<span>Use a new card</span>\n\t\t\t\t</label>\n\t\t\t</div>\n\t\t`;t.innerHTML=e,t.querySelectorAll('input[name="payment-method"]').forEach(t=>{t.addEventListener("change",t=>{const e="new"===t.target.value,a=document.getElementById("payment-container");a&&(a.style.display=e?"block":"none"),this.selectedCardId=e?null:t.target.dataset.cardId})})}handleSuccess(t,e){document.dispatchEvent(new CustomEvent("checkoutSuccess",{detail:{result:t,form:e,provider:this.provider}}));const a=e.dataset.successUrl||`/order-confirmation/?order=${t.order_id||t.wp_order_id}`;window.location.href=a}handleError(t){console.error(`${this.provider} checkout error:`,t),document.dispatchEvent(new CustomEvent("checkoutError",{detail:{error:t,provider:this.provider}})),window.jvbNotifications?.show?.(t.message||t||"Payment failed","error")}}; |