commercetools-8.x-1.2-alpha1/modules/commercetools_decoupled/js/molecules/AddToCartForm.js

modules/commercetools_decoupled/js/molecules/AddToCartForm.js
class AddToCartForm extends HTMLElement {
  connectedCallback() {
    const currentVariant = this.product.currentSku
      ? this.getCurrentVariant({
          sku: this.product.currentSku,
        })
      : this.product.masterVariant;
    const form = document.createElement('form');
    form.classList.add('add-to-cart-form');

    const attributes = this.getEnabledProductAttributes();

    // Sort attributes: attributes with more than one option come last
    attributes.sort((attr) => {
      return Object.keys(attr.options).length > 1 ? 1 : -1;
    });

    if (attributes.length) {
      const container = document.createElement('div');
      container.classList.add(
        'attributes',
        'border-top',
        'border-bottom',
        'pt-4',
        'pb-4',
        'mt-4',
        'mb-4',
      );

      attributes.forEach((attr) => {
        const attrContainer = document.createElement('div');
        attrContainer.classList.add(
          'd-flex',
          'justify-content-between',
          'w-100',
        );

        const label = document.createElement('span');
        label.classList.add('fw-medium', 'align-self-center');
        label.innerText = attr.label;
        attrContainer.append(label);

        const optionKeys = Object.keys(attr.options);
        if (optionKeys.length <= 1) {
          const value = document.createElement('span');
          const eventData = {
            key: attr.name,
            labelValue: attr.options[optionKeys[0]],
          };
          document.dispatchEvent(
            new CustomEvent('commercetools:productAttributeLabel', {
              detail: eventData,
            }),
          );
          value[
            attr.name === 'color' || attr.name === 'finish'
              ? 'innerHTML'
              : 'innerText'
          ] = eventData.labelValue || '-';
          attrContainer.classList.add('pt-1', 'pb-1');
          attrContainer.append(value);
        } else {
          const select = document.createElement('select');
          select.classList.add('form-select', 'w-50');
          select.name = attr.name;

          optionKeys.forEach((optionKey) => {
            const option = document.createElement('option');
            option.value = optionKey;
            option.textContent = attr.options[optionKey];
            option.selected =
              optionKey === currentVariant.attributes[attr.name].value;
            select.append(option);
          });
          attrContainer.append(select);
          attrContainer.classList.add('form-item');
        }
        container.append(attrContainer);
      });
      form.append(container);
    }

    const addToCart = document.createElement('input');
    addToCart.classList.add(
      'btn-lg',
      'button',
      'js-form-submit',
      'form-submit',
      'btn',
      'btn-primary',
    );
    addToCart.value = Drupal.t('Add to Cart');
    addToCart.type = 'submit';
    form.append(addToCart);

    // Update the product page and change the current sku according to args.
    form.addEventListener('change', () => {
      const formData = new FormData(form);
      const attrArgs = Object.fromEntries(formData.entries());
      const newVariant = this.getCurrentVariant({ attributes: attrArgs });
      this.product.currentSku = newVariant.sku;
      this?.handleSkuChange(newVariant.sku);

      const url = Drupal.url(
        `${drupalSettings.path.currentPath}?sku=${newVariant.sku}`,
      );
      window.history.pushState({ path: url }, '', url);
    });

    form.addEventListener('submit', async (e) => {
      e.preventDefault();
      const response = await window.commercetools.updateCart({
        actions: [{ addLineItem: { quantity: 1, sku: currentVariant.sku } }],
      });
      document.dispatchEvent(
        new CustomEvent('commercetoolsDecoupledCartUpdated', {
          detail: { totalItems: response.lineItems.length },
        }),
      );

      if (window.drupalSettings.commercetoolsDecoupled.cartPath) {
        const cartUrl = Drupal.url(
          window.drupalSettings.commercetoolsDecoupled.cartPath.substring(1),
        );

        new Drupal.Message().add(
          Drupal.t(
            `${this.product.name} added to <a href="${cartUrl}">cart</a>`,
          ),
        );
      } else {
        new Drupal.Message().add(
          Drupal.t('The cart page path is not configured.'),
          {
            type: 'error',
          },
        );
      }
    });

    this.appendChild(form);
  }

  getEnabledProductAttributes() {
    if (this.product.isLoading) {
      return [];
    }
    const variants = [this.product.masterVariant, ...this.product.variants];
    const productType = this.product.productType.key;
    const attributes =
      drupalSettings.commercetoolsDecoupled.attributes[productType] || [];

    return attributes.map((attr) => {
      const options = {};
      variants.forEach((variant) => {
        if (!variant.attributes?.[attr.name]) {
          return;
        }
        const { value, labelValue } = variant.attributes[attr.name];
        options[value] = labelValue;
      });

      return {
        name: attr.name,
        label: attr.label,
        options,
      };
    });
  }

  getCurrentVariant(variantArgs) {
    const variant = this.product.variants.find((v) => {
      if (variantArgs.sku && variantArgs.sku !== v.sku) {
        return false;
      }
      if (variantArgs.attributes) {
        return Object.keys(variantArgs.attributes).every((attrName) => {
          return (
            v.attributes[attrName].value === variantArgs.attributes[attrName]
          );
        });
      }
      return true;
    });

    return variant || this.product.masterVariant;
  }
}

customElements.define('ct-add-to-cart-form', AddToCartForm);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc