commercetools-8.x-1.2-alpha1/modules/commercetools_decoupled/components/blocks/filters-block/js/FiltersBlock.js

modules/commercetools_decoupled/components/blocks/filters-block/js/FiltersBlock.js
class FiltersBlock extends HTMLElement {
  constructor() {
    super();
    this.filtersForm = null;
    this.activeFilters = {};
    this.activeSorts = {};
    this.filterSubmitHandler = this.filterSubmitHandler.bind(this);
    this.applyProductListToFilters = this.applyProductListToFilters.bind(this);
    document.addEventListener(
      'DOMContentLoaded',
      this.applyProductListToFilters,
    );
    document.addEventListener(
      'ct.filters.change',
      this.applyProductListToFilters,
    );
  }

  connectedCallback() {
    const filtersForm = document.createElement('ct-filters-form');
    filtersForm.isLoading = true;
    this.append(filtersForm);

    this.componentConfig = window.commercetools.getComponentConfig(this);
    const url = new URL(window.location);
    this.setActiveFilters(url.searchParams);
    this.setActiveSorts(url.searchParams);
  }

  applyProductListConfiguration(configuration) {
    const facets = this.componentConfig.productListConfigs.filters
      .filter((filter) => {
        return ['facet', 'facet_count', 'custom'].includes(filter.widget_type);
      })
      .map((facetObj) => facetObj.graphql);

    configuration.facets = !configuration.facets
      ? facets
      : FiltersBlock.mergeFacetsByPath(configuration.facets, facets);

    // Apply sorting from URL if available.
    if (this.activeSorts && this.activeSorts?.sorts?.length > 0) {
      configuration.sorts = this.activeSorts.sorts;
    }

    if (!this.activeFilters || Object.keys(this.activeFilters).length === 0) {
      return configuration;
    }
    configuration.queryFilters = configuration.queryFilters || [];
    Object.keys(this.activeFilters).forEach((filterName) => {
      const filterValues = this.activeFilters[filterName];
      if (filterName === 'variants.price.centAmount') {
        const type = 'range';
        if (Array.isArray(filterValues)) {
          const range = {
            from: filterValues.from || '*',
            to: filterValues.to || '*',
          };
          configuration.queryFilters.push(
            window.commercetools.buildFilter(filterName, range, type),
          );
        }
      } else {
        configuration.queryFilters.push(
          window.commercetools.buildFilter(filterName, filterValues),
        );
      }
    });

    return configuration;
  }

  static mergeFacetsByPath(oldFacets, newFacets) {
    const facetMap = {};

    // Index existing old facets by path
    oldFacets.forEach((facet) => {
      const { path } = facet.model.terms;
      facetMap[path] = facet;
    });

    // Merge or overwrite with new facets
    newFacets.forEach((facet) => {
      const { path } = facet.model.terms;

      if (facetMap[path]) {
        const oldCount = facetMap[path].model.terms.countProducts;
        const newCount = facet.model.terms.countProducts;
        facet.model.terms.countProducts = oldCount || newCount;
      }

      facetMap[path] = facet;
    });

    return Object.values(facetMap);
  }

  applyProductListToFilters() {
    if (this.filtersForm) {
      this.filtersForm.setLoadingState('reload');
    }
    const url = new URL(window.location);
    this.setActiveFilters(url.searchParams);
    const response = window.commercetools.getProductListResult(
      this.componentConfig.productListIndex,
    );
    response.then((response) => {
      this.renderFiltersForm(response);
    });
  }

  setActiveFilters(params) {
    this.activeFilters = {};
    const paramName = window.commercetools.getParamNameByIndex(
      'filters',
      this.componentConfig.productListIndex,
    );

    // This matches all variations: filters[path], filters[path][subkey], filters[path][]
    const regex = new RegExp(`^${paramName}\\[(.+?)\\](?:\\[(.*)\\])?$`);

    params.forEach((filterValue, key) => {
      const match = key.match(regex);
      if (match) {
        const [, path, subkey] = match;

        // Initialize the path if it doesn't exist.
        if (!this.activeFilters[path]) {
          this.activeFilters[path] = [];
        }

        // Handle different cases based on subkey.
        if (subkey === '' || subkey === undefined) {
          // Case: filters[path] or filters[path][].
          this.activeFilters[path].push(filterValue);
        } else {
          // Case: filters[path][from], filters[path][to].
          if (!Array.isArray(this.activeFilters[path])) {
            this.activeFilters[path] = [];
          }
          if (!this.activeFilters[path][subkey]) {
            this.activeFilters[path][subkey] = '';
          }

          // Convert price values when setting them.
          const processedValue = window.commercetools.convertPrice(
            filterValue,
            this.filtersForm?.fractionDigits ?? 0,
            'multiply',
          );

          this.activeFilters[path][subkey] = processedValue;
        }
      }
    });

    return this.activeFilters;
  }

  setActiveSorts(params) {
    this.activeSorts = {};
    const paramName = window.commercetools.getParamNameByIndex(
      'sorts',
      this.componentConfig.productListIndex,
    );
    params.forEach((filterValue, key) => {
      if (paramName === key) {
        this.activeSorts[key] = filterValue;
      }
    });

    return this.activeSorts;
  }

  renderFiltersForm(response) {
    this.innerHTML = '';
    this.filtersForm = document.createElement('ct-filters-form');
    this.filtersForm.productListIndex = this.componentConfig.productListIndex;
    this.filtersForm.filters =
      this.componentConfig.productListConfigs.filters || [];
    this.filtersForm.activeFilters = this.activeFilters;
    this.filtersForm.filterSubmitHandler = this.filterSubmitHandler;
    this.filtersForm.response = response;

    // Get fraction digits from first product's master variant price.
    if (response?.products?.length > 0) {
      this.filtersForm.fractionDigits =
        response.products[0].masterVariant?.price?.fractionDigits ?? 0;
    }
    this.append(this.filtersForm);
  }

  filterSubmitHandler(e) {
    e.preventDefault();
    const newUrl = window.commercetools.generateNewUrl(e.currentTarget);
    this.setActiveFilters(newUrl.searchParams);
    this.setActiveSorts(newUrl.searchParams);
    newUrl.searchParams.delete('page');

    if (
      this.componentConfig.targetPage.trim() !== '' &&
      this.componentConfig.targetPage !== newUrl.pathname
    ) {
      newUrl.pathname = this.componentConfig.targetPage;
      window.location = newUrl.toString();
    }
    window.history.pushState(
      { path: newUrl.toString() },
      '',
      newUrl.toString(),
    );

    window.commercetools.resetProductListResult(
      this.componentConfig.productListIndex,
    );
    const changeEvent = new CustomEvent('ct.filters.change', {
      detail: {
        productListIndex: this.componentConfig.productListIndex,
        newUrl,
      },
    });
    document.dispatchEvent(changeEvent);

    const response = window.commercetools.getProductListResult(
      this.componentConfig.productListIndex,
    );
    response.then((response) => {
      this.renderFiltersForm(response);
    });
  }
}

customElements.define('ct-filters-block', FiltersBlock);

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

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