[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/GalleryLayoutSwitcher.tsx from the search-result VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useCallback } from 'react'
import classNames from 'classnames'
import { useCssHandles } from 'vtex.css-handles'
import { SearchPageContext } from 'vtex.search-page-context'

const { useSearchPageState, useSearchPageStateDispatch } = SearchPageContext

const CSS_HANDLES = ['galleryLayoutSwitcher'] as const

const GalleryLayoutSwitcher: React.FC = ({ children }) => {
  const handles = useCssHandles(CSS_HANDLES)
  const { selectedGalleryLayout, focusedGalleryLayout, galleryLayouts } =
    useSearchPageState()

  const dispatch = useSearchPageStateDispatch()

  const gallerySwitcherClasses = classNames(
    handles.galleryLayoutSwitcher,
    'flex flex-row bn'
  )

  const navigateWithKeys = useCallback(
    (e: React.KeyboardEvent<HTMLDivElement>) => {
      if (
        !galleryLayouts ||
        !(
          e.key === 'ArrowLeft' ||
          e.key === 'ArrowUp' ||
          e.key === 'ArrowRight' ||
          e.key === 'ArrowDown'
        )
      ) {
        return
      }

      const currentFocusedIndex = galleryLayouts.findIndex(
        layout =>
          layout.name === (focusedGalleryLayout ?? selectedGalleryLayout)
      )

      if (currentFocusedIndex === -1) {
        console.error(
          `No layout defined with name ${focusedGalleryLayout}. Check if there are unnecessary layout options with this name.`
        )
      }

      let newFocusedLayoutIndex = 0

      /**
       * - ArrowLeft moves the focus to the left until it reaches the beginning
       * - ArrowRight moves the focus to the right until it reaches the end
       * - ArrowUp loops through the items by moving the focus to the left,
       *   going to the end when it reaches the beginning
       * - ArrowDown loops through the items by moving the focus to the right,
       *   going to the beginning when it reaches the end
       */
      if (e.key === 'ArrowLeft') {
        newFocusedLayoutIndex = Math.max(0, currentFocusedIndex - 1)
      } else if (e.key === 'ArrowRight') {
        newFocusedLayoutIndex = Math.min(
          currentFocusedIndex + 1,
          galleryLayouts.length - 1
        )
      } else if (e.key === 'ArrowUp') {
        newFocusedLayoutIndex =
          (currentFocusedIndex - 1) % galleryLayouts.length

        if (newFocusedLayoutIndex < 0) {
          newFocusedLayoutIndex = galleryLayouts.length - 1
        }
      } else if (e.key === 'ArrowDown') {
        newFocusedLayoutIndex =
          (currentFocusedIndex + 1) % galleryLayouts.length
      }

      if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
        e.preventDefault()
      }

      dispatch({
        type: 'SET_FOCUS_GALLERY_LAYOUT',
        args: {
          focusedGalleryLayout: galleryLayouts[newFocusedLayoutIndex].name,
        },
      })
    },
    [galleryLayouts, dispatch, focusedGalleryLayout, selectedGalleryLayout]
  )

  return (
    // eslint-disable-next-line jsx-a11y/interactive-supports-focus
    <div
      className={gallerySwitcherClasses}
      role="radiogroup"
      aria-label="Search result layout"
      onKeyDown={navigateWithKeys}
    >
      {children}
    </div>
  )
}

export default GalleryLayoutSwitcher

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/SearchTitle.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import classNames from 'classnames'
import React from 'react'

import styles from './searchResult.css'
import { useSearchTitle } from './hooks/useSearchTitle'

const SHIPPING_MESSAGES = [
  'delivery',
  'pickup-all',
  'pickup-in-point',
  'pickup-nearby',
]

const SearchTitle = props => {
  const { breadcrumb: breadcrumbProp, wrapperClass = styles.galleryTitle } =
    props

  const title = useSearchTitle(breadcrumbProp || [], {
    matchFt: true,
    fallbackToLastName: true,
  })

  if (!title || SHIPPING_MESSAGES.includes(title)) {
    return null
  }

  return <h1 className={classNames(wrapperClass, 't-heading-1')}>{title}</h1>
}

export default SearchTitle

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/FetchMore.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
// eslint-disable-next-line no-restricted-imports
import { path } from 'ramda'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import { useSearchPage } from 'vtex.search-page-context/SearchPageContext'

import FetchMoreButton from './components/loaders/FetchMoreButton'
import LoadingSpinner from './components/loaders/LoadingSpinner'
import { PAGINATION_TYPE } from './constants/paginationType'
import { useFetchMore } from './hooks/useFetchMore'
import styles from './searchResult.css'

const FetchMore = ({ htmlElementForButton = 'button' }) => {
  const { pagination, searchQuery, maxItemsPerPage, page } = useSearchPage()
  const products = path(['data', 'productSearch', 'products'], searchQuery)
  const recordsFiltered = path(
    ['data', 'productSearch', 'recordsFiltered'],
    searchQuery
  )

  const fetchMore = path(['fetchMore'], searchQuery)
  const queryData = {
    query: path(['variables', 'query'], searchQuery),
    map: path(['variables', 'map'], searchQuery),
    orderBy: path(['variables', 'orderBy'], searchQuery),
    priceRange: path(['variables', 'selectedFacets'], searchQuery)?.find(
      facet => facet.key === 'priceRange'
    )?.value,
  }

  const { handleFetchMoreNext, loading, to, nextPage } = useFetchMore({
    page,
    recordsFiltered,
    maxItemsPerPage,
    fetchMore,
    products,
    queryData,
  })

  const isShowMore = pagination === PAGINATION_TYPE.SHOW_MORE

  if (isShowMore) {
    return (
      <div
        className={classNames(
          styles['buttonShowMore--layout'],
          'w-100 flex justify-center'
        )}
      >
        <FetchMoreButton
          products={products}
          to={to}
          recordsFiltered={recordsFiltered}
          onFetchMore={handleFetchMoreNext}
          loading={loading}
          showProductsCount={false}
          htmlElementForButton={htmlElementForButton}
          nextPage={nextPage}
        />
      </div>
    )
  }

  return <LoadingSpinner loading={loading} />
}

FetchMore.propTypes = {
  /* html element to render for fetch more button */
  htmlElementForButton: PropTypes.string,
}

FetchMore.schema = {
  title: 'admin/editor.search-result.fetch-more',
}

export default FetchMore

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/FilterNavigatorFlexible.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useMemo } from 'react'
import { useSearchPage } from 'vtex.search-page-context/SearchPageContext'
import { useDevice } from 'vtex.device-detector'

import FilterNavigator from './FilterNavigator'
import FilterNavigatorContext from './components/FilterNavigatorContext'
import styles from './searchResult.css'
import { sortFilterValues } from './utils/sortFilterValues'

const withSearchPageContextProps =
  Component =>
  // eslint-disable-next-line react/display-name
  ({
    layout,
    initiallyCollapsed,
    scrollToTop,
    maxItemsDepartment,
    maxItemsCategory,
    categoryFiltersMode,
    filtersTitleHtmlTag,
    truncateFilters,
    openFiltersMode,
    closeOnOutsideClick,
    appliedFiltersOverview,
    totalProductsOnMobile,
    fullWidthOnMobile,
    navigationTypeOnMobile,
    updateOnFilterSelectionOnMobile,
    drawerDirectionMobile,
    showClearByFilter,
    showClearAllFiltersOnDesktop,
    priceRangeLayout,
    facetOrdering = [],
    showQuantityBadgeOnMobile = false,
  }) => {
    const {
      searchQuery,
      map,
      params,
      priceRange,
      hiddenFacets,
      filters,
      showFacets,
      preventRouteChange,
      facetsLoading,
    } = useSearchPage()

    const { isMobile } = useDevice()

    const filtersFetchMore =
      searchQuery && searchQuery.facets && searchQuery.facets.facetsFetchMore
        ? searchQuery.facets.facetsFetchMore
        : undefined

    const facets =
      searchQuery && searchQuery.data && searchQuery.data.facets
        ? searchQuery.data.facets
        : {}

    const {
      brands,
      priceRanges,
      specificationFilters,
      categoriesTrees,
      queryArgs,
      deliveries,
    } = facets

    const sortedFilters = useMemo(
      () => sortFilterValues(filters, facetOrdering),
      [filters, facetOrdering]
    )

    if (showFacets === false || !map) {
      return null
    }

    return (
      <div
        className={`${styles['filters--layout']} ${
          layout === 'desktop' && isMobile ? 'w-100 mh5' : ''
        }`}
      >
        <FilterNavigatorContext.Provider value={queryArgs}>
          <Component
            preventRouteChange={preventRouteChange}
            brands={brands}
            params={params}
            priceRange={priceRange}
            priceRanges={priceRanges}
            specificationFilters={specificationFilters}
            tree={categoriesTrees}
            loading={facetsLoading}
            filters={sortedFilters}
            filtersFetchMore={filtersFetchMore}
            hiddenFacets={hiddenFacets}
            layout={layout}
            initiallyCollapsed={initiallyCollapsed}
            scrollToTop={scrollToTop}
            maxItemsDepartment={maxItemsDepartment}
            maxItemsCategory={maxItemsCategory}
            categoryFiltersMode={categoryFiltersMode}
            filtersTitleHtmlTag={filtersTitleHtmlTag}
            truncateFilters={truncateFilters}
            openFiltersMode={openFiltersMode}
            closeOnOutsideClick={closeOnOutsideClick}
            appliedFiltersOverview={appliedFiltersOverview}
            totalProductsOnMobile={totalProductsOnMobile}
            fullWidthOnMobile={fullWidthOnMobile}
            navigationTypeOnMobile={navigationTypeOnMobile}
            updateOnFilterSelectionOnMobile={updateOnFilterSelectionOnMobile}
            showClearByFilter={showClearByFilter}
            showClearAllFiltersOnDesktop={showClearAllFiltersOnDesktop}
            priceRangeLayout={priceRangeLayout}
            drawerDirectionMobile={drawerDirectionMobile}
            showQuantityBadgeOnMobile={showQuantityBadgeOnMobile}
            deliveries={deliveries}
          />
        </FilterNavigatorContext.Provider>
      </div>
    )
  }

export default withSearchPageContextProps(FilterNavigator)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/FilterNavigator.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import classNames from 'classnames'
import PropTypes from 'prop-types'
import React, { useMemo, Fragment, useState, useEffect } from 'react'
import ContentLoader from 'react-content-loader'
import { ExtensionPoint } from 'vtex.render-runtime'
import { useDevice } from 'vtex.device-detector'
import { useCssHandles, applyModifiers } from 'vtex.css-handles'
import { useSearchPage } from 'vtex.search-page-context/SearchPageContext'
// eslint-disable-next-line no-restricted-imports
import { flatten } from 'ramda'
import { FormattedMessage, useIntl } from 'react-intl'
import { Button } from 'vtex.styleguide'
import PostalCodeModal from 'vtex.shipping-option-components/PostalCodeModal'
import PickupModal from 'vtex.shipping-option-components/PickupModal'

