UNPKG

@ribajs/shopify

Version:

Shopify extension for Riba.js

226 lines (201 loc) 6 kB
import { Component, ScopeBase } from "@ribajs/core"; import { ShopifyCartLineItem, ShopifyCartObject, ShopifyCustomerAddress, ShopifyShippingRates, ShopifyShippingRatesNormalized, } from "../../interfaces/index.js"; import { ShopifyCartService } from "../../services/index.js"; import { getInputValue, hasChildNodesTrim } from "@ribajs/utils/src/dom.js"; export interface Scope extends ScopeBase { cart: ShopifyCartObject | null; shippingAddress: ShopifyCustomerAddress | null; estimateShippingRate: boolean; shippingRates: ShopifyShippingRatesNormalized; removeItem: ShopifyCartComponent["removeItem"]; increaseItem: ShopifyCartComponent["increaseItem"]; decreaseItem: ShopifyCartComponent["decreaseItem"]; getItem: ShopifyCartComponent["getItem"]; onItemQuantityChanged: ShopifyCartComponent["onItemQuantityChanged"]; pending: boolean; } export class ShopifyCartComponent extends Component { public static tagName = "shopify-cart"; static get observedAttributes(): string[] { return ["shipping-address", "estimate-shipping-rate"]; } protected requiredAttributes(): string[] { return []; } public scope: Scope = this.getScopeDefaults(); protected getScopeDefaults(): Scope { return { cart: ShopifyCartService.cart, shippingAddress: null, estimateShippingRate: false, shippingRates: [], removeItem: this.removeItem, increaseItem: this.increaseItem, decreaseItem: this.decreaseItem, getItem: this.getItem, onItemQuantityChanged: this.onItemQuantityChanged, pending: false, }; } protected set cart(cart: ShopifyCartObject | null) { // TODO check if cart values are changed this.scope.cart = cart; if (this.scope.shippingAddress && this.scope.estimateShippingRate) { ShopifyCartService.getShippingRates(this.scope.shippingAddress, true, { triggerOnChange: false, triggerOnComplete: false, triggerOnStart: false, }).then( ( shippingRates: ShopifyShippingRates | ShopifyShippingRatesNormalized, ) => { this.scope.shippingRates = shippingRates as ShopifyShippingRatesNormalized; }, ); } } protected get cart(): ShopifyCartObject | null { return this.scope.cart || null; } constructor() { super(); } protected connectedCallback() { super.connectedCallback(); this.init(ShopifyCartComponent.observedAttributes); } public removeItem(lineItem: ShopifyCartLineItem) { ShopifyCartService.change(lineItem.variant_id, 0) .then((cart: ShopifyCartObject) => { // this.cart = cart; return cart; }) .catch((error) => { console.error(error); }); } public increaseItem(lineItem: ShopifyCartLineItem) { lineItem.quantity++; ShopifyCartService.change(lineItem.variant_id, lineItem.quantity) .then((cart: ShopifyCartObject) => { // this.cart = cart; return cart; }) .catch((error) => { console.error(error); }); } public decreaseItem(lineItem: ShopifyCartLineItem) { lineItem.quantity--; if (lineItem.quantity < 0) { lineItem.quantity = 0; } ShopifyCartService.change(lineItem.variant_id, lineItem.quantity) .then((cart: ShopifyCartObject) => { return cart; }) .catch((error) => { console.error(error); }); } /** * Can be used for a changeable quantity input field * @example * ```html * <input type="number" rv-on-change="onItemQuantityChanged" rv-value="quantity" /> * ``` */ public onItemQuantityChanged( lineItem: ShopifyCartLineItem, event: Event, scope: Scope, htmlEl: HTMLInputElement, ) { if (!htmlEl) { console.warn("Input element not found"); return; } const newValue = Number(getInputValue(htmlEl)); if (newValue === lineItem.quantity) { return; } lineItem.quantity = newValue; ShopifyCartService.change(lineItem.variant_id, lineItem.quantity) .then((cart: ShopifyCartObject) => { this.debug("ShopifyCartService changed", cart); return cart; }) .catch((error) => { console.error(error); }); } /** * Get line item by id * @param id */ public getItem(id: number | string): ShopifyCartLineItem | null { id = Number(id); const item = this.scope.cart?.items.find((item) => Number(item.id) === id) || null; this.debug("getItem", id, item, this.scope.cart?.items); return item; } protected onCartRequestStart() { this.scope.pending = true; } protected onCartRequestComplete(cart: ShopifyCartObject) { if (cart) { this.cart = cart; } this.scope.pending = false; } protected async beforeBind() { await super.beforeBind(); ShopifyCartService.shopifyCartEventDispatcher.on( "ShopifyCart:request:start", this.onCartRequestStart, this, ); ShopifyCartService.shopifyCartEventDispatcher.on( "ShopifyCart:request:complete", this.onCartRequestComplete, this, ); } protected disconnectedCallback() { super.disconnectedCallback(); ShopifyCartService.shopifyCartEventDispatcher.off( "ShopifyCart:request:start", this.onCartRequestStart, this, ); ShopifyCartService.shopifyCartEventDispatcher.off( "ShopifyCart:request:complete", this.onCartRequestComplete, this, ); } protected async afterBind() { this.debug("afterBind", this.scope); if (!this.cart) { this.cart = await ShopifyCartService.get(); } await super.afterBind(); } protected async template() { // Only set the component template if there no childs already if (hasChildNodesTrim(this)) { return null; } else { const { default: template } = await import("./cart.component.html?raw"); return template; } } }