@salla.sa/twilight-components
Version:
Salla Web Component
198 lines (197 loc) • 8.73 kB
JavaScript
/*!
* Crafted with ❤ by Salla
*/
import { h, Host } from "@stencil/core";
import { getOrderEditProductMaxQuantity } from "./helpers";
/**
* @salla/ui-components
* The `salla-order-edit-item` component renders a single editable order item card
* with quantity controls, editable product options, and a remove button.
*/
export class SallaOrderEditItem {
constructor() {
this.quantityInput = null;
this.productOptions = null;
this.handleQuantityChange = (event) => {
const detail = event.detail;
const newQuantity = detail?.quantity ?? parseInt(event.target.value, 10);
if (isNaN(newQuantity) || newQuantity < 1)
return;
if (newQuantity === this.quantity)
return;
this.quantity = newQuantity;
this.emitUpdate(newQuantity);
};
this.handleOptionsChange = () => {
this.emitUpdate(this.quantity);
};
}
componentWillLoad() {
this.quantity = this.item?.quantity || 1;
}
handleItemChange(newItem) {
const newQuantity = newItem?.quantity || 1;
if (newQuantity === this.quantity)
return;
this.quantity = newQuantity;
this.quantityInput?.setValue?.(newQuantity, false);
}
get hasOptions() {
return (this.item.product?.options?.length || 0) > 0;
}
async getSelectedOptions() {
return (await this.productOptions?.getSelectedOptionsData?.()) || {};
}
async getOptionsData() {
return (await this.productOptions?.getOptionsData?.()) || this.item.product?.options || [];
}
async emitUpdate(quantity) {
const itemId = this.item?.id;
if (itemId == null)
return;
const detail = { itemId, quantity };
if (this.hasOptions) {
detail.options = await this.getSelectedOptions();
detail.optionDefinitions = await this.getOptionsData();
}
this.orderItemUpdated.emit(detail);
}
removeItem() {
const itemId = this.item?.id;
if (itemId == null)
return;
this.orderItemRemoved.emit({ itemId });
}
render() {
if (!this.item)
return null;
const product = this.item.product;
const productName = this.item.name || product?.name || '';
const imageUrl = product?.image?.url || '';
const imageAlt = product?.image?.alt || productName;
const productUrl = product?.url || '#';
const price = product?.price;
const maxQuantity = getOrderEditProductMaxQuantity(product);
const weightLabel = product?.weight_label;
const options = this.item.product?.options;
const optionsInstanceKey = `order-edit-item-${this.item.id}-${product?.id}`;
const quantityAttrs = { value: this.quantity };
if (maxQuantity) {
quantityAttrs.max = maxQuantity;
}
return (h(Host, null, h("div", null, h("div", { class: "s-order-edit-item-header" }, h("div", { class: "s-order-edit-item-media" }, imageUrl && (h("a", { href: productUrl }, h("img", { src: imageUrl, alt: imageAlt, class: "s-order-edit-item-image" }))), h("div", { class: "s-order-edit-item-details" }, h("h2", { class: "s-order-edit-item-name" }, h("a", { href: productUrl, class: "s-order-edit-item-link" }, productName)), price != null && (h("span", { class: "s-order-edit-item-price", innerHTML: salla.money(price) })), weightLabel && (h("p", { class: "s-order-edit-item-weight" }, salla.lang.getWithDefault('pages.products.weight', 'الوزن'), " ", weightLabel)))), h("salla-button", { type: "button", shape: "icon", size: "small", color: "danger", "aria-label": salla.lang.getWithDefault('common.elements.delete', 'حذف'), onClick: () => this.removeItem() }, h("i", { class: "sicon-cancel" }))), h("div", { class: "s-order-edit-item-quantity" }, h("h3", { class: "s-order-edit-item-quantity-label" }, salla.lang.getWithDefault('common.elements.quantity', 'الكمية')), h("div", { class: "s-order-edit-item-quantity-input" }, h("salla-quantity-input", { ref: el => (this.quantityInput = el), ...quantityAttrs, onChange: this.handleQuantityChange }))), this.hasOptions && (h("form", { class: "s-order-edit-item-options", onSubmit: e => e.preventDefault() }, h("salla-product-options", { ref: el => (this.productOptions = el), onChange: this.handleOptionsChange, "product-id": product.id, "unique-key": optionsInstanceKey, options: JSON.stringify(options), key: `${optionsInstanceKey}-options` }))))));
}
static get is() { return "salla-order-edit-item"; }
static get originalStyleUrls() {
return {
"$": ["salla-order-edit-item.scss"]
};
}
static get styleUrls() {
return {
"$": ["salla-order-edit-item.css"]
};
}
static get properties() {
return {
"item": {
"type": "unknown",
"attribute": "item",
"mutable": false,
"complexType": {
"original": "OrderEditItem",
"resolved": "OrderEditItem",
"references": {
"OrderEditItem": {
"location": "import",
"path": "./interfaces",
"id": "src/components/salla-order-edit/interfaces.ts::OrderEditItem"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Item data object"
},
"getter": false,
"setter": false
},
"orderId": {
"type": "any",
"attribute": "order-id",
"mutable": false,
"complexType": {
"original": "string | number",
"resolved": "number | string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Parent order ID (for API calls)"
},
"getter": false,
"setter": false,
"reflect": false
}
};
}
static get states() {
return {
"quantity": {}
};
}
static get events() {
return [{
"method": "orderItemUpdated",
"name": "orderItemUpdated",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when an item quantity or options are updated"
},
"complexType": {
"original": "{\n itemId: string | number;\n quantity: number;\n options?: OrderEditSelectedOptions;\n optionDefinitions?: OrderEditProductOption[];\n }",
"resolved": "{ itemId: string | number; quantity: number; options?: OrderEditSelectedOptions; optionDefinitions?: Option[]; }",
"references": {
"OrderEditSelectedOptions": {
"location": "import",
"path": "./interfaces",
"id": "src/components/salla-order-edit/interfaces.ts::OrderEditSelectedOptions"
},
"OrderEditProductOption": {
"location": "import",
"path": "./interfaces",
"id": "src/components/salla-order-edit/interfaces.ts::OrderEditProductOption"
}
}
}
}, {
"method": "orderItemRemoved",
"name": "orderItemRemoved",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when an item is successfully removed"
},
"complexType": {
"original": "{\n itemId: string | number;\n }",
"resolved": "{ itemId: string | number; }",
"references": {}
}
}];
}
static get watchers() {
return [{
"propName": "item",
"methodName": "handleItemChange"
}];
}
}