import FilterSidebar from './components/FilterSidebar'
import SelectedFilters from './components/SelectedFilters'
import AvailableFilters from './components/AvailableFilters'
import DepartmentFilters from './components/DepartmentFilters'
import {
  facetOptionShape,
  paramShape,
  hiddenFacetsSchema,
} from './constants/propTypes'
import useFacetNavigation from './hooks/useFacetNavigation'
import FilterNavigatorTitleTag from './components/FilterNavigatorTitleTag'
import styles from './searchResult.css'
import { CATEGORIES_TITLE, shippingOptions } from './utils/getFilters'
import { newFacetPathName } from './utils/slug'
import { FACETS_RENDER_THRESHOLD } from './constants/filterConstants'

const CSS_HANDLES = [
  'filter__container',
  'filtersWrapper',
  'filtersWrapperMobile',
  'clearAllFilters',
]

const LAYOUT_TYPES = {
  responsive: 'responsive',
  desktop: 'desktop',
  phone: 'phone',
}

const DRAWER_DIRECTION_MOBILE = {
  drawerRight: 'drawerRight',
  drawerLeft: 'drawerLeft',
}

const getSelectedCategories = tree => {
  for (const node of tree) {
    if (!node.selected) {
      continue
    }

    if (node.children) {
      return [node, ...getSelectedCategories(node.children)]
    }

    return [node]
  }

  return []
}

const newNamedFacet = facet => {
  return { ...facet, newQuerySegment: newFacetPathName(facet) }
}

/**
 * Wrapper around the filters (selected and available) as well
 * as the popup filters that appear on mobile devices
 */
const FilterNavigator = ({
  priceRange,
  tree = [],
  specificationFilters = [],
  deliveries = [],
  priceRanges = [],
  brands = [],
  loading = false,
  filters = [],
  preventRouteChange = false,
  hiddenFacets = {},
  initiallyCollapsed = false,
  truncateFilters = false,
  layout = LAYOUT_TYPES.responsive,
  maxItemsDepartment = 8,
  maxItemsCategory = 8,
  categoryFiltersMode = 'default',
  filtersTitleHtmlTag = 'h5',
  scrollToTop = 'none',
  openFiltersMode = 'many',
  filtersFetchMore,
  closeOnOutsideClick = false,
  appliedFiltersOverview = 'hide',
  totalProductsOnMobile = 'hide',
  fullWidthOnMobile = false,
  navigationTypeOnMobile = 'page',
  updateOnFilterSelectionOnMobile = false,
  drawerDirectionMobile = DRAWER_DIRECTION_MOBILE.drawerLeft,
  showClearByFilter = false,
  showClearAllFiltersOnDesktop = false,
  priceRangeLayout = 'slider',
  showQuantityBadgeOnMobile = false,
}) => {
  const intl = useIntl()
  const { isMobile } = useDevice()
  const handles = useCssHandles(CSS_HANDLES)
  const [truncatedFacetsFetched, setTruncatedFacetsFetched] = useState(false)
  const [isPostalCodeModalOpen, setIsPostalCodeModalOpen] = useState(false)
  const [isPickupModalOpen, setisPickupModalOpen] = useState(false)

  const mobileLayout =
    (isMobile && layout === LAYOUT_TYPES.responsive) ||
    layout === LAYOUT_TYPES.mobile ||
    layout === LAYOUT_TYPES.phone

  const filtersDrawerDirectionMobile =
    DRAWER_DIRECTION_MOBILE[drawerDirectionMobile] ??
    DRAWER_DIRECTION_MOBILE.drawerLeft

  useEffect(() => {
    // This condition confirms if there are facets that still need fetching
    const needsFetching = !!filters.find(
      filter => filter.quantity > filter.facets.length
    )

    if (truncatedFacetsFetched && needsFetching && !loading) {
      filtersFetchMore({
        variables: {
          from: FACETS_RENDER_THRESHOLD,
          to: undefined, // to the end of the results
        },
        updateQuery: (prevResult, { fetchMoreResult }) => {
          if (!prevResult || !fetchMoreResult) {
            return
          }

          const prevFacets = prevResult.facets.facets
          const newFacets = fetchMoreResult.facets.facets
          const fullFacets = []

          for (let i = 0; i < prevFacets.length; i++) {
            const completeFacets = [
              ...prevFacets[i].facets,
              ...newFacets[i].facets,
            ]

            fullFacets.push({
              ...prevFacets[i],
              facets: completeFacets,
            })
          }

          return {
            facets: {
              ...prevResult.facets,
              facets: fullFacets,
            },
          }
        },
      })
    }
  }, [filters, filtersFetchMore, truncatedFacetsFetched, loading])

  const shipping = deliveries.map(delivery => ({
    ...delivery,
    facets: delivery.facets.map(facet => ({
      ...facet,
      name: shippingOptions[facet.name]
        ? intl.formatMessage({
            id: shippingOptions[facet.name],
          })
        : facet.name,
    })),
  }))

  const selectedFilters = useMemo(() => {
    const options = [
      ...specificationFilters.concat(shipping).map(filter => {
        return filter.facets.map(facet => {
          return {
            ...newNamedFacet({ ...facet, title: filter.name }),
            hidden: filter.hidden,
          }
        })
      }),
      ...brands,
      ...priceRanges,
    ]

    return flatten(options)
  }, [brands, priceRanges, specificationFilters, shipping]).filter(
    facet => facet.selected
  )

  const { searchQuery, showShippingFacet } = useSearchPage()
  const hasFiltersApplied = searchQuery?.variables?.selectedFacets?.length > 1

  const handleResetFilters = () => {
    navigateToFacet(selectedFilters, preventRouteChange, true)
  }

  const selectedCategories = getSelectedCategories(tree)
  const navigateToFacet = useFacetNavigation(
    useMemo(() => {
      return selectedCategories.concat(selectedFilters)
    }, [selectedFilters, selectedCategories]),
    scrollToTop
  )

  const filterClasses = classNames({
    'flex items-center justify-center flex-auto h-100': mobileLayout,
    dn: loading,
  })

  return (
    <Fragment>
      {loading && !mobileLayout ? (
        <div className="mv5">
          <ContentLoader
            style={{
              width: '230px',
              height: '320px',
            }}
            width="230"
            height="320"
            y="0"
            x="0"
          >
            <rect width="100%" height="1em" />
            <rect width="100%" height="8em" y="1.5em" />
            <rect width="100%" height="1em" y="10.5em" />
            <rect width="100%" height="8em" y="12em" />
          </ContentLoader>
        </div>
      ) : null}

      {mobileLayout ? (
        <div className={styles.filters}>
          <div className={`${filterClasses} ${handles.filtersWrapperMobile}`}>
            <FilterSidebar
              selectedFilters={selectedCategories.concat(selectedFilters)}
              filters={filters}
              tree={tree}
              priceRange={priceRange}
              preventRouteChange={preventRouteChange}
              navigateToFacet={navigateToFacet}
              appliedFiltersOverview={appliedFiltersOverview}
              totalProductsOnMobile={totalProductsOnMobile}
              fullWidth={fullWidthOnMobile}
              navigationType={navigationTypeOnMobile}
              initiallyCollapsed={initiallyCollapsed}
              truncateFilters={truncateFilters}
              truncatedFacetsFetched={truncatedFacetsFetched}
              setTruncatedFacetsFetched={setTruncatedFacetsFetched}
              categoryFiltersMode={categoryFiltersMode}
              loading={loading}
              updateOnFilterSelectionOnMobile={updateOnFilterSelectionOnMobile}
              showClearByFilter={showClearByFilter}
              priceRangeLayout={priceRangeLayout}
              filtersDrawerDirectionMobile={filtersDrawerDirectionMobile}
              showQuantityBadgeOnMobile={showQuantityBadgeOnMobile}
              onOpenPostalCodeModal={() => setIsPostalCodeModalOpen(true)}
              onOpenPickupModal={() => setisPickupModalOpen(true)}
            />
          </div>
        </div>
      ) : (
        <Fragment>
          <div className={`${filterClasses} ${handles.filtersWrapper}`}>
            <div
              className={`${applyModifiers(
                handles.filter__container,
                'title'
              )} bb b--muted-4`}
            >
              <FilterNavigatorTitleTag
                filtersTitleHtmlTag={filtersTitleHtmlTag}
              />
            </div>
            <SelectedFilters
              filters={selectedFilters}
              preventRouteChange={preventRouteChange}
              navigateToFacet={navigateToFacet}
              onOpenPostalCodeModal={() => setIsPostalCodeModalOpen(true)}
              onOpenPickupModal={() => setisPickupModalOpen(true)}
              showShippingFacet={showShippingFacet}
            />
            <DepartmentFilters
              title={CATEGORIES_TITLE}
              tree={tree}
              isVisible={!hiddenFacets.categories}
              onCategorySelect={navigateToFacet}
              preventRouteChange={preventRouteChange}
              maxItemsDepartment={maxItemsDepartment}
              maxItemsCategory={maxItemsCategory}
              categoryFiltersMode={categoryFiltersMode}
            />
            <AvailableFilters
              filters={filters}
              priceRange={priceRange}
              preventRouteChange={preventRouteChange}
              initiallyCollapsed={initiallyCollapsed}
              navigateToFacet={navigateToFacet}
              truncatedFacetsFetched={truncatedFacetsFetched}
              setTruncatedFacetsFetched={setTruncatedFacetsFetched}
              truncateFilters={truncateFilters}
              openFiltersMode={openFiltersMode}
              closeOnOutsideClick={closeOnOutsideClick}
              appliedFiltersOverview={appliedFiltersOverview}
              showClearByFilter={showClearByFilter}
              priceRangeLayout={priceRangeLayout}
              scrollToTop={scrollToTop}
              onOpenPostalCodeModal={() => setIsPostalCodeModalOpen(true)}
              onOpenPickupModal={() => setisPickupModalOpen(true)}
            />
            {showClearAllFiltersOnDesktop && hasFiltersApplied && (
              <div
                className={`${applyModifiers(
                  handles.filter__container,
                  'clearAllFilters'
                )} bb b--muted-4`}
              >
                <Button onClick={handleResetFilters}>
                  <FormattedMessage id="store/search-result.filter-button.clearAll" />
                </Button>
              </div>
            )}
          </div>
          <ExtensionPoint id="shop-review-summary" />
        </Fragment>
      )}
      <PostalCodeModal
        isOpen={isPostalCodeModalOpen}
        onClose={() => setIsPostalCodeModalOpen(false)}
      />
      <PickupModal
        isOpen={isPickupModalOpen}
        onClose={() => setisPickupModalOpen(false)}
      />
    </Fragment>
  )
}

FilterNavigator.propTypes = {
  /** Categories tree */
  tree: PropTypes.arrayOf(facetOptionShape),
  /** Params from pages */
  params: paramShape,
  /** List of brand filters (e.g. Samsung) */
  brands: PropTypes.arrayOf(facetOptionShape),
  /** List of specification filters (e.g. Android 7.0) */
  specificationFilters: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      facets: PropTypes.arrayOf(facetOptionShape),
    })
  ),
  /** List of price ranges filters (e.g. from-0-to-100) */
  priceRanges: PropTypes.arrayOf(facetOptionShape),
  /** Current price range filter query parameter */
  priceRange: PropTypes.string,
  /** Loading indicator */
  loading: PropTypes.bool,
  layout: PropTypes.oneOf(Object.values(LAYOUT_TYPES)),
  filtersDrawerDirectionMobile: PropTypes.oneOf(
    Object.values(DRAWER_DIRECTION_MOBILE)
  ),
  initiallyCollapsed: PropTypes.bool,
  truncateFilters: PropTypes.bool,
  filtersTitleHtmlTag: PropTypes.string,
  /** Whether an overview of the applied filters should be displayed (`"show"`) or not (`"hide"`). */
  appliedFiltersOverview: PropTypes.string,
  ...hiddenFacetsSchema,
}

export default FilterNavigator

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/GalleryLayoutOption.tsx from the search-result VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect } from 'react'
import type { PropsWithChildren } from 'react'
import { useCssHandles, applyModifiers } from 'vtex.css-handles'
import type { RenderContext } from 'vtex.render-runtime'
import { useRuntime } from 'vtex.render-runtime'
import { SearchPageContext } from 'vtex.search-page-context'

import { SWITCH_GALLERY_LAYOUT_TYPE } from './constants'

const { useSearchPageState, useSearchPageStateDispatch } = SearchPageContext

interface GalleryLayoutOptionProps {
  /** Unique name to match with a layout name */
  name: string
}

const CSS_HANDLES = ['galleryLayoutOptionButton'] as const

function GalleryLayoutOption({
  name,
  children,
}: PropsWithChildren<GalleryLayoutOptionProps>) {
  const handles = useCssHandles(CSS_HANDLES)
  const optionButtonRef = React.useRef<HTMLButtonElement>(null)
  const { setQuery } = useRuntime() as RenderContext
  const { selectedGalleryLayout, focusedGalleryLayout } = useSearchPageState()
  const dispatch = useSearchPageStateDispatch()

  const selected = name === selectedGalleryLayout

  useEffect(() => {
    if (focusedGalleryLayout === name) {
      optionButtonRef.current?.focus()
    }
  }, [focusedGalleryLayout, name])

  const handleOptionClick = () => {
    dispatch({
      type: SWITCH_GALLERY_LAYOUT_TYPE,
      args: { selectedGalleryLayout: name },
    })

    setQuery({ layout: name })
  }

  return (
    <button
      className={`${applyModifiers(
        handles.galleryLayoutOptionButton,
        selected ? 'selected' : ''
      )} bw0 pointer bg-transparent flex flex-row items-center`}
      onClick={handleOptionClick}
      role="radio"
      aria-checked={selected}
      aria-controls="gallery-layout-container"
      aria-label={`Switch to ${name} layout`}
      tabIndex={
        (focusedGalleryLayout ?? selectedGalleryLayout) === name ? 0 : -1
      }
      ref={optionButtonRef}
    >
      {children}
    </button>
  )
}

export default GalleryLayoutOption

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/OrderBy.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import React, { useMemo } from 'react'
import { useIntl } from 'react-intl'

import SelectionListOrderBy from './components/SelectionListOrderBy'

export const SORT_OPTIONS = [
  {
    value: '',
    label: 'store/ordenation.relevance',
  },
  {
    value: 'OrderByTopSaleDESC',
    label: 'store/ordenation.sales',
  },
  {
    value: 'OrderByReleaseDateDESC',
    label: 'store/ordenation.release.date',
  },
  {
    value: 'OrderByBestDiscountDESC',
    label: 'store/ordenation.discount',
  },
  {
    value: 'OrderByPriceDESC',
    label: 'store/ordenation.price.descending',
  },
  {
    value: 'OrderByPriceASC',
    label: 'store/ordenation.price.ascending',
  },
  {
    value: 'OrderByNameASC',
    label: 'store/ordenation.name.ascending',
  },
  {
    value: 'OrderByNameDESC',
    label: 'store/ordenation.name.descending',
  },
]

const OrderBy = ({
  orderBy,
  message,
  specificationOptions = [],
  hiddenOptions = [],
  showOrderTitle = true,
}) => {
  const intl = useIntl()

  const sortingOptions = useMemo(() => {
    return SORT_OPTIONS.concat(specificationOptions)
      .filter(option => !hiddenOptions.includes(option.value) && option.label)
      .map(({ value, label }) => {
        return {
          value,
          label: intl.formatMessage({ id: label }),
        }
      })
  }, [intl, hiddenOptions, specificationOptions])

  return (
    <SelectionListOrderBy
      orderBy={orderBy}
      message={message}
      options={sortingOptions}
      showOrderTitle={showOrderTitle}
    />
  )
}

OrderBy.propTypes = {
  /** Which sorting option is selected. */
  orderBy: PropTypes.string,
  /** Specification sorting options to be displayed in the list */
  specificationOptions: PropTypes.arrayOf(PropTypes.object),
  /** Options to be hidden. (e.g. `["OrderByNameASC", "OrderByNameDESC"]`) */
  hiddenOptions: PropTypes.arrayOf(PropTypes.string),
  /** Message to be displayed */
  message: PropTypes.string,
  /** Show or hide order title */
  showOrderTitle: PropTypes.bool,
}

export default OrderBy

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/package.json from the search-result VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.search-result",
  "description": "A Search Result.",
  "scripts": {
    "pretest": "yarn",
    "test": "vtex-test-tools test"
  },
  "author": "VTEX",
  "license": "ISC",
  "dependencies": {
    "@vtex/ads-react": "0.3.1",
    "@vtex/css-handles": "^1.1.3",
    "classnames": "^2.2.6",
    "immer": "^9.0.6",
    "query-string": "^7.0.1",
    "ramda": "^0.25.0",
    "react-apollo": "3.1.3",
    "react-collapse": "^5.1.1",
    "react-content-loader": "^3.1.2",
    "react-infinite-scroll-component": "^4.1.0",
    "react-intersection-observer": "^8.23.0",
    "react-intl": "^3.12.0",
    "react-motion": "^0.5.2",
    "react-outside-click-handler": "^1.2.2",
    "react-resize-detector": "^3.4.0",
    "react-spring": "^8.0.20",
    "resize-observer-polyfill": "^1.5.1",
    "slugify": "^1.3.4"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@testing-library/react-hooks": "^2.0.1",
    "@types/classnames": "^2.2.10",
    "@types/graphql": "^14.5.0",
    "@types/jest": "^25.1.4",
    "@types/node": "^13.9.8",
    "@types/ramda": "^0.27.20",
    "@types/react": "^16.9.31",
    "@types/react-resize-detector": "^5.0.0",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.5.5",
    "apollo-cache-inmemory": "^1.6.5",
    "babel-eslint": "^10.1.0",
    "graphql": "^14.6.0",
    "typescript": "3.9.7",
    "vtex.blog-interfaces": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.blog-interfaces@0.2.0/public/@types/vtex.blog-interfaces",
    "vtex.breadcrumb": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.breadcrumb@1.9.4/public/@types/vtex.breadcrumb",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.device-detector": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.device-detector@0.2.6/public/@types/vtex.device-detector",
    "vtex.flex-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.flex-layout@0.20.1/public/@types/vtex.flex-layout",
    "vtex.format-currency": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.format-currency@0.4.1/public/@types/vtex.format-currency",
    "vtex.native-types": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.native-types@0.8.0/public/@types/vtex.native-types",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.8.0/public/@types/vtex.pixel-manager",
    "vtex.product-list-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-list-context@0.4.1/public/@types/vtex.product-list-context",
    "vtex.product-summary": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-summary@2.80.1/public/@types/vtex.product-summary",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.132.4/public/@types/vtex.render-runtime",
    "vtex.responsive-values": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.responsive-values@0.4.2/public/@types/vtex.responsive-values",
    "vtex.rich-text": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.rich-text@0.15.0/public/@types/vtex.rich-text",
    "vtex.search-page-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-page-context@0.2.0/public/@types/vtex.search-page-context",
    "vtex.search-result": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-result@3.118.14/public/@types/vtex.search-result",
    "vtex.shelf": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.shelf@1.47.2/public/@types/vtex.shelf",
    "vtex.shop-review-interfaces": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.shop-review-interfaces@0.3.1/public/@types/vtex.shop-review-interfaces",
    "vtex.store-components": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-components@3.162.2/public/@types/vtex.store-components",
    "vtex.store-drawer": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-drawer@0.16.2/public/@types/vtex.store-drawer",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.156.1/public/@types/vtex.store-graphql",
    "vtex.store-icons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-icons@0.18.0/public/@types/vtex.store-icons",
    "vtex.store-resources": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-resources@0.101.0/public/@types/vtex.store-resources",
    "vtex.structured-data": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.structured-data@0.9.1/public/@types/vtex.structured-data",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.146.3/public/@types/vtex.styleguide",
    "vtex.tab-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.tab-layout@0.4.3/public/@types/vtex.tab-layout"
  },
  "resolutions": {
    "json-schema": "^0.4.0",
    "jsdom": "^16.5.0",
    "jest-environment-jsdom": "^26.0.0",
    "node-notifier": "^8.0.1"
  },
  "version": "3.143.0"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/SidebarCloseButton.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import SidebarCloseButton from './components/SidebarCloseButton'

export default SidebarCloseButton

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const MAP_CATEGORY_CHAR = 'c'
export const MAP_BRAND_CHAR = 'b'
export const MAP_QUERY_KEY = 'map'
export const FULLTEXT_QUERY_KEY = 'ft'
export const SELLER_QUERY_KEY = 'seller'
export const PRODUCT_CLUSTER_IDS = 'productClusterIds'
export const MAP_VALUES_SEP = ','
export const PATH_SEPARATOR = '/'
export const SPACE_REPLACER = '-'
export const FILTER_TITLE_SEP = '_'
export const SPEC_FILTER = 'specificationFilter'
export const SPEC_FILTERS = 'SpecificationFilters'
export const SET_GALLERY_LAYOUTS_TYPE = 'SET_GALLERY_LAYOUTS'
export const SWITCH_GALLERY_LAYOUT_TYPE = 'SWITCH_GALLERY_LAYOUT'
export const SET_FOCUS_GALLERY_LAYOUT_TYPE = 'SET_FOCUS_GALLERY_LAYOUT'
export const ASC = 'ASC'
export const DESC = 'DESC'

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/FetchPrevious.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
// eslint-disable-next-line no-restricted-imports
import { path } from 'ramda'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import { useSearchPage } from 'vtex.search-page-context/SearchPageContext'

import FetchPreviousButton from './components/loaders/FetchPreviousButton'
import { useFetchMore } from './hooks/useFetchMore'
import styles from './searchResult.css'

const FetchPrevious = ({ htmlElementForButton = 'button' }) => {
  const { searchQuery, maxItemsPerPage, page } = useSearchPage()
  const products = path(['data', 'productSearch', 'products'], searchQuery)
  const recordsFiltered = path(
    ['data', 'productSearch', 'recordsFiltered'],
    searchQuery
  )

  const fetchMore = path(['fetchMore'], searchQuery)
  const queryData = {
    query: path(['variables', 'query'], searchQuery),
    map: path(['variables', 'map'], searchQuery),
    orderBy: path(['variables', 'orderBy'], searchQuery),
    priceRange: path(['variables', 'selectedFacets'], searchQuery)?.find(
      facet => facet.key === 'priceRange'
    )?.value,
  }

  const { handleFetchMorePrevious, loading, from, previousPage } = useFetchMore(
    {
      page,
      recordsFiltered,
      maxItemsPerPage,
      fetchMore,
      products,
      queryData,
    }
  )

  return (
    <div
      className={classNames(
        styles['buttonShowMore--layout'],
        'w-100 flex justify-center'
      )}
    >
      <FetchPreviousButton
        products={products}
        from={from}
        recordsFiltered={recordsFiltered}
        onFetchPrevious={handleFetchMorePrevious}
        loading={loading}
        htmlElementForButton={htmlElementForButton}
        previousPage={previousPage}
      />
    </div>
  )
}

FetchPrevious.propTypes = {
  /* html element to render for fetch previous button */
  htmlElementForButton: PropTypes.string,
}

FetchPrevious.schema = {
  title: 'admin/editor.search-result.fetch-previous',
}

export default FetchPrevious

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/FilterNavigatorLegacy.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import FilterNavigator from './components/FilterNavigator/legacy/index'

export default FilterNavigator

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/NotFoundSearch.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import React, { Fragment } from 'react'
import { FormattedMessage } from 'react-intl'
import { ExtensionPoint } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'
import { useSearchPage } from 'vtex.search-page-context/SearchPageContext'
import { range } from 'ramda'

const CSS_HANDLES = [
  'searchNotFound',
  'searchNotFoundOops',
  'searchNotFoundInfo',
  'searchNotFoundWhatDoIDo',
  'searchNotFoundWhatToDoDots',
  'searchNotFoundWhatToDoDotsContainer',
  'searchNotFoundTerm',
  'searchNotFoundTextListLine',
]

/**
 * Not found page component, rendered when the search doesn't return any
 * products from the API.
 */
const NotFoundSearch = () => {
  const handles = useCssHandles(CSS_HANDLES)

  const { params } = useSearchPage()

  const term = params?.term ? decodeURI(params?.term) : ''

  return (
    <Fragment>
      <div
        className={`${handles.searchNotFound} flex flex-column-s flex-row-ns justify-center-ns items-center h-auto-s h5-ns`}
      >
        <div
          className={`${handles.searchNotFoundOops} flex justify-end-ns justify-center-s ttu f1 ph4 pv4-s pv0-ns c-muted-3 ph9 b`}
        >
          oops!
        </div>
        <div className={`${handles.searchNotFoundInfo} flex flex-column ph9`}>
          {term ? (
            <FormattedMessage
              id="store/search.empty-products"
              values={{
                term: (
                  <span
                    className={`${handles.searchNotFoundTerm} c-action-primary`}
                  >
                    {term}
                  </span>
                ),
              }}
            >
              {(...textList) => (
                <span
                  className={`${handles.searchNotFoundTextListLine} c-muted-1 b`}
                >
                  {textList.map((text, index) => (
                    <Fragment key={index}>{text}</Fragment>
                  ))}
                </span>
              )}
            </FormattedMessage>
          ) : (
            <FormattedMessage id="store/search.no-products" />
          )}
          <FormattedMessage id="store/search.what-do-i-do">
            {text => (
              <p className={`${handles.searchNotFoundWhatDoIDo} c-muted-2`}>
                {text}
              </p>
            )}
          </FormattedMessage>
          <ul
            className={`${handles.searchNotFoundWhatToDoDotsContainer} c-muted-2`}
          >
            {range(1, 5).map(id => (
              <FormattedMessage id={`store/search.what-to-do.${id}`} key={id}>
                {text => (
                  <li
                    className={`${handles.searchNotFoundWhatToDoDots}`}
                    key={text}
                  >
                    {text}
                  </li>
                )}
              </FormattedMessage>
            ))}
          </ul>
        </div>
      </div>
      <ExtensionPoint id="shelf" />
    </Fragment>
  )
}

NotFoundSearch.propTypes = {
  /** Search term */
  term: PropTypes.string,
}

export default NotFoundSearch

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/SearchResultLayoutCustomQuery.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { useChildBlock, ExtensionPoint, useRuntime } from 'vtex.render-runtime'
import { useDevice } from 'vtex.device-detector'
import { path, compose, equals, pathOr, isEmpty } from 'ramda'

import LocalQuery from './components/LocalQuery'
import OldSearchResult from './index'
import { removeTreePath } from './utils/removeTreePath'
import SearchResultCustomQueryWrapper from './components/SearchResultCustomQueryWrapper'

const noProducts = compose(
  isEmpty,
  pathOr([], ['data', 'productSearch', 'products'])
)

const isFtOnly = compose(equals('ft'), path(['variables', 'map']))

