@ribajs/shopify
Version:
Shopify extension for Riba.js
289 lines (260 loc) • 7.94 kB
text/typescript
import { Component, ScopeBase } from "@ribajs/core";
import { hasChildNodesTrim } from "@ribajs/utils/src/dom.js";
import {
ShopifyCartLineItem,
ShopifyCartObject,
} from "../../interfaces/index.js";
import { ShopifyCartService } from "../../services/index.js";
export interface Scope extends ScopeBase {
id: ShopifyCartLineItem["id"];
title?: ShopifyCartLineItem["title"];
price?: ShopifyCartLineItem["id"];
linePrice?: ShopifyCartLineItem["line_price"];
lineNumber?: ShopifyCartLineItem["line_number"];
quantity: ShopifyCartLineItem["quantity"];
sku?: ShopifyCartLineItem["sku"];
grams?: ShopifyCartLineItem["grams"];
vendor?: ShopifyCartLineItem["vendor"];
properties?: ShopifyCartLineItem["properties"];
giftCard?: ShopifyCartLineItem["gift_card"];
url?: ShopifyCartLineItem["url"];
image?: ShopifyCartLineItem["image"];
handle?: ShopifyCartLineItem["handle"];
requiresShipping?: ShopifyCartLineItem["requires_shipping"];
productTitle?: ShopifyCartLineItem["product_title"];
productDescription?: ShopifyCartLineItem["product_description"];
productType?: ShopifyCartLineItem["product_type"];
productId?: ShopifyCartLineItem["product_id"];
variantTitle?: ShopifyCartLineItem["variant_title"];
variantOptions?: ShopifyCartLineItem["variant_options"];
variantId: ShopifyCartLineItem["variant_id"];
key?: ShopifyCartLineItem["key"];
remove: ShopifyCartItemComponent["remove"];
increase: ShopifyCartItemComponent["increase"];
decrease: ShopifyCartItemComponent["decrease"];
onInputQuantityChanged: ShopifyCartItemComponent["onInputQuantityChanged"];
pending: boolean;
}
export class ShopifyCartItemComponent extends Component {
public static tagName = "shopify-cart-item";
static get observedAttributes(): string[] {
return [
"id",
"title",
"price",
"line-price",
"line-number",
"quantity",
"sku",
"grams",
"vendor",
"properties",
"gift-card",
"url",
"image",
"handle",
"requires-shipping",
"product-title",
"product-description",
"product-type",
"product-id",
"variant-title",
"variant-options",
"variant-id",
"key",
];
}
protected requiredAttributes(): string[] {
return ["id", "variantId", "quantity"];
}
public scope: Scope = this.getScopeDefaults();
protected getScopeDefaults(): Scope {
return {
id: 0,
productId: 0,
variantId: 0,
properties: [],
quantity: 0,
remove: this.remove,
increase: this.increase,
decrease: this.decrease,
onInputQuantityChanged: this.onInputQuantityChanged,
pending: false,
};
}
constructor() {
super();
}
protected connectedCallback() {
super.connectedCallback();
this.init(ShopifyCartItemComponent.observedAttributes);
}
public remove() {
this.debug("decrease", this.scope.variantId);
ShopifyCartService.change(this.scope.variantId, 0)
.then((cart: ShopifyCartObject) => {
return cart;
})
.catch((error) => {
console.error(error);
});
}
/**
* Can be used for a quantity increase + button in the template
*/
public increase() {
this.debug("increase", this.scope.quantity);
this.scope.quantity++;
ShopifyCartService.change(this.scope.variantId, this.scope.quantity)
.then((cart: ShopifyCartObject) => {
return cart;
})
.catch((error) => {
console.error(error);
});
}
/**
* Can be used for a quantity decrease - button in the template
*/
public decrease() {
this.debug("decrease", this.scope.quantity);
this.scope.quantity--;
if (this.scope.quantity < 0) {
this.scope.quantity = 0;
}
ShopifyCartService.change(this.scope.variantId, this.scope.quantity)
.then((cart: ShopifyCartObject) => {
this.debug("ShopifyCartService changed", cart);
return cart;
})
.catch((error) => {
console.error(error);
});
}
/**
* Can be used for a changeable quantity input field
* @example
* ```html
* <input type="number" rv-on-change="onInputQuantityChanged" rv-value="quantity" />
* ```
*/
public onInputQuantityChanged() {
this.debug("onInputQuantityChanged");
ShopifyCartService.change(this.scope.variantId, this.scope.quantity)
.then((cart: ShopifyCartObject) => {
this.debug("ShopifyCartService changed", cart);
return cart;
})
.catch((error) => {
console.error(error);
});
}
protected onCartUpdate(cart: ShopifyCartObject) {
const item = this.getItemFromCart(cart);
if (!item) {
this.debug("Item not found, probably item was removed.");
super.remove(); // Remove element
return;
}
this.debug("update item from cart");
// this.scope.id = item.id;
this.scope.title = item.title;
this.scope.price = item.price;
this.scope.linePrice = item.line_price;
this.scope.lineNumber = item.line_number;
this.scope.quantity = item.quantity;
this.scope.sku = item.sku;
this.scope.grams = item.grams;
this.scope.vendor = item.vendor;
this.scope.properties = item.properties;
this.scope.giftCard = item.gift_card;
this.scope.url = item.url;
this.scope.image = item.image;
this.scope.handle = item.handle;
this.scope.requiresShipping = item.requires_shipping;
this.scope.productTitle = item.product_title;
this.scope.productDescription = item.product_description;
this.scope.productType = item.product_type;
this.scope.productId = item.product_id;
this.scope.variantTitle = item.variant_title;
this.scope.variantOptions = item.variant_options;
// this.scope.variantId = item.variant_id;
this.scope.key = item.key;
if (this.scope.quantity === 0) {
super.remove(); // Remove element
return;
}
}
protected getItemFromCart(cart: ShopifyCartObject) {
for (const item of cart.items) {
// Compare key
if (item.key && this.scope.key) {
if (item.key === this.scope.key) {
return item;
}
} else {
// Compare id and variantId
if (
item.id === this.scope.id &&
item.variant_id === this.scope.variantId
) {
return item;
}
}
}
return null;
}
protected async beforeBind() {
await super.beforeBind();
// const cart = await ShopifyCartService.get();
}
protected onCartRequestStart() {
this.scope.pending = true;
}
protected onCartRequestComplete(cart: ShopifyCartObject) {
this.debug("ShopifyCart:request:complete", cart);
this.onCartUpdate(cart);
this.scope.pending = false;
return cart;
}
protected async afterBind() {
this.debug("afterBind", this.scope);
ShopifyCartService.shopifyCartEventDispatcher.on(
"ShopifyCart:request:start",
this.onCartRequestStart,
this,
);
ShopifyCartService.shopifyCartEventDispatcher.on(
"ShopifyCart:request:complete",
this.onCartRequestComplete,
this,
);
const cart = await ShopifyCartService.get();
this.onCartUpdate(cart);
await super.afterBind();
}
protected disconnectedCallback() {
super.disconnectedCallback();
ShopifyCartService.shopifyCartEventDispatcher.off(
"ShopifyCart:request:start",
this.onCartRequestStart,
this,
);
ShopifyCartService.shopifyCartEventDispatcher.off(
"ShopifyCart:request:complete",
this.onCartRequestComplete,
this,
);
}
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-item.component.html?raw"
);
return template;
}
}
}