Vue Storefront is now Alokai! Learn More
Change Log

Change Log

5.0.0

Major Changes

  • CHANGED Changed minimum Node version from 16 to 18. The condition that was forcing the Node version to be lower than 19 is also removed.

Patch Changes

  • Updated dependencies:
    • @vsf-enterprise/bigcommerce-types@2.0.0

4.0.0

Major Changes

  • REMOVED impersonateCustomer method from available endpoints. It's an internal method and should not be used by the client.
  • CHANGED getOrder params are now obligatory.
- const orderResponse = await sdk.bigcommerce.getOrder();
+ const orderResponse = await sdk.bigcommerce.getOrder({ orderId: 123456 });

Patch Changes

  • FIXED Return empty response in getProductById when edges have length equal to zero.
  • ADDED Aliases for some methods:
    • addCoupon is now an alias for addCouponToCart method.
    • deleteCoupon is now an alias for deleteCartCoupon method.
  • CHANGED getCustomerSettings by adding optional params that allow to get customer settings by channel id.
const getCustomerSettingsResponse = await sdk.bigcommerce.getCustomerSettings({
  channel: 123456,
});

3.0.1

Patch Changes

  • CHANGED The package now builds using the built-in types of the node-fetch package, rather than using @types/node-fetch

3.0.0

Major Changes

  • CHANGED Endpoints interface. Previously, each endpoint contained context param, which is internal and shouldn't be exposed in the final interface. Now, Endpoints interface properties don't contain context param. If you need to use context param, you should use ApiMethods type.
- import { Endpoints } from '@vsf-enterprise/commercetools-api';
+ import { ApiMethods } from '@vsf-enterprise/commercetools-api';
  • CHANGED ContextualizedEndpoints type. Use Endpoints instead.
- import { ContextualizedEndpoints } from '@vsf-enterprise/commercetools-api';
+ import { Endpoints } from '@vsf-enterprise/commercetools-api';
  • REMOVED several interfaces that are not being used anymore:
    • GetProductsMethod
    • GetProductsWithFilterMethod
    • GetProductByIdMethod
    • GetProductsByIdMethod
    • GetProductsByCategoryMethod
    • GetCurrenciesMethod
    • GetFiltersMethod
    • GetCustomersMethod
    • CreateCustomerMethod
    • UpdateCustomerMethod
    • LoginCustomerMethod
    • LoginCustomerGqlMethod
    • LogoutCustomerMethod
    • UpdateCustomerFormFieldsMethod
    • GetCustomerSettingsMethod
    • GetProductReviewMethod
    • GetProductReviewCollectionMethod
    • GetCategoryMethod
    • GetCategoryTreeMethod
    • GetCategoryTreeGqlMethod
    • CreateProductReviewMethod
    • AddCartItemsMethod
    • RemoveCartItemMethod
    • UpdateCartItemMethod
    • CreateCartMethod
    • DeleteCartMethod
    • GetCartMethod
    • UpdateCartMethod
    • CreateWishlistMethod
    • GetAllWishlistsMethod
    • AddWishlistItemsMethod
    • RemoveWishlistItemMethod
    • DeleteWishlistMethod
    • ValidateCredentialsMethod
    • CreateCustomerAddressMethod
    • DeleteCustomerAddressMethod
    • GetCustomerAddressMethod
    • UpdateCustomerAddressMethod
    • GetOrdersMethod
    • GetOrderMethod
    • GetOrderProductsMethod
    • GetOrderShippingAddressesMethod
    • GetOrderByCartMethod
    • GetStoreMetaMethod
    • GetSiteMethod
    • GetChannelMethod
    • GetOrdersWithDetailsMethod
    • AddCouponMethod
    • DeleteCouponMethod
  • REMOVED createSite, createSiteRoute and createChannel methods.

2.13.4

Patch Changes

  • FIXED getProducts function was reworked to use id or id:in parameters exclusively. Previously, if only id was provided, the function was also using id:in parameter with default value which was causing issues with the set of products returned. Now, if id is provided, id:in parameter is not used, id has higher priority as it is more specific. If neither id nor id:in is provided, the function will return products that belong to the currently selected channel.

2.13.3

Patch Changes

  • FIXED Add missing minPurchaseQuantity and maxPurchaseQuantity properties to the product response. GraphQL endpoints getProductById and getProductsById was not returning the minPurchaseQuantity and maxPurchaseQuantity properties of a product. Fixed endpoints: getProductById, getProductsById, getProductsByCategory and getProductsWithFilter.

2.13.2

Patch Changes

  • CHANGED BigcommerceIntegrationContext interface. It has been standarized by removing req definition from it. Previously it was defined to include x-bigcommerce-channel-id in the request headers. Now, it's no longer necessary. It's not the breaking change as req.headers is still available in the context.
  • CHANGED IncomingHttpHeadersWithChannelId interface has been deprecated.
  • CHANGED IncommingMessageWithExtendedHeaders interface has been deprecated.

2.13.1

Patch Changes

  • fac25ca: FIXED Fixed an issue where product variants' defaultImage was not returned when using the getProductById method of the integration.

2.13.0

Minor Changes

  • cefe8e6: Add 'getCategoryTreeGql' method to fetch category tree from BigCommerce via GraphQL. The response is enriched with a 'productCount' field that contains the number of products in each category comparing to the REST getCategoryTree method.

Patch Changes

  • Updated dependencies cefe8e6
    • @vsf-enterprise/bigcommerce-types@1.5.0

2.12.0

Minor Changes

  • 93ebb8f: Added possibility to send cookie-independent requests via SDK to integration's GET endpoints in order to cache their response

Patch Changes

  • Updated dependencies 93ebb8f
    • @vsf-enterprise/bigcommerce-types@1.4.0

2.11.1

Patch Changes

  • Fix an issue where the 'path' GraphQL property was not properly mapped to its corresponding custom URL in the API response.

2.11.0

Minor Changes

  • Bumped @vue-storefront/middleware version to ^3.5.0 which introduces support for HTTP GET requests.

2.10.0

Minor Changes

  • Added "deleteCoupon" Endpoint Functionality:
    • Introduced a new API endpoint in the api package to facilitate coupon deletion.
    • Implemented a corresponding client method in the SDK package for seamless interaction.
    • Expanded the types package with necessary data structures to support this feature.

Patch Changes

  • Updated dependencies [bdfe3b3]:
    • @vsf-enterprise/bigcommerce-types@1.3.0

2.9.0

Minor Changes

  • Added "addCoupon" Endpoint Functionality:
    • Introduced a new API endpoint in the api package to facilitate coupon addition.
    • Implemented a corresponding client method in the SDK package for seamless interaction.
    • Expanded the types package with necessary data structures to support this feature.

Patch Changes

  • Updated dependencies [d5150d2]:
    • @vsf-enterprise/bigcommerce-types@1.2.0

2.8.2

Patch Changes

  • chore: updateCustomer add customer settings global login

2.8.1

Patch Changes

  • Fix an issue where validateCredentials() (used when updating customer and logging in) would immediately retry if the preceding request failed with 429 Too Many Requests. A fallback value of 3s before retry was added.
  • Export Endpoints as interface rather than type in TypeScript. After this change, adding new middleware methods to the integration typedefs using declare module should again be possible.

2.8.0

Minor Changes

  • feat: added secureOrderAPIs config for order apis

Patch Changes

  • Updated dependencies [5cbb3c7]:
    • @vsf-enterprise/bigcommerce-types@1.1.0

2.7.0

Minor Changes

  • add node18 (>= 16 < 19) support
  • Adjusted the bigcommerce integration to work with @vsf-enterprise/multistore

2.6.1

Patch Changes

  • Update vsf package versions to stable versions

2.6.0

Please note that from 2.6.0 imports such as import { CurrencyCode } from '@vsf-enterprise/bigcommerce-api/lib/types/graphql/schema' need to be changed so that they import types from @vsf-enterprise/bigcommerce-types.

Minor Changes

  • fixed JS error in the updateCustomerAddress endpoint where destructuring was made on a variable that can be undefined. added a new updateCustomerAddress method for the sdk
  • Applied the fix to disable the redirect to the unexisting route account.php, update login method to return customer token, added login and updateCart methods to the SDK
  • Created a new graphql login customer mutation endpoint which should not have a rate limiter set on BigCommerce and support high user traffic.
  • api package: fixed issue with unauthenticated users being able to create new carts for existing users, performLogin now returns a user token; sdk package: cart methods and integration tests
  • addCartItems method for the sdk, updated nock output, corrections for updateCart integration tests

Patch Changes

  • Removing the SSO URL fetch from the login mechanism as it was only used to keep the authenticated state on the checkout. The SSO login was also performed as part of the load of the embedded checkout, making the two calls redundant.
  • Updated the generated documentation for the BigCommerce, formatted and added the entire documentation for the sdk. Changed SDK methods from arrow functions to function declarations.
  • Updated dependencies
    • @vsf-enterprise/bigcommerce-types@1.0.0

2.5.0

Minor Changes

  • Created a new graphql login customer mutation endpoint which should not have a rate limiter set on BigCommerce and support high user traffic.

Patch Changes

  • Removing the SSO URL fetch from the login mechanism as it was only used to keep the authenticated state on the checkout. The SSO login was also performed as part of the load of the embedded checkout, making the two calls redundant.

2.5.0-rc.1

Minor Changes

  • Created a new graphql login customer mutation endpoint which should not have a rate limiter set on BigCommerce and support high user traffic.

2.4.7-rc.0

Patch Changes

  • 9ab80044: Removing the SSO URL fetch from the login mechanism as it was only used to keep the authenticated state on the checkout. The SSO login was also performed as part of the load of the embedded checkout, making the two calls redundant.

2.4.6

Patch Changes

  • It should now be possible to unset a user's phone number using updateCustomerProfile()
  • add getOrderWithDetails endpoint to middleware; it allows getting orders using cart ID
  • Update docs for getProductById to mention the include* params (modifiers, options), added in 2.4.4 and updated in 2.4.5
  • getProductsById (plural) now returns the first 50 custom fields of a product. Additionally, each variant now returns the first 50 product options (IN-3309)

All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.

2.4.4

In this release, we further improved on 2.4.3 by creating a new middleware method that makes sure:

  • tax is included in variant prices,
  • price data is properly fetched from BigCommerce,
  • product options are returned,
  • product modifiers are returned,
  • paginated product variants are returned (see variantAfter and variantLimit properties on getProductById() method)

To use the new method, call $bigcommerce.api.getProductById().

2.4.3

In this release, we have included fixes so that:

  • tax is included in product prices (but not variants),
  • retail price is returned for a product,
  • sale price is returned for a product.

Please use 2.4.4 instead of this release.

2.4.2

In this release, we fixed an issue with adding channel_id and origin_channel_id to create user requests when allow_global_logins is set to true.

2.4.1

In this release, we added a missing options and variants to the response of getProductsById API endpoint.

2.4.0 (2023-03-03)

In this release, we:

  • added multi-currency support,
  • added a guide describing multi-currency usage in BigCommerce integration.

Migration guide

To achieve the responses in specific currency:

  • add currencyCode param to the getProductsById API endpoint,
  • add currencyCode param to the getProductsWithFilter API endpoint,
  • add currencyCode param to the getProductsByCategory API endpoint,

To get the list of available currencies:

  • use the getCurrencies API endpoint
  • use the getChannel API endpoint with { include: 'currencies' } parameter.

Features

  • in-2432: added endpoint to update cart currency (#684) (2b03e64)
  • in-2514: create endpoint to get all currencies (#688) (e4e89b5)
  • remove theme from the monorepo (2806520)

2.3.0 (2023-01-04)

Introduction

In this release, we:

  • fixed a bug that keeps the user session active after logging out,
  • added an option to customize cookie_options by modifying middleware.config.js.

Migration guide

To customize cookie_options, simply add this information to middleware.config.js like this:

# middleware.config.js

module.exports = {
  integrations: {
    bigcommerce: {
      location: '@vsf-enterprise/bigcommerce-api/server',
      configuration: {
        ...
+        cookie_options: {
+          'customer-data': {
+            httpOnly: true,
+            secure: true,
+            sameSite: 'strict'
+          }
+        },
        // @deprecated
        secureCookies: process.env.NODE_ENV === 'production'
      }
    }
  }
};

The only available cookie to customize is customer-data and its options by default are set to:

{
  httpOnly: true,
  secure: true,
  sameSite: 'strict'
}

Bug Fixes

  • add api-extractor workaround for export as (#655) (031a254)
  • add rimraf to api-client devDependencies (5d1d52d)
  • in-1703: bigcommerce logout logic (#677) (51bc856)
  • in-1717: add missing variants (#669) (5c9476d)

Features

  • in-678: add caching to graph ql endpoint (#648) (8e2f3d0), closes #652
  • in-684: added integration test (#649) (37196e5)
  • separated middleware for multiple domains (fc2f616)

Reverts

  • Revert "chore(release): v2.2.1 (#671)" (7fd0eb2), closes #671

2.2.1 (2022-12-08)

Introduction

In this release, we fixed a bug with missing product information on GraphQL filtered product response.

Bug Fixes

  • add api-extractor workaround for export as (#655) (031a254)
  • add rimraf to api-client devDependencies (5d1d52d)
  • in-1717: add missing variants (#669) (5c9476d)

Features

Reverts

  • Revert "chore(release): v2.2.1 (#671)" (7fd0eb2), closes #671

2.2.0 (2022-11-29)

Introduction

In this release, we improved the backend performance for retrieving filters by adding caching on the server side.

Migration guide

Caching on the server side is a non-breaking change, migration describes only a way of caching customization.

middleware.config.js file

We added 2 properties to configuration that allow customization of the cache:

  • sdkSettings.graphqlMaxRetry - number of API call retries when there is no response from BigCommerce GraphQL API (3 retries by default),
  • stdTTL - cache standard Time To Live (1 day by default).
# middleware.config.js

module.exports = {
  integrations: {
    bigcommerce: {
      location: '@vsf-enterprise/bigcommerce-api/server',
      configuration: {
        sdkSettings: {
          logLevel: 'info',
          clientId: process.env.BIGCOMMERCE_API_CLIENT_ID,
          secret: process.env.BIGCOMMERCE_API_CLIENT_SECRET,
          callback: process.env.BIGCOMMERCE_API_URL,
          storeHash: process.env.BIGCOMMERCE_STORE_ID,
          accessToken: process.env.BIGCOMMERCE_API_ACCESS_TOKEN,
          guestToken: process.env.BIGCOMMERCE_STORE_GUEST_TOKEN,
          responseType: 'json',
          headers: { 'Accept-Encoding': '*' },
+         graphqlMaxRetry: Number(process.env.GRAPHQL_MAX_RETRY)
        },
        jwtTokenExpirationDays: 2,
+       stdTTL: 86400,
        secureCookies: process.env.NODE_ENV === 'production'
      }
    }
  }
};

Bug Fixes

  • add api-extractor workaround for export as (#655) (031a254)
  • add rimraf to api-client devDependencies (5d1d52d)

Features

2.1.0 (2022-11-03)

Introduction

In this release, we added a filtering feature on category page. To add this feature, we:

  • added a new useFilters composable,
  • added a new filter method to useProduct composable,
  • added a new FilterSidebar component,
  • modified usePagination composable to support filters pagination,
  • added new Sort by options
  • fixed an issue with getFacetsFromURL method of useUIHelpers composable,
  • added a filters guide showing how to implement filtering feature in existing projects.

Filters guide

All necessary information, including how to use new composables, methods and component can be found in our Filters guide.

Migration guide

New useFilters composable

To be able to load available filters, you should add useFilters compsable and its types to your composables/ directory.

Implementation:

// composables/useFilters/index.ts

import { useContext, ref } from "@nuxtjs/composition-api";
import { useLogger } from "~/composables/useLogger";
import { GetFiltersParameters, GraphQL } from "@vsf-enterprise/bigcommerce-api";
import { UseFilterErrors, UseFilterInterface } from "./types";

/**
 * @public
 *
 * Allows loading filters available for products.
 *
 * See the {@link UseFilterInterface} for a list of methods and values available in this composable.
 */
export function useFilters(): UseFilterInterface {
  const { $bigcommerce } = useContext();
  const { Logger } = useLogger();

  const loading = ref(false);
  const error = ref<UseFilterErrors>({
    load: null,
  });

  const load = async (
    params: GetFiltersParameters
  ): Promise<GraphQL.SearchProductFilterConnection> => {
    try {
      loading.value = true;
      error.value.load = null;

      return await $bigcommerce.api.getFilters(params);
    } catch (err) {
      Logger.error("useFilters/load", err);
      error.value.load = err;
    } finally {
      loading.value = false;
    }
  };

  return {
    load,
    loading,
    error,
  };
}

Types:

// composables/useFilters/types/index.ts

import { Ref } from "@nuxtjs/composition-api";
import { GraphQL, GetFiltersParameters } from "@vsf-enterprise/bigcommerce-api";

/**
 * `useFilters` composable errors.
 */
export interface UseFilterErrors {
  /**
   * Errors occurred during `load` action.
   */
  load: Error;
}

/**
 * Data and methods returned from the {@link useFilters|useFilters()} composable
 */
export interface UseFilterInterface {
  /**
   * Contains errors from the composable methods.
   */
  error: Ref<UseFilterErrors>;

  /**
   * Indicates whether any of the methods is in progress.
   */
  loading: Ref<boolean>;

  /**
   * load filters.
   */
  load: (
    params: GetFiltersParameters
  ) => Promise<GraphQL.SearchProductFilterConnection>;
}

Remember to export implementation from composables/index.ts and types from composables/types.d.ts files:

// composables/index.ts

...
+ export { useFilters } from './useFilters';
...
// composables/index.ts

...
+ export * from './useFilters/types';
...

New method of useProduct composable

To be able to filter products, you should add new filter method to useProduct composable.

// composables/useProduct/index.ts

+ const filter = async (
+   params: GetProductsWithFilterParameters
+ ): Promise<ProductsResponse> => {
+   try {
+     loading.value = true;
+     error.value.filter = null;
+
+     return await $bigcommerce.api.getProductsWithFilter(params);
+   } catch (err) {
+     Logger.error('useProduct/filter', err);
+     error.value.filter = err;
+   } finally {
+     loading.value = false;
+   }
+ };

and it's types:

// composables/useProduct/types/index.ts

export interface UseProductInterface {
  /**
   * Contains errors from the composable methods.
   */
  error: Ref<UseProductErrors>;

  /**
   * Indicates whether any of the methods is in progress.
   */
  loading: Ref<boolean>;

  /**
   * Searches for products.
   */
  search: (params: GetProductsParameters) => Promise<ProductsResponse>;

+  /**
+   * Filters products.
+   */
+  filter: (params: GetProductsWithFilterParameters) => Promise<ProductsResponse>
}

Modification of usePagination

Filtered products response includes pageInfo property that should be handeled by usePagination composable.

Implementation:

export const usePagination = (
  collection: PaginatedCollection
): UsePaginationInterface => {
  const { $config } = useContext();

  const defaultPagination = {
    currentPage: 1,
    totalPages: 1,
    totalItems: 1,
-    itemsPerPage: 1,
+    itemsPerPage: $config.theme?.itemsPerPage?.[0] || 1,
    pageOptions: $config.theme?.itemsPerPage
  };

  const pagination = computed(() =>
    getPagination(collection.value?.meta, defaultPagination)
  );

+  const pageInfo = computed(() => collection.value?.meta?.pageInfo);

  return {
    pagination,
+    pageInfo
  };
};

New types:

export interface UsePaginationInterface {
  /**
   * Computed pagination.
   */
  pagination: ComputedRef<GetPaginationResponse>;
+  /**
+   * Computed page info.
+   */
+  pageInfo: ComputedRef<MetaCollection['pageInfo']>;
}

Helpers:

export function getPagination(meta: MetaCollection, defaults: GetPaginationResponse): GetPaginationResponse {
  return {
    currentPage: meta?.pagination?.current_page ?? defaults.currentPage,
    totalPages: meta?.pagination?.total_pages ?? defaults.totalPages,
-    totalItems: meta?.pagination?.total ?? defaults.totalItems,
+    totalItems: meta?.pagination?.total ?? meta?.totalItems ?? defaults.totalItems,
    itemsPerPage: meta?.pagination?.per_page ?? defaults.itemsPerPage,
    pageOptions: defaults.pageOptions
  };
}

Using categorySlug of useUIHelpers composable

Previously, when loading the categorySlug from getFacetsFromURL, categorySlug was not reactive. This was

// Old usage

const { getFacetsFromURL } = useUIHelpers();
const { categorySlug } = getFacetsFromURL();

To make it reactive, we changed useUIHelpers implementation like this:

...

export function useUiHelpers(): UseUiHelpersInterface {
  const { $config } = useContext();
  const route = useRoute();
  const router = useRouter();

+  const categorySlug = computed(() => {
+    return `/${route.value.path.split('/c/').pop()}${
+      /\/$/.test(route.value.path) ? '' : '/'
+    }`;
+  });

  const getFiltersDataFromUrl = (onlyFilters) => {
    const { query } = route.value;

    return Object.keys(query)
      .filter((f) =>
        onlyFilters ? !nonFilters.includes(f) : nonFilters.includes(f)
      )
      .reduce(reduceFilters(query), {});
  };

  const getFacetsFromURL = () => {
    const { query } = route.value;
-    const categorySlug = `/${path.split('/c/').pop()}${
-      /\/$/.test(path) ? '' : '/'
-    }`;

    return {
-      categorySlug,
      page: parseInt(query.page as string, 10) || 1,
      sort: query.sort,
      direction: query.direction,
      filters: getFiltersDataFromUrl(true),
      itemsPerPage:
        parseInt(query.itemsperpage as string, 10) ||
        $config.theme?.itemsPerPage?.[0] ||
        20,
      term: query.term
    };
  };

  ...

+  const changeFilters = (filters: Record<string, string[]> = {}) => {
+    /**
+     * Remove empty filter values from query.
+     */
+    const query = Object.fromEntries(
+      Object.entries(filters).filter(([_, value]) => value.length > 0)
+    );
+
+    router.push({
+      query
+    });
+  };

+  const getFilterFromUrlAsArray = (filterFromUrl: QueryItem) => {
+    if (!filterFromUrl) {
+      return [];
+    }
+
+    return Array.isArray(filterFromUrl) ? filterFromUrl : [filterFromUrl];
+  };

  ...

  return {
+    categorySlug,
    getFacetsFromURL,
    changeSorting,
    changeFilters,
    changeItemsPerPage,
    formatDateString,
    getFilterFromUrlAsArray
  };
}

Sort by options

Filtering feature requires other values for sorting products, they can be modified in themeConfig.js file:

productsSortOptions: [

// Rest API sort-by options, used with `search` method of `useProduct` composable

-  { label: 'Latest', id: 1, value: { sort: 'id', direction: 'desc' } },
-  { label: 'Oldest', id: 2, value: { sort: 'id' } },
-  { label: 'Name: A to Z', id: 3, value: { sort: 'name' } },
-  {
-    label: 'Name: Z to A',
-    id: 4,
-    value: { sort: 'name', direction: 'desc' }
-  },

// GraphQL API sort-by options, used with `filter` method of `useProduct` composable

+  { label: 'Featured', id: 1, value: { sort: 'FEATURED' } },
+  { label: 'Relevance', id: 2, value: { sort: 'RELEVANCE' } },
+  { label: 'Best selling', id: 3, value: { sort: 'BEST_SELLING' } },
+  { label: 'Best reviewed', id: 4, value: { sort: 'BEST_REVIEWED' } },
+  { label: 'Newest', id: 5, value: { sort: 'NEWEST' } },
+  { label: 'Name: A to Z', id: 6, value: { sort: 'A_TO_Z' } },
+  { label: 'Name: Z to A', id: 7, value: { sort: 'Z_TO_A' } },
+  {
+    label: 'Price from high to low',
+    id: 8,
+    value: { sort: 'HIGHEST_PRICE' }
+  },
+  { label: 'Price from low to high', id: 9, value: { sort: 'LOWEST_PRICE' } }
],

New FilterSidebar component

You can start building your FilterSidebar component based on the example that we used in our template

<template>
  <LazyHydrate when-idle>
    <SfSidebar
      :visible="isFilterSidebarOpen"
      class="sidebar-filters"
      data-testid="mobile-sidebar"
      @close="toggleFilterSidebar"
    >
      <span v-if="filtersLoading" class="filters__loading-title">
        {{ $t('Loading filters') }}...
      </span>
      <template v-else-if="areFiltersAvailable && !filtersLoading">
        <SfAccordion class="filters-accordion smartphone-only">
          <SfAccordionItem
            key="filter-title-colors"
            header="Color"
            class="filters-accordion-item filters-accordion-item__colors"
            v-if="colors.length > 0"
          >
            <SfColor
              v-for="color of colors"
              :key="color.value"
              :color="color.value"
              :selected="filters.color === color.value"
              class="filters-item__colors"
              @click="setSelectedColor(color.value)"
            />
          </SfAccordionItem>
          <SfAccordionItem
            key="filter-title-sizes"
            header="Size"
            class="filters-accordion-item"
            v-if="sizes.length > 0"
          >
            <SfFilter
              v-for="size in sizes"
              :key="size.value"
              :label="size.value"
              :count="size.productCount"
              :selected="filters.size === size.value"
              class="filters-item__sizes"
              @change="setSelectedSize(size.value)"
            />
          </SfAccordionItem>
        </SfAccordion>

        <div v-if="colors.length > 0" class="filters-container desktop-only">
          <SfHeading
            :level="4"
            :title="$t('Color')"
            class="filters-title__colors"
          />
          <div class="filters-content__colors filters-content">
            <SfColor
              v-for="color of colors"
              :key="color.value"
              :color="color.value"
              :selected="filters.color.includes(color.value)"
              class="filters-item__colors"
              @click="setSelectedColor(color.value)"
            />
          </div>
        </div>

        <div v-if="sizes.length > 0" class="filters-container desktop-only">
          <SfHeading
            :level="4"
            :title="$t('Size')"
            class="filters-title__sizes"
          />
          <div class="filters-content__sizes filters-content">
            <SfFilter
              v-for="size in sizes"
              :key="size.value"
              :label="size.value"
              :count="size.productCount"
              :selected="filters.size.includes(size.value)"
              class="filters-item__sizes"
              @change="setSelectedSize(size.value)"
            />
          </div>
        </div>
      </template>
      <span v-else class="filters__empty-title">
        {{ $t('No filters are available now.') }}
      </span>
      <template #content-bottom>
        <div class="filters__buttons">
          <SfButton
            class="sf-button--full-width"
            :aria-label="$t('Apply filters')"
            @click="applyFilter"
          >
            {{ $t('Done') }}
          </SfButton>
          <SfButton
            class="sf-button--full-width filters__button-clear"
            :aria-label="$t('Clear filters')"
            @click="resetFilter"
          >
            {{ $t('Clear All') }}
          </SfButton>
        </div>
      </template>
    </SfSidebar>
  </LazyHydrate>
</template>

<script lang="ts">
import {
  computed,
  defineComponent,
  onMounted,
  reactive,
  ref,
  watch
} from '@nuxtjs/composition-api';
import LazyHydrate from 'vue-lazy-hydration';
import {
  SfAccordion,
  SfMenuItem,
  SfList,
  SfLoader,
  SfHeading,
  SfColor,
  SfSidebar,
  SfFilter,
  SfButton
} from '@storefront-ui/vue';
import { GraphQL } from '@vsf-enterprise/bigcommerce-api';
import { useUiHelpers, useUiState, useFilters } from '~/composables';
import { useCategoryTreeStore } from '~/stores';

export default defineComponent({
  components: {
    LazyHydrate,
    SfAccordion,
    SfFilter,
    SfList,
    SfHeading,
    SfMenuItem,
    SfLoader,
    SfColor,
    SfSidebar,
    SfButton
  },
  transition: 'fade',
  setup() {
    const { load, loading: filtersLoading } = useFilters();
    const {
      categorySlug,
      changeFilters,
      getFacetsFromURL,
      getFilterFromUrlAsArray
    } = useUiHelpers();
    const { isFilterSidebarOpen, toggleFilterSidebar } = useUiState();
    const categoryTreeStore = useCategoryTreeStore();
    const { filters: filtersFromUrl } = getFacetsFromURL();

    const filters = reactive<{
      color: string[];
      size: string[];
    }>({
      color: getFilterFromUrlAsArray(filtersFromUrl.color),
      size: getFilterFromUrlAsArray(filtersFromUrl.size)
    });
    const categorizedFilters = ref({});
    const categoryId = computed(() => {
      const category = categoryTreeStore.listOfRootBranches.find((item) =>
        item.url.includes(categorySlug.value)
      );

      if (!category) return null;

      return category.id;
    });

    async function fetchAvailableFilters() {
      if (!categoryId.value || categorizedFilters.value[categoryId.value]) {
        return;
      }

      const raw = await load({
        filters: {
          categoryEntityId: categoryId.value
        }
      });

      categorizedFilters.value = {
        ...categorizedFilters.value,
        [categoryId.value]: raw.edges.map((item) => item.node)
      };
    }

    onMounted(() => fetchAvailableFilters());

    watch(categorySlug, () => {
      fetchAvailableFilters();
    });

    const currentFilters = computed(() => {
      const currentCategoryFilters = categorizedFilters.value[categoryId.value];

      if (!currentCategoryFilters) {
        return { color: [], size: [] };
      }

      const allAttributesFilters: GraphQL.ProductAttributeSearchFilter[] =
        currentCategoryFilters.filter((item) => Boolean(item.attributes));

      return allAttributesFilters.reduce(
        (obj, item) => {
          obj[item.name.toLowerCase()] =
            item.attributes.edges.map((item) => item.node) ?? [];

          return obj;
        },
        { color: [], size: [] }
      );
    });

    const areFiltersAvailable = computed(
      () =>
        currentFilters.value.color.length > 0 ||
        currentFilters.value.size.length > 0
    );

    function resetFilter() {
      filters.color = [];
      filters.size = [];
      changeFilters();

      toggleFilterSidebar();
    }

    function applyFilter() {
      if (areFiltersAvailable.value) {
        changeFilters({ color: filters.color, size: filters.size });
      }

      toggleFilterSidebar();
    }

    function setSelectedColor(color: string) {
      if (filters.color.includes(color)) {
        filters.color = filters.color.filter((item) => color !== item);
      } else {
        filters.color.push(color);
      }
    }

    function setSelectedSize(size: string) {
      if (filters.size.includes(size)) {
        filters.size = filters.size.filter((item) => size !== item);
      } else {
        filters.size.push(size);
      }
    }

    return {
      filtersLoading,
      colors: computed(() => currentFilters.value.color),
      sizes: computed(() => currentFilters.value.size),
      filters,
      isFilterSidebarOpen,
      areFiltersAvailable,
      toggleFilterSidebar,
      applyFilter,
      resetFilter,
      setSelectedColor,
      setSelectedSize
    };
  }
});
</script>

<style lang="scss" scoped>
.sf-heading__title {
  text-align: left;
  display: block;
}

.list {
  &__item {
    .nuxt-link-exact-active {
      text-decoration: underline;
    }
  }
}

.filters {
  &__buttons {
    margin: var(--spacer-sm) 0;
  }
  &__button-clear {
    --button-background: var(--c-light);
    --button-color: var(--c-dark-variant);
    margin: var(--spacer-xs) 0 0 0;
  }
}

.filters-container {
  &:not(:first-of-type) {
    margin-top: var(--spacer-lg);
  }
}

.filters-content {
  margin-top: var(--spacer-sm);

  &__colors {
    display: flex;
  }
}

.filters-item {
  &__colors {
    margin: var(--spacer-xs);
    margin-top: 0;
  }
}

.filters-accordion-item {
  &__colors {
    ::v-deep .sf-accordion-item__content {
      display: flex;
    }
  }
}

::v-deep .sf-sidebar {
  &__aside {
    z-index: 3;
  }
}
</style>

Features

2.0.1 (2022-10-10)

Introduction

In this release, we fixed an issue with logging in on multiple domains with separated middleware.

Bug Fixes

Reverts

  • Revert "chore(in-3): added impersonate token (#628)" (c97586c), closes #628

2.0.0 (2022-09-09)

Alokai for BigCommerce v2.0.0 contains backward-incompatible changes.

Introduction

In this release, we:

  • added support for BigCommerce's multi-storefront feature (see Multi-storefront overview for more information),
  • changed the way of using and deploying our middleware (see Separate Middleware for more information),
  • reduced and simplified configuration steps of BigCommerce instance,
  • moved the logic of @vsf-enterprise/bigcommerce package to the theme composables,
  • reduced the code complexity and improved performance,
  • updated StorefrontUI version to v0.13.3

Backward-incompatible changes

Crucial breaking changes in the v2.0.0 compared to the v1.3.0 release.

What has changedHow it has changed
@vue-storefront/core packagePackage was removed from the dependences, features (that were being used in the integration) was moved to the theme.
Logger of @vue-storefront/core packageLoger is now available with usage of useLogger composable.
onSSR of @vue-storefront/core packageInstead of onSSR, now useAsync and useFetch from @nuxtjs/composition-api are being used.
sharedRef of @vue-storefront/core packageGlobal state management with sharedRef was replace by Pinia
RoutesRoutes looks the same, but are no longer defined in @vue-storefront/core package, they are included in nuxt.config.js file now.
@vsf-enterprise/bigcommerce package@vsf-enterprise/bigcommerce package was removed from the dependences, features and logic and interfaces has been changed and moved to the theme.
useCart of @vue-storefront/core packageuseCart has been moved to the theme, see useCart composable. for more information.
useCategory of @vue-storefront/core packageuseCategory has been merged with useCategoryTree, see useCategory composable. for more information.
useCategoryTree of @vue-storefront/core packageuseCategoryTree has been merged with useCategory, see useCategory composable. for more information.
useGuestWishlist of @vue-storefront/core packageuseGuestWishlist has been moved to the theme, see useGuestWishlist composable. for more information.
useProduct of @vue-storefront/core packageuseProduct has been moved to the theme, see useProduct composable for more information.
useReview of @vue-storefront/core packageuseReview has been moved to the theme, see useReview composable. for more information.
useUser of @vue-storefront/core packageuseUser has been moved to the theme, see useUser composable for more information.
useUserOrder of @vue-storefront/core packageuseUserOrder has been moved to the theme, see useOrder composable for more information.
useUserOrderByCart of @vue-storefront/core packageuseUserOrderByCart has been moved to the theme, see useSearchOrderByCart composable for more information.
useUserOrderProducts of @vue-storefront/core packageuseUserOrderProducts has been moved to the theme, see useOrderProducts composable for more information.
useUserShipping of @vue-storefront/core packageuseUserShipping has been moved to the theme, see useUserShipping composable for more information.
useWishlist of @vue-storefront/core packageuseWishlist has been moved to the theme, see useWishlist composable for more information.
useCartData composableCart helpers can now be imported from ~composables/useCart/helpers.
useCategoryData composableCategory helpers can now be imported from ~composables/useCategory/helpers.
useFacetData composableuseFacetData has been refactored and renamed to useSortOptions.
useOrderData composableOrder helpers can now be imported from ~composables/useOrder/helpers.
usePaginationData composableusePaginationData has been refactored and renamed to usePagination.
useProductData composableProduct helpers can now be imported from ~composables/useProductData/helpers
useReviewData composableReview helpers can now be imported from ~composables/useReview/helpers
useUserShippingData composableShipping helpers can now be imported from ~composables/useUserShipping/helpers
useUserShippingData composableShipping helpers can now be imported from ~composables/useUserShipping/helpers

Composables in theme may have different interfaces, despite of the same name. See List of composables for more information about the new interfaces.

Project configuration

See Configuring BigCommerce and Configuring Alokai for complex configuration information.

If you're migrating from v1.3.0, you need to adjust project configuration. The only breaking change here is adding new environment variables:

  • DEFAULT_CHANNEL_ID - Channel of the default storefront. This value was previously called BIGCOMMERCE_CHANNEL_ID
  • API_BASE_URL - Link to the API, see Separate Middleware for more information.

Following environment variables are not being used anymore:

  • BIGCOMMERCE_CHANNEL_ID
  • BIGCOMMERCE_DEVTOOLS_APP_CLIENT_ID
  • BIGCOMMERCE_DEVTOOLS_APP_CLIENT_SECRET
  • BIGCOMMERCE_STORE_URL

There are no breaking changes that require updates to your BigCommerce instance, however we encourage you to follow the steps from the Configure Content-Security-Policy Header guide, which is necessary to set up multi-storefront capabilities.

Bug Fixes

  • api on auth using deprecated format of customerId (#542) (802ff77)
  • api-client: missing comma (#451) (bef33ba)
  • bc-456: fix store meta and category jest and type issue (#450) (bddc055)
  • bc-515: develop order products are not visible for guest users (#516) (e04339a)
  • bc-585: default variant (#551) (7d73d5b)
  • BC-612: separate users by storefrotns (#581) (133c38e)
  • bc-639: add await for logout (#616) (14ca79f)
  • modify ChannelAssignment type and remove useReview from vsf-enterprise (#475) (f82cc91)

Features

  • add api-extractor for theme package (#525) (329f85c)
  • bc-324: added support for getChannel api (#434) (3008426)
  • bc-325: current storefront information (#457) (a36e699)
  • bc-329: modify products API + composable to meet multi-storefront requirements (#449) (688876e)
  • BC-331: modify category tree api to meet multi storefront requirements (#445) (1234a67)
  • BC-394: added API storefront seo settings (#444) (658396c)
  • bc-461: header for storefront (#455) (9afae03)
  • bc-476: get channel site (#477) (adedf49)
  • bc-480: added getCustomerSettings (#521) (7da3169)
  • middleware separation (#479) (3dc09c6)
  • separate middleware on 2.0.0 (7a68423)
  • setup script (#428) (393f68b)

1.3.0 (2022-05-24)

Bug Fixes

Features

Reverts

  • Revert "chore: enterprise repo setup (#389)" (#391) (e3e6293), closes #389 #391
  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.2.2 (2022-04-21)

Bug Fixes

Features

Reverts

  • Revert "chore: enterprise repo setup (#389)" (#391) (e3e6293), closes #389 #391
  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.2.1 (2022-04-14)

Bug Fixes

Features

Reverts

  • Revert "chore: enterprise repo setup (#389)" (#391) (e3e6293), closes #389 #391
  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.2.0 (2022-04-13)

Bug Fixes

Features

Reverts

  • Revert "chore: enterprise repo setup (#389)" (#391) (e3e6293), closes #389 #391
  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.1.0 (2022-03-31)

Bug Fixes

Features

Reverts

  • Revert "chore: enterprise repo setup (#389)" (#391) (e3e6293), closes #389 #391
  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.0.3 (2022-03-22)

Bug Fixes

Features

Reverts

  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.0.2 (2022-03-08)

Bug Fixes

Features

Reverts

  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.0.1 (2022-02-22)

Bug Fixes

Features

Reverts

  • Revert "feat: removing client ID from update customer requests (#296)" (#310) (dbbf1e8), closes #296 #310
  • Revert "feat: getting the client id from the cookie for formfields api's (#308)" (#309) (6a4b682), closes #308 #309
  • Revert "feat: use prettier for formatting (#280)" (#294) (e04cb07), closes #280 #294

1.0.0 (2022-02-04)

Bug Fixes

Features

1.0.0-beta.2 (2022-01-21)

Bug Fixes

  • add variant image to product images (#122) (9c43973)
  • authentication issues (#124) (796205a)
  • createcustomer endpoint: set customer data cookie on registration as well (#107) (592939b)
  • generate index.d.ts file in lib for api-client (#22) (9dbf026)
  • replace embedded checkout URL when the user is logged in (#164) (a1d4926)
  • ts build of api-client package (#73) (55329ab)
  • VBC-340, VBC-360: make wishlist working correctly (#123) (011bdc9)

Features

1.0.0-beta.1 (2022-01-17)

Bug Fixes

  • add variant image to product images (#122) (9c43973)
  • authentication issues (#124) (796205a)
  • createcustomer endpoint: set customer data cookie on registration as well (#107) (592939b)
  • generate index.d.ts file in lib for api-client (#22) (9dbf026)
  • ts build of api-client package (#73) (55329ab)
  • VBC-340, VBC-360: make wishlist working correctly (#123) (011bdc9)

Features

1.0.0-beta.0 (2022-01-14)

Bug Fixes

  • add variant image to product images (#122) (9c43973)
  • authentication issues (#124) (796205a)
  • createcustomer endpoint: set customer data cookie on registration as well (#107) (592939b)
  • generate index.d.ts file in lib for api-client (#22) (9dbf026)
  • ts build of api-client package (#73) (55329ab)
  • VBC-340, VBC-360: make wishlist working correctly (#123) (011bdc9)

Features