const trimStartingSlash = value => value && value.replace(/^\//, '')

const foundNothing = searchQuery => {
  const { loading } = searchQuery || {}

  return isFtOnly(searchQuery) && !loading && noProducts(searchQuery)
}

const ExtensionPointWithProps = ({ id, parentProps, localSearchQueryData }) => {
  return (
    <SearchResultCustomQueryWrapper localSearchQueryData={localSearchQueryData}>
      <ExtensionPoint
        id={id}
        {...removeTreePath(parentProps)}
        searchQuery={localSearchQueryData.searchQuery}
        maxItemsPerPage={localSearchQueryData.maxItemsPerPage}
        map={localSearchQueryData.map}
        params={localSearchQueryData.params}
        priceRange={localSearchQueryData.priceRange}
        orderBy={localSearchQueryData.orderBy}
        page={localSearchQueryData.page}
      />
    </SearchResultCustomQueryWrapper>
  )
}

const SearchResultLayoutCustomQuery = props => {
  const hasMobileBlock = !!useChildBlock({ id: 'search-result-layout.mobile' })
  const hasCustomNotFound = !!useChildBlock({ id: 'search-not-found-layout' })
  const { isMobile } = useDevice()
  const { query } = useRuntime()

  const fieldsFromQueryString = {
    mapField: query.map,
    queryField: trimStartingSlash(query.query),
  }

  const areFieldsFromQueryStringValid = !!(
    fieldsFromQueryString.mapField && fieldsFromQueryString.queryField
  )

  if (!props.querySchema) {
    // No valid Query schema provided!
    return null
  }

  return (
    <LocalQuery
      maxItemsPerPage={props.querySchema.maxItemsPerPage}
      {...(areFieldsFromQueryStringValid
        ? fieldsFromQueryString
        : {
            queryField: props.querySchema.queryField,
            mapField: props.querySchema.mapField,
          })}
      orderByField={props.querySchema.orderByField}
      priceRangeField={props.querySchema.priceRangeField}
      hideUnavailableItems={props.querySchema.hideUnavailableItems}
      facetsBehavior={props.querySchema.facetsBehavior}
      skusFilter={props.querySchema.skusFilter}
      installmentCriteria={props.querySchema.installmentCriteria}
      query={props.query}
      __unstableProductOriginVtex={
        props.querySchema.__unstableProductOriginVtex
      }
      render={localSearchQueryData => {
        if (
          foundNothing(localSearchQueryData.searchQuery) &&
          hasCustomNotFound
        ) {
          return (
            <ExtensionPointWithProps
              id="search-not-found-layout"
              parentProps={props}
              localSearchQueryData={localSearchQueryData}
            />
          )
        }

        if (hasMobileBlock && isMobile) {
          return (
            <ExtensionPointWithProps
              id="search-result-layout.mobile"
              parentProps={props}
              localSearchQueryData={localSearchQueryData}
            />
          )
        }

        if (areFieldsFromQueryStringValid) {
          return (
            <ExtensionPointWithProps
              id="search-result-layout.desktop"
              parentProps={{
                ...props,
                querySchema: {
                  ...props.querySchema,
                  ...fieldsFromQueryString,
                },
              }}
              localSearchQueryData={localSearchQueryData}
            />
          )
        }

        return (
          <ExtensionPointWithProps
            id="search-result-layout.desktop"
            parentProps={props}
            localSearchQueryData={localSearchQueryData}
          />
        )
      }}
    />
  )
}

SearchResultLayoutCustomQuery.getSchema = () => {
  const { description, ...schema } = OldSearchResult.getSchema({})

  return {
    ...schema,
    title: 'admin/editor.search-result-layout-custom.title',
  }
}

export default SearchResultLayoutCustomQuery

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/SearchTitleFlexible.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'

import { useBreadcrumb } from './hooks/useBreadcrumb'
import SearchTitle from './SearchTitle'
import styles from './searchResult.css'

// eslint-disable-next-line react/display-name
const withSearchPageContextProps = Component => () => {
  const breadcrumb = useBreadcrumb()

  return (
    <Component
      breadcrumb={breadcrumb}
      wrapperClass={styles['galleryTitle--layout']}
    />
  )
}

export default withSearchPageContextProps(SearchTitle)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/OrderByFlexible.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { useSearchPage } from 'vtex.search-page-context/SearchPageContext'

import OrderBy from './OrderBy'
import styles from './searchResult.css'

// eslint-disable-next-line react/display-name
const withSearchPageContextProps = Component => props => {
  const { orderBy } = useSearchPage()

  if (orderBy == null) {
    return null
  }

  return (
    <div className={styles['orderBy--layout']}>
      <Component {...props} orderBy={orderBy} />
    </div>
  )
}

const OrderByFlexible = withSearchPageContextProps(OrderBy)

OrderByFlexible.schema = {
  title: 'admin/editor.search-result.ordination.sort-by',
}

export default OrderByFlexible

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/SearchContent.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import { ExtensionPoint } from 'vtex.render-runtime'
import { path } from 'ramda'
import {
  useSearchPage,
  useSearchPageState,
} from 'vtex.search-page-context/SearchPageContext'

const SearchContent = () => {
  const { searchQuery, showFacets, lazyItemsRemaining } = useSearchPage()
  const { mobileLayout, showContentLoader } = useSearchPageState()

  const products =
    path(['data', 'productSearch', 'products'], searchQuery) || []

  const redirect = path(['data', 'productSearch', 'redirect'], searchQuery)

  /* No need to show the spinner if it is loading because
   the LoadingOverlay already takes care of this */
  if (showContentLoader === undefined || showContentLoader || redirect) {
    return null
  }

  if (!products || products.length === 0) {
    return <ExtensionPoint id="not-found" />
  }

  return (
    <>
      <ExtensionPoint
        id="gallery"
        products={products}
        className="bn"
        mobileLayoutMode={mobileLayout}
        showingFacets={showFacets}
        lazyItemsRemaining={lazyItemsRemaining}
      />
    </>
  )
}

export default SearchContent

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/LayoutModeSwitcherFlexible.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'
import {
  useSearchPage,
  useSearchPageState,
  useSearchPageStateDispatch,
} from 'vtex.search-page-context/SearchPageContext'
import { prop } from 'ramda'

import LayoutModeSwitcher from './LayoutModeSwitcher'

// eslint-disable-next-line react/display-name
const withSearchPageContextProps = Component => () => {
  const { mobileLayout: layoutOptions } = useSearchPage()
  const { mobileLayout } = useSearchPageState()
  const dispatch = useSearchPageStateDispatch()

  const onChange = e => {
    e.preventDefault()
    const newLayoutIndex =
      prop('mode1', layoutOptions) === mobileLayout ? 'mode2' : 'mode1'

    const newLayout = prop(newLayoutIndex, layoutOptions)

    dispatch({ type: 'SWITCH_LAYOUT', args: { mobileLayout: newLayout } })
  }

  if (layoutOptions && Object.keys(layoutOptions).length < 2) {
    return null
  }

  return <Component activeMode={mobileLayout} onChange={onChange} />
}

export default withSearchPageContextProps(LayoutModeSwitcher)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/store/contentSchemas.json from the search-result VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "OrderBy": {
      "title": "admin/editor.search-result.ordination.sort-by",
      "type": "object",
      "properties": {
        "message": {
          "$ref": "app:vtex.native-types#/definitions/text",
          "title": "admin/editor.search-result.ordination.sort-by"
        }
      }
    },
    "TotalProducts": {
      "title": "admin/editor.search-result.total-products",
      "type": "object",
      "properties": {
        "message": {
          "$ref": "app:vtex.native-types#/definitions/text",
          "title": "admin/editor.search-result.total-products"
        }
      }
    },
    "FetchPrevious": {
      "title": "admin/editor.search-result.fetch-previous",
      "type": "object",
      "properties": {
        "htmlElementForButton": {
          "title": "admin/editor.search-result.fetch-button.button-behavior",
          "enum": ["button", "a"],
          "enumNames": [
            "admin/editor.search-result.fetch-button.button-behavior.button",
            "admin/editor.search-result.fetch-button.button-behavior.link-to-page"
          ],
          "widget": {
            "ui:widget": "radio"
          },
          "default": "button"
        }
      }
    },
    "FetchMore": {
      "title": "admin/editor.search-result.fetch-more",
      "type": "object",
      "properties": {
        "htmlElementForButton": {
          "title": "admin/editor.search-result.fetch-button.button-behavior",
          "enum": ["button", "a"],
          "enumNames": [
            "admin/editor.search-result.fetch-button.button-behavior.button",
            "admin/editor.search-result.fetch-button.button-behavior.link-to-page"
          ],
          "widget": {
            "ui:widget": "radio"
          },
          "default": "button"
        }
      }
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/store/blocks.json from the search-result VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "search-result": {
    "blocks": [
      "filter-navigator",
      "gallery",
      "not-found",
      "breadcrumb",
      "total-products",
      "order-by"
    ]
  },
  "gallery": {
    "blocks": ["product-summary"]
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/store/interfaces.json from the search-result VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "search-result": {
    "allowed": [
      "not-found",
      "breadcrumb",
      "filter-navigator",
      "total-products",
      "order-by",
      "search-title",
      "rich-text",
      "search-products-progress-bar"
    ],
    "required": ["gallery"],
    "component": "index"
  },
  "filter-navigator": {
    "component": "FilterNavigatorLegacy"
  },
  "filter-navigator.v1": {
    "component": "FilterNavigatorLegacy"
  },
  "filter-navigator.v2": {
    "component": "FilterNavigator",
    "allowed": ["shop-review-summary", "sidebar-close-button"]
  },
  "gallery": {
    "allowed": ["product-summary"],
    "component": "Gallery"
  },
  "gallery-layout-switcher": {
    "component": "GalleryLayoutSwitcher",
    "composition": "children"
  },
  "gallery-layout-option": {
    "component": "GalleryLayoutOption",
    "composition": "children"
  },
  "not-found": {
    "allowed": ["shelf"],
    "component": "NotFoundSearch"
  },
  "order-by": {
    "component": "OrderBy"
  },
  "total-products": {
    "component": "TotalProducts"
  },
  "search-title": {
    "component": "SearchTitle"
  },
  "search-result-layout": {
    "allowed": [
      "search-result-layout.desktop",
      "search-result-layout.mobile",
      "search-not-found-layout"
    ],
    "component": "SearchResultLayout"
  },
  "search-result-layout.customQuery": {
    "allowed": [
      "search-result-layout.desktop",
      "search-result-layout.mobile",
      "search-not-found-layout"
    ],
    "component": "SearchResultLayoutCustomQuery"
  },
  "search-layout-switcher": {
    "component": "LayoutModeSwitcherFlexible"
  },
  "search-content": {
    "required": ["gallery", "not-found"],
    "component": "SearchContent"
  },
  "search-fetch-more": {
    "component": "FetchMore",
    "content": {
      "$ref": "app:vtex.search-result#/definitions/FetchMore"
    }
  },
  "search-fetch-previous": {
    "component": "FetchPrevious",
    "content": {
      "$ref": "app:vtex.search-result#/definitions/FetchPrevious"
    }
  },
  "search-result-layout.desktop": {
    "allowed": [
      "breadcrumb.search",
      "filter-navigator.v3",
      "total-products.v2",
      "order-by.v2",
      "search-title.v2",
      "rich-text",
      "info-card",
      "flex-layout",
      "tab-layout",
      "tab-list",
      "tab-content",
      "search-fetch-previous",
      "search-fetch-more",
      "search-content",
      "search-products-count-per-page",
      "search-blog-articles-preview",
      "search-blog-articles-list"
    ],
    "composition": "children",
    "component": "SearchResultFlexible"
  },
  "search-result-layout.mobile": {
    "allowed": [
      "breadcrumb.search",
      "filter-navigator.v3",
      "total-products.v2",
      "order-by.v2",
      "search-title.v2",
      "rich-text",
      "info-card",
      "flex-layout",
      "tab-layout",
      "drawer",
      "search-layout-switcher",
      "search-fetch-previous",
      "search-fetch-more",
      "search-content",
      "search-products-count-per-page",
      "search-blog-articles-preview",
      "search-blog-articles-list"
    ],
    "composition": "children",
    "component": "SearchResultFlexibleMobile",
    "device": "mobile"
  },
  "search-not-found-layout": {
    "allowed": [
      "breadcrumb.search",
      "search-title.v2",
      "rich-text",
      "info-card",
      "flex-layout",
      "not-found"
    ],
    "composition": "children",
    "component": "NotFoundLayout"
  },
  "search-products-count-per-page": {
    "component": "ProductCountPerPage"
  },
  "search-products-progress-bar": {
    "component": "ProductsProgressBar"
  },
  "order-by.v2": {
    "component": "OrderByFlexible",
    "content": {
      "$ref": "app:vtex.search-result#/definitions/OrderBy"
    }
  },
  "filter-navigator.v3": {
    "component": "FilterNavigatorFlexible",
    "allowed": ["sidebar-close-button"]
  },
  "total-products.v2": {
    "component": "TotalProductsFlexible",
    "content": {
      "$ref": "app:vtex.search-result#/definitions/TotalProducts"
    }
  },
  "search-title.v2": {
    "component": "SearchTitleFlexible"
  },
  "sidebar-close-button": {
    "component": "SidebarCloseButton"
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants/filterTypes.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
/**
 * Types of radio filters available in the application
 */
const RADIO_FILTER_TYPES = {
  SHIPPING: 'shipping',
  DELIVERY_OPTIONS: 'delivery-options',
}

/**
 * Types of toggle filters available in the application
 */
const TOGGLE_FILTER_TYPES = {
  DYNAMIC_ESTIMATE: 'dynamic-estimate',
}

/**
 * Checks if a filter key corresponds to a radio filter type
 * @param {string} key - Filter key to check
 * @returns {boolean} True if the key belongs to a radio filter type
 */
export const isRadioFilter = (key: string): boolean =>
  Object.values(RADIO_FILTER_TYPES).includes(key)

/**
 * Checks if a filter key corresponds to a toggle filter type
 * @param {string} key - Filter key to check
 * @returns {boolean} True if the key belongs to a toggle filter type
 */
export const isToggleFilter = (key: string): boolean =>
  Object.values(TOGGLE_FILTER_TYPES).includes(key)

export const isSingleOptionFilter = (key: string): boolean =>
  [
    ...Object.values(RADIO_FILTER_TYPES),
    ...Object.values(TOGGLE_FILTER_TYPES),
  ].includes(key)

export default RADIO_FILTER_TYPES

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants/filterConstants.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
export const FACETS_RENDER_THRESHOLD = 10

/**
 * Translation mappings for toggle filter labels
 * Maps filter names to their i18n message keys
 */
export const toggleFiltersValue = {
  'same-day': 'store/search.filter.dynamic-estimate.same-day.name',
  'next-day': 'store/search.filter.dynamic-estimate.next-day.name',
  'delivery-same-day':
    'store/search.filter.dynamic-estimate.delivery-same-day.name',
  'delivery-next-day':
    'store/search.filter.dynamic-estimate.delivery-next-day.name',
  'pickup-same-day':
    'store/search.filter.dynamic-estimate.pickup-same-day.name',
  'pickup-next-day':
    'store/search.filter.dynamic-estimate.pickup-next-day.name',
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants/SearchHelpers.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
// eslint-disable-next-line default-param-last
export function getFilterTitle(title = '', intl) {
  return intl.messages[title] ? intl.formatMessage({ id: title }) : title
}

export const HEADER_SCROLL_OFFSET = 90

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants/paginationType.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
export const PAGINATION_TYPE = {
  SHOW_MORE: 'show-more',
  INFINITE_SCROLL: 'infinite-scroll',
}

export const PAGINATION_TYPES = [
  PAGINATION_TYPE.SHOW_MORE,
  PAGINATION_TYPE.INFINITE_SCROLL,
]

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants/propTypes.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'

import { LAYOUT_MODE } from '../components/LayoutModeSwitcher'

export const paramShape = PropTypes.shape({
  /** Department of the page */
  department: PropTypes.string,
  /** Category of the page */
  category: PropTypes.string,
  /** Subcategory of the page */
  subcategory: PropTypes.string,
  /** Search term */
  term: PropTypes.string,
})

export const facetOptionShape = PropTypes.shape({
  /** Quantity of products matched with the facet option. */
  quantity: PropTypes.number.isRequired,
  /** Link of the facets option. */
  link: PropTypes.string,
  /** Name of the facet option. */
  name: PropTypes.string.isRequired,
})

export const productShape = PropTypes.shape({
  /** Product's id. */
  productId: PropTypes.string.isRequired,
  /** Product's name. */
  productName: PropTypes.string.isRequired,
  /** Product's description. */
  description: PropTypes.string.isRequired,
  /** Product's categories. */
  categories: PropTypes.array,
  /** Product's link. */
  link: PropTypes.string,
  /** Product's link text. */
  linkText: PropTypes.string.isRequired,
  /** Product's brand. */
  brand: PropTypes.string,
  /** Product's SKU items. */
  items: PropTypes.arrayOf(
    PropTypes.shape({
      /** SKU's id. */
      itemId: PropTypes.string.isRequired,
      /** SKU's name. */
      name: PropTypes.string.isRequired,
      /** SKU's referenceId. */
      referenceId: PropTypes.arrayOf(
        PropTypes.shape({
          /** ReferenceId's value. */
          Value: PropTypes.string.isRequired,
        })
      ),
      /** SKU's images. */
      images: PropTypes.arrayOf(
        PropTypes.shape({
          /** Images's imageUrl. */
          imageUrl: PropTypes.string.isRequired,
          /** Images's imageTag. */
          imageTag: PropTypes.string.isRequired,
        })
      ).isRequired,
      /** SKU's sellers. */
      sellers: PropTypes.arrayOf(
        PropTypes.shape({
          /** Sellers's commertialOffer. */
          commertialOffer: PropTypes.shape({
            /** CommertialOffer's price. */
            Price: PropTypes.number.isRequired,
            /** CommertialOffer's list price. */
            ListPrice: PropTypes.number.isRequired,
          }).isRequired,
        })
      ).isRequired,
    })
  ).isRequired,
})

export const facetsShape = PropTypes.shape({
  /** Departments matched with the facets. */
  departments: PropTypes.arrayOf(facetOptionShape),
  /** Brands matched with the facets. */
  brands: PropTypes.arrayOf(facetOptionShape),
  /** SpecificationFilters matched with the facets. */
  specificationFilters: PropTypes.arrayOf(
    PropTypes.shape({
      /** SpecificationFilter's name. */
      name: PropTypes.string.isRequired,
      /** SpecificationFilter's facets. */
      facets: PropTypes.arrayOf(facetOptionShape),
    })
  ),
  /** Categories matched with the facets. */
  categoriesTrees: PropTypes.arrayOf(
    PropTypes.shape({
      /** Category's name. */
      name: PropTypes.string.isRequired,
      /** Category's quantity. */
      quantity: PropTypes.number.isRequired,
      /** Array of SubCategories. */
      children: PropTypes.arrayOf(facetOptionShape),
    })
  ),
})

export const searchQueryShape = PropTypes.shape({
  /** Facets resulting by the search. */
  facets: facetsShape,
  /** Products resulting by the search.  */
  products: PropTypes.arrayOf(productShape),
  /** Records filtered by the search. */
  recordsFiltered: PropTypes.number,
})

export const queryShape = PropTypes.shape({
  /** Determines the types of the terms, e.g: "c,c,b" (category, category, brand). */
  map: PropTypes.string,
  /** Current ordination. */
  order: PropTypes.string,
  /** Current page number. */
  page: PropTypes.string,
  /**
   * Current price range filtering, e.g. "0 TO 1000" (meaning the result
   * is filtered with the price starting at 0 and ending at 1000)
   */
  priceRange: PropTypes.string,
})

export const hiddenFacetsSchema = {
  /** Indicates which facets will be hidden */
  hiddenFacets: PropTypes.shape({
    /** Determines if the brands facets will be hidden */
    brands: PropTypes.bool,
    /** Determines if the categories facets will be hidden */
    categories: PropTypes.bool,
    /** Determines if the price range will be hidden */
    priceRange: PropTypes.bool,
    /** Hidden specification filters facets configuration */
    specificationFilters: PropTypes.shape({
      /** Determines if all the specification filters facets will be hidden */
      hideAll: PropTypes.bool,
      /** Array of specific hidden filters */
      hiddenFilters: PropTypes.arrayOf(
        PropTypes.shape({
          /** Name of the hidden filter */
          name: PropTypes.string,
        })
      ),
    }),
  }),
}

export const schemaPropsTypes = {
  /** Maximum number of items per page. */
  maxItemsPerPage: PropTypes.number,
  /** Product Summary's props */
  summary: PropTypes.any,
  ...hiddenFacetsSchema,
}

export const searchResultContainerPropTypes = {
  /** Internal route path. e.g: 'store.search' */
  pagesPath: PropTypes.string,
  /** Internal route params.
   * e.g: { department: 'electronics', category: 'smartphones' }
   */
  params: PropTypes.object,
  /** Map param. e.g: c,c */
  map: PropTypes.string,
  /** Search result page. */
  page: PropTypes.number,
  /** Search result ordination. */
  orderBy: PropTypes.string,
  /** Price range filter */
  priceRange: PropTypes.string,
  /** Search graphql query. */
  searchQuery: searchQueryShape,
  ...schemaPropsTypes,
}

export const searchResultPropTypes = {
  breadcrumbsProps: PropTypes.shape({
    categories: PropTypes.array,
    term: PropTypes.string,
  }),
  /** Number of items available according to the filters */
  recordsFiltered: PropTypes.number.isRequired,
  /** List of brands available */
  brands: PropTypes.array.isRequired,
  /** Map param. e.g: c,c */
  map: PropTypes.string,
  params: PropTypes.object,
  /** Price range filter */
  priceRange: PropTypes.string,
  /** List of price ranges filter */
  priceRanges: PropTypes.array.isRequired,
  /** Hidden specification filters facets configuration */
  specificationFilters: PropTypes.array.isRequired,
  /** Categories matched with the facets. */
  tree: PropTypes.array,
  /** Query loading status */
  loading: PropTypes.bool.isRequired,
  /** Loading status when the query is refetched */
  fetchMoreLoading: PropTypes.bool.isRequired,
  /** Runtime context */
  runtime: PropTypes.shape({
    hints: PropTypes.shape({
      /** Indicates if is on a mobile device */
      mobile: PropTypes.bool,
    }),
  }),
  /** Mobile Layout Modes setup */
  mobileLayout: PropTypes.shape({
    /** First Layout Mode */
    mode1: PropTypes.oneOf(LAYOUT_MODE.map(mode => mode.value)),
    /** Second Layout Mode */
    mode2: PropTypes.oneOf(LAYOUT_MODE.map(mode => mode.value)),
  }),
}

export const loaderPropTypes = {
  /** List of products */
  products: PropTypes.arrayOf(productShape),
  /** Function to refetch de data query */
  onFetchMore: PropTypes.func.isRequired,
  /** Number of items available according to the filters */
  recordsFiltered: PropTypes.number.isRequired,
  /** Loading status when the query is refetched */
  fetchMoreLoading: PropTypes.bool,
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/constants/urlHelpers.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
export const DEFAULT_WIDTH = 'auto'
export const DEFAULT_HEIGHT = 'auto'
export const MAX_WIDTH = 3000
export const MAX_HEIGHT = 4000

/**
 * Having the url below as base for the LEGACY file manager,
 * https://storecomponents.vteximg.com.br/arquivos/ids/155472/Frame-3.jpg?v=636793763985400000
 * the following regex will match https://storecomponents.vteximg.com.br/arquivos/ids/155472
 *
 * Also matches urls with defined sizes like:
 * https://storecomponents.vteximg.com.br/arquivos/ids/155473-160-auto
 * @type {RegExp}
 *
 * On the new vtex.file-manager isn't necessary replace the URL, just add the param on the querystring, like:
 * "?width=WIDTH&height=HEIGHT&aspect=true"
 *
 */
const baseUrlRegex = new RegExp(/.+ids\/(\d+)/)

const httpRegex = new RegExp(/http:\/\//)

export function toHttps(url) {
  return url.replace(httpRegex, 'https://')
}

export function cleanImageUrl(imageUrl) {
  const result = baseUrlRegex.exec(imageUrl)

  if (result.length > 0) return result[0]
}

function replaceLegacyFileManagerUrl(imageUrl, width, height) {
  const legacyUrlPattern = '/arquivos/ids/'
  const isLegacyUrl = imageUrl.includes(legacyUrlPattern)

  if (!isLegacyUrl) return imageUrl

  return `${cleanImageUrl(imageUrl)}-${width}-${height}`
}

export function changeImageUrlSize(
  imageUrl,
  width = DEFAULT_WIDTH,
  height = DEFAULT_HEIGHT
) {
  if (!imageUrl) return
  typeof width === 'number' && (width = Math.min(width, MAX_WIDTH))
  typeof height === 'number' && (height = Math.min(height, MAX_HEIGHT))

  const normalizedImageUrl = replaceLegacyFileManagerUrl(
    imageUrl,
    width,
    height
  )

  const queryStringSeparator = normalizedImageUrl.includes('?') ? '&' : '?'

  return `${normalizedImageUrl}${queryStringSeparator}width=${width}&height=${height}&aspect=true`
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.search-page-context.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.search-page-context/SearchPageContext' {
  type DispatchFunction = (payload: {
    type: string
    args?: Record<string, unknown>
  }) => void

  export const useSearchPage: () => any
  export const useSearchPageState: () => SearchPageState
  export const useSearchPageStateDispatch: () => DispatchFunction

  export interface SearchPageState {
    galleryLayout?: string
    searchQuery: any
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.responsive-values.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.responsive-values' {
  const useResponsiveValues: (input: any) => any
  const useResponsiveValue: <T>(input: MaybeResponsiveInput<T>) => T

  // eslint-disable-next-line no-restricted-syntax
  enum InputDevices {
    Mobile = 'mobile',
    Phone = 'phone',
    Tablet = 'tablet',
    Desktop = 'desktop',
  }

  // eslint-disable-next-line no-restricted-syntax
  enum InputDevices {
    MOBILE = 'mobile',
    PHONE = 'phone',
    TABLET = 'tablet',
    DESKTOP = 'desktop',
  }

  // eslint-disable-next-line no-restricted-syntax
  enum InputDevices {
    mobile = 'mobile',
    phone = 'phone',
    tablet = 'tablet',
    desktop = 'desktop',
  }

  // eslint-disable-next-line no-restricted-syntax
  enum OutputDevices {
    phone = 'phone',
    tablet = 'tablet',
    desktop = 'desktop',
  }

  type ResponsiveInput<T> = { [P in keyof typeof InputDevices]?: T }
  export type MaybeResponsiveInput<T> = T | ResponsiveInput<T>

  type ResponsiveOutput<T> = { [P in keyof typeof OutputDevices]: T }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.render-runtime.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.render-runtime' {
  interface Runtime {
    account: string
    rootPath: string
    query: Record<string, string>
    navigate: (args: NavigateArgs) => void
    getSettings(id: string): StoreSettings
    route: {
      routeId: string
    }
  }

  interface RuntimeWithRoute extends Runtime {
    route: {
      routeId: string
      title?: string
      metaTags?: MetaTagsParams
      canonicalPath?: string
    }
  }

  export function useRuntime(): Runtime
  export const Helmet
  export const canUseDOM: boolean
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.structured-data.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.structured-data' {
  import type { ComponentType } from 'react'

  export const ProductList: ComponentType<Record<string, unknown>>
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/global.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Window extends Window {
  __hostname__: string | undefined
}

declare module '../utils/removeTreePath' {
  export function removeTreePath<T = unknown>(props: T): T
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.pixel-manager.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.pixel-manager/PixelContext' {
  interface Pixel {
    push(data: unknown): void
  }

  export function usePixel(): Pixel
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.product-summary.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.product-summary/ProductSummaryCustom'

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/typings/vtex.styleguide.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.styleguide' {
  import type { ComponentType } from 'react'

  export const Spinner: ComponentType<Record<string, unknown>>
  export const RadioGroup: ComponentType<Record<string, unknown>>
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/slug.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  SPACE_REPLACER,
  SPEC_FILTER,
  FILTER_TITLE_SEP,
  MAP_CATEGORY_CHAR,
  MAP_BRAND_CHAR,
} from '../constants'

const from =
  'ÁÄÂÀÃÅČÇĆĎÉĚËÈÊẼĔȆÍÌÎÏŇÑÓÖÒÔÕØŘŔŠŤÚŮÜÙÛÝŸŽáäâàãåčçćďéěëèêẽĕȇíìîïňñóöòôõøðřŕšťúůüùûýÿžþÞĐđßÆa·/_,:;'

const to =
  'AAAAAACCCDEEEEEEEEIIIINNOOOOOORRSTUUUUUYYZaaaaaacccdeeeeeeeeiiiinnooooooorrstuuuuuyyzbBDdBAa------'

const removeAccents = (str: string) => {
  let newStr = str.slice(0)

  for (let i = 0; i < from.length; i++) {
    newStr = newStr.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i))
  }

  return newStr
}

// Parameter "S. Coifman" should output "s--coifman"
export function searchSlugify(str: string) {
  // According to Bacelar, the search API uses a legacy method for slugifying strings.
  // replaces special characters with dashes, remove accents and lower cases everything
  // eslint-disable-next-line no-useless-escape
  const replaced = str.replace(/[*+~.()'"!:@&\[\]`,/ %$#?{}|><=_^]/g, '-')

  return removeAccents(replaced).toLowerCase()
}

export const newFacetPathName = (facet: any) => {
  if (facet.map?.includes(SPEC_FILTER)) {
    return `${searchSlugify(
      facet.title
    )}${FILTER_TITLE_SEP}${facet.value.replace(/\s/g, SPACE_REPLACER)}`
  }

  if (facet.map === MAP_CATEGORY_CHAR || facet.map === MAP_BRAND_CHAR) {
    return facet.value.toLowerCase()
  }

  return facet.value
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/queryAndMapUtils.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  MAP_CATEGORY_CHAR,
  PATH_SEPARATOR,
  MAP_VALUES_SEP,
  PRODUCT_CLUSTER_IDS,
  FULLTEXT_QUERY_KEY,
} from '../constants'

const CATEGORY_DEPARTMENTS_CLUSTER_ID_FT = [
  MAP_CATEGORY_CHAR,
  PRODUCT_CLUSTER_IDS,
  FULLTEXT_QUERY_KEY,
]

const CATEGORY_DEPARTMENTS_FT = [MAP_CATEGORY_CHAR, FULLTEXT_QUERY_KEY]

/* With the addition of the new VTEX search, it is possible to have different maps.
  This function checks the equivalent possibilities for the 'c' map */
export const isSameMap = (map1: string, map2: string) => {
  if (CATEGORY_DEPARTMENTS_FT.includes(map1)) {
    return CATEGORY_DEPARTMENTS_FT.includes(map2)
  }

  return map1 === map2
}

export const isCategoryDepartmentCollectionOrFT = (term: string) => {
  return CATEGORY_DEPARTMENTS_CLUSTER_ID_FT.includes(term)
}

export const filterCategoryDepartmentCollectionAndFT = (context: any) => {
  const query = context.query.split(PATH_SEPARATOR)
  const map = context.map.split(MAP_VALUES_SEP)
  const newQuery = []
  const newMap = []

  for (let i = 0; i < map.length; i++) {
    if (isCategoryDepartmentCollectionOrFT(map[i])) {
      newQuery.push(query[i])
      newMap.push(map[i])
    }
  }

  return {
    query: newQuery.join(PATH_SEPARATOR),
    map: newMap.join(MAP_VALUES_SEP),
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/filterManipulationPixelEvents.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
const getCategoryFromObjs = (products: Array<Record<string, unknown>>) => {
  if (products[0] === null || products[0] === undefined) {
    return ''
  }

  const [{ categoryId }] = products
  const result = products.every(
    (product: Record<string, unknown>) => product.categoryId === categoryId
  )

  return result ? categoryId : ''
}

interface PushFilterManipulationPixelEventParams {
  name: string
  value: unknown
  products: Array<Record<string, unknown>>
  push: (data: {
    event: string
    items: {
      filterProductCategory: unknown
      filterName: string
      filterValue: unknown
    }
  }) => void
}

export const pushFilterManipulationPixelEvent = ({
  name,
  value,
  products,
  push,
}: PushFilterManipulationPixelEventParams) => {
  push({
    event: 'filterManipulation',
    items: {
      filterProductCategory: getCategoryFromObjs(products),
      filterName: name,
      filterValue: value,
    },
  })
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/isShippingOptionsComponent.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
const SHIPPING_OPTION_COMPONENT_DRAWER_CLASS =
  'vtex-shipping-option-components-0-x-drawer'

const SHIPPING_OPTION_COMPONENT_OVERLAY_CLASS =
  'vtex-shipping-option-components-0-x-overlay'

const isShippingOptionsComponent = e => {
  if (!e.target) {
    return false
  }

  const shippingOptionsDawerElement = e.target.closest(
    `.${SHIPPING_OPTION_COMPONENT_DRAWER_CLASS}`
  )

  const isShippingOptionsOverlayElement = e.target.classList.contains(
    SHIPPING_OPTION_COMPONENT_OVERLAY_CLASS
  )

  return shippingOptionsDawerElement || isShippingOptionsOverlayElement
}

export default isShippingOptionsComponent

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/ProductListEventCaller.tsx from the search-result VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useProductImpression } from 'vtex.product-list-context'

const ProductListEventCaller = () => {
  useProductImpression()

  return null
}

export default ProductListEventCaller

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/sortFilterValues.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { SPEC_FILTERS, ASC, DESC } from '../constants'

interface Filters {
  key: string
  quantity: number
  title: string
  type: string
  facets: Facets[]
}

interface Facets {
  name: string
  quantity: number
}

interface SortRules {
  key: string
  orderBy: keyof Facets
  order: typeof ASC | typeof DESC
}

// Handle string and number comparation
const compare = (
  a: string | number,
  b: string | number,
  order: SortRules['order']
) => {
  const isASC = order.toUpperCase() === ASC
  const isString = typeof a === 'string'
  const isNumber = typeof a === 'number'

  if (isString) {
    if (isASC) return (a as string).localeCompare(b as string)

    return (b as string).localeCompare(a as string)
  }

  if (isNumber) {
    if (isASC) return (a as number) - (b as number)

    return (b as number) - (a as number)
  }

  return 0
}

// Make sure rule has key and orderBy
const validateRule = (rule: unknown): boolean => {
  if (typeof rule !== 'object' || rule === null) return false

  const ruleKeys = Object.keys(rule)

  return ruleKeys.indexOf('key') > -1 && ruleKeys.indexOf('orderBy') > -1
}

// Handle cases where user pass a non valid string to order field, defaulting to ASC
const ensureOrderValue = (order: string): SortRules['order'] => {
  const isDESC = order.toUpperCase() === DESC

  if (isDESC) return DESC

  return ASC
}

export const sortFilterValues = (
  filters: Filters[],
  sortingRules: SortRules[]
): Filters[] => {
  // Check if user has entered the right type on store-theme
  if (!Array.isArray(sortingRules)) {
    console.warn(
      'Wrong type passed as facetOrdering prop to filter-navigator.v3 block. It should be an array.'
    )

    return filters
  }

  // Skip logic if there is no sorting rules
  if (!sortingRules.length) {
    return filters
  }

  // Map rules for all keys
  const mappedRules = sortingRules.reduce<
    Record<SortRules['key'], Omit<SortRules, 'key'>>
  >((map, rule) => {
    if (!validateRule(rule)) {
      console.warn(
        'One of the rules passed inside facetOrdering prop to filter-navigator.v3 block has the wrong signature and was ignored.'
      )

      return map
    }

    map[rule.key.toLowerCase()] = {
      orderBy: rule.orderBy,
      order: ensureOrderValue(rule.order ?? ASC),
    }

    return map
  }, {})

  // Apply rules for each facet
  const filtersAdjusted = filters.map(filter => {
    const isSpecFilter = filter.type === SPEC_FILTERS
    const hasSortingRule = filter.key
      ? Boolean(mappedRules[filter.key.toLowerCase()])
      : false

    if (!isSpecFilter || !hasSortingRule) return filter

    const { orderBy, order } = mappedRules[filter.key.toLowerCase()]

    const filterCopy = { ...filter }

    filterCopy.facets.sort((a, b) => compare(a[orderBy], b[orderBy], order))

    return filterCopy
  })

  return filtersAdjusted
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/searchMetadata.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { zipObj } from 'ramda'

interface SpecificationFilter {
  facets?: any[]
  hidden: boolean
  name: string
  quantity: number
  type: string
}

interface CategoriesTrees {
  id: string
  name: string
  selected: boolean
  children?: CategoriesTrees[]
}

interface QueryArgs {
  query: string
  map: string
}

interface Facets {
  categoriesTrees?: CategoriesTrees[]
  queryArgs?: QueryArgs
  specificationFilters?: SpecificationFilter[]
}

interface Breadcrumb {
  name: string
  href: string
}

interface SearchQueryData {
  searchMetadata?: {
    titleTag: string
    metaTagDescription: string
  }
  productSearch?: {
    breadcrumb: Breadcrumb[]
    recordsFiltered: number
    operator?: string
    searchState?: string
    correction?: {
      misspelled: boolean
    }
  }
  facets?: Facets
}

export interface SearchQuery {
  loading: boolean
  products: any
  data?: SearchQueryData
  variables: {
    query: string
    map: string
  }
}

interface GetTitleTagParams {
  titleTag: string
  storeTitle: string
  term?: string
  pageTitle?: string
  pageNumber?: number
  removeStoreNameTitle?: boolean
}

type PageEventName =
  | 'internalSiteSearchView'
  | 'categoryView'
  | 'departmentView'
  | 'emptySearchView'

const mapEvent = {
  InternalSiteSearch: 'internalSiteSearchView',
  Category: 'categoryView',
  Department: 'departmentView',
  EmptySearch: 'emptySearchView',
}

const fallbackView = 'otherView'

interface Variables {
  fullText?: string
  category?: any
}

const pageCategory = (products: unknown[], variables: Variables) => {
  if (!products || products.length === 0) {
    return 'EmptySearch'
  }

  const { category, fullText } = variables

  return fullText ? 'InternalSiteSearch' : category ? 'Category' : 'Department'
}

export const getPageEventName = (
  products: unknown[],
  variables: Variables
): PageEventName => {
  if (!products) {
    return fallbackView as PageEventName
  }

  const category = pageCategory(products, variables)

  return (mapEvent[category] || fallbackView) as PageEventName
}

const getDecodeURIComponent = (encodedURIComponent: string) => {
  try {
    return decodeURIComponent(encodedURIComponent)
  } catch {
    return encodedURIComponent
  }
}

const capitalize = (str?: string) => {
  return str && str.charAt(0).toUpperCase() + str.slice(1)
}

export const getTitleTag = ({
  titleTag,
  storeTitle,
  term,
  pageTitle,
  pageNumber = 0,
  removeStoreNameTitle,
}: GetTitleTagParams) => {
  /*
  titleNumber and storeTitleFormatted depend on the value of enablePageNumberTitle and removeStoreNameTitle params.
  by default, the value of enablePageNumberTitle and removeStoreNameTitle is false, only if the value of these
  parameters is true, it will affect the value of titleNumber or storeTitleFormatted.
  */
  const titleNumber = pageNumber > 0 ? ` #${pageNumber}` : ''
  const storeTitleFormatted = removeStoreNameTitle ? '' : ` - ${storeTitle}`

  if (titleTag) {
    return `${getDecodeURIComponent(
      titleTag
    )}${titleNumber}${storeTitleFormatted}`
  }

  if (pageTitle) {
    return `${getDecodeURIComponent(
      pageTitle
    )}${titleNumber}${storeTitleFormatted}`
  }

  if (term) {
    return `${capitalize(
      getDecodeURIComponent(term)
    )}${titleNumber}${storeTitleFormatted}`
  }

  return storeTitle
}

const getDepartmentFromSpecificationFilters = (facets?: Facets) => {
  if (!facets?.queryArgs?.map.split(',').includes('c')) {
    return
  }

  const departmentFilter = facets.specificationFilters?.find(specFilter => {
    return specFilter.facets?.[0].key === 'category-1'
  })

  return departmentFilter?.facets?.find(facet => facet.selected)
}

const getDepartment = (searchQuery: SearchQueryData) => {
  if (searchQuery.facets?.categoriesTrees?.length) {
    return searchQuery.facets.categoriesTrees.find(
      department => department.selected
    )
  }

  return getDepartmentFromSpecificationFilters(searchQuery.facets)
}

export const getDepartmentMetadata = (searchQuery?: SearchQueryData) => {
  if (
    !searchQuery ||
    !searchQuery.facets ||
    !searchQuery.facets.categoriesTrees
  ) {
    return
  }

  const department = getDepartment(searchQuery)

  if (!department) {
    return
  }

  return {
    id: department.id,
    name: department.name,
  }
}

const getCategoryFromSpecificationFilters = (facets?: Facets) => {
  const totalCategories =
    facets?.queryArgs?.map.split(',').filter((key: string) => key === 'c')
      .length ?? 0

  if (totalCategories <= 1) {
    return
  }

  const categoryFilter = facets?.specificationFilters?.find(specFilter => {
    return specFilter.facets?.[0].key === 'category-2'
  })

  return categoryFilter?.facets?.find(facet => facet.selected)
}

const getLastCategory = (
  category: CategoriesTrees,
  facets?: Facets
): CategoriesTrees => {
  const selectedCategory =
    category.children &&
    category.children.length > 0 &&
    category.children.find(currCategory => currCategory.selected)

  if (!selectedCategory) {
    return getCategoryFromSpecificationFilters(facets) ?? category
  }

  return getLastCategory(selectedCategory)
}

export const getCategoryMetadata = (searchQuery?: SearchQueryData) => {
  if (
    !searchQuery ||
    !searchQuery.facets ||
    !searchQuery.facets.categoriesTrees
  ) {
    return
  }

  const department = getDepartment(searchQuery)

  if (!department) {
    return
  }

  const category = getLastCategory(department, searchQuery.facets)

  if (category === department) {
    return
  }

  return {
    id: category.id,
    name: category.name,
  }
}

export const getSearchMetadata = (searchQuery?: SearchQueryData) => {
  if (
    !searchQuery ||
    !searchQuery.productSearch ||
    !searchQuery.facets ||
    !searchQuery.facets.queryArgs
  ) {
    return
  }

  const { query, map } = searchQuery.facets.queryArgs
  const queryMap = zipObj(map.split(','), query.split('/'))

  const searchTerm = queryMap.ft

  let decodedTerm = ''

  // This try/catch works to prevent decoding search terms that end in "%".
  try {
    decodedTerm = decodeURIComponent(searchTerm || '')
  } catch (e) {
    decodedTerm = decodeURIComponent(encodeURIComponent(searchTerm || ''))
  }

  const department = getDepartment(searchQuery)

  return {
    term: decodedTerm || undefined,
    category: department ? { id: department.id, name: department.name } : null,
    results: searchQuery.productSearch.recordsFiltered,
    operator: searchQuery.productSearch.operator,
    searchState: searchQuery.productSearch.searchState,
    correction: searchQuery.productSearch.correction,
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/removeTreePath.d.ts from the search-result VTEX app.

[Assistant]
Here's the implementation:

```typescript
export function removeTreePath<T = unknown>(props: T): T

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/getCookie.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { canUseDOM } from 'exenv'

function getCookie(cname) {
  if (!canUseDOM) {
    return undefined
  }

  const name = `${cname}=`
  const decodedCookie = decodeURIComponent(document.cookie)
  const ca = decodedCookie.split(';')

  for (let i = 0; i < ca.length; i++) {
    let c = ca[i]

    while (c.charAt(0) === ' ') {
      c = c.substring(1)
    }

    if (c.indexOf(name) === 0) {
      return c.substring(name.length, c.length)
    }
  }

  return undefined
}

export default getCookie

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of search-result/react/utils/getFilters.js from the search-result VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { path, contains, isEmpty } from 'ramda'
import { useIntl } from 'react-intl'

export const SHIPPING_TITLE = 'store/search.filter.title.shipping'
export const CATEGORIES_TITLE = 'store/search.filter.title.categories'
export const BRANDS_TITLE = 'store/search.filter.title.brands'
export const PRICE_RANGES_TITLE = 'store/search.filter.title.price-ranges'

export const shippingOptions = {
  delivery: 'store/search.filter.shipping.name.delivery',
  'pickup-in-point': 'store/search.filter.shipping.name.pickup-in-point',
  'pickup-nearby': 'store/search.filter.shipping.name.pickup-nearby',
  'pickup-all': 'store/search.filter.shipping.name.pickup-all',
}

export const SHIPPING_KEY = 'shipping'

const BRANDS_TYPE = 'Brands'
const PRICE_RANGES_TYPE = 'PriceRanges'
const SPECIFICATION_FILTERS_TYPE = 'SpecificationFilters'

const getFilters = ({
  specificationFilters = [],
  priceRanges = [],
  brands = [],
  deliveries = [],
  brandsQuantity = 0,
  hiddenFacets = {},
  showShippingFacet = false,
  availableShippingValues = [],
}) => {
  // eslint-disable-next-line react-hooks/rules-of-hooks
  const intl = useIntl()

  let deliveriesFormatted = deliveries

  let shipping = deliveries.find(d => d.name === SHIPPING_KEY)

  if (shipping && availableShippingValues.length !== 0) {
    shipping = {
      ...shipping,
      facets: shipping.facets.filter(facet =>
        availableShippingValues.includes(facet.name)
      ),
    }
  }

  if (shipping) {
    const shippingFormattedFacetsName = {
      ...shipping,
      title: SHIPPING_TITLE,
      facets: shipping.facets.map(facet => ({
        ...facet,
        name: intl.formatMessage({ id: shippingOptions[facet.name] }),
      })),
    }

    deliveriesFormatted = deliveries.map(facet =>
      facet.name === SHIPPING_KEY ? shippingFormattedFacetsName : facet
    )
  }

  if (!showShippingFacet) {
    deliveriesFormatted = deliveriesFormatted.filter(
      d => d.name !== SHIPPING_KEY
    )
  }

  const hiddenFacetsNames = (
    path(['specificationFilters', 'hiddenFilters'], hiddenFacets) || []
  ).map(filter => filter.name)

  const mappedSpecificationFilters = !path(
    ['specificationFilters', 'hideAll'],
    hiddenFacets
  )
    ? specificationFilters
        .filter(spec => !contains(spec.name, hiddenFacetsNames) && !spec.hidden)
        .map(spec => ({
          type: SPECIFICATION_FILTERS_TYPE,
          title: spec.name,
          facets: spec.facets,
          quantity: spec.quantity,
          key: spec.facets?.[0].key,
        }))
    : []

  return [
    ...deliveriesFormatted,
    ...mappedSpecificationFilters,
    !hiddenFacets.brands &&
      !isEmpty(brands) && {
        type: BRANDS_TYPE,
        title: BRANDS_TITLE,
        facets: brands,
        quantity: brandsQuantity,
      },
    !hiddenFacets.priceRange &&
      !isEmpty(priceRanges) && {
        type: PRICE_RANGES_TYPE,
        title: PRICE_RANGES_TITLE,
        facets: priceRanges,
      },
  ].filter(Boolean)
}

export default getFilters

```