[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 store/react/components/OrderFormProvider.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import { graphql, compose } from 'react-apollo'

import addToCart from 'vtex.store-resources/MutationAddToCart'
import updateItems from 'vtex.store-resources/MutationUpdateItems'
import updateOrderFormProfile from 'vtex.store-resources/MutationUpdateOrderFormProfile'
import updateOrderFormShipping from 'vtex.store-resources/MutationUpdateOrderFormShipping'
import updateOrderFormCheckin from 'vtex.store-resources/MutationUpdateOrderFormCheckin'

import { Provider } from 'vtex.store-resources/OrderFormContext'
import orderForm from 'vtex.store-resources/QueryOrderForm'

class OrderFormProvider extends Component {
  state = {
    orderFormContext: {
      message: { isSuccess: null, text: null },
      loading: true,
      orderForm: {},
      refetch: () => {},
      addItem: this.props.addItem,
      updateToastMessage: this.handleMessageUpdate,
      updateOrderForm: this.props.updateOrderForm,
      updateAndRefetchOrderForm: this.handleUpdateAndRefetchOrderForm,
      updateOrderFormProfile: this.props.updateOrderFormProfile,
      updateOrderFormShipping: this.props.updateOrderFormShipping,
      updateOrderFormCheckin: this.props.updateOrderFormCheckin,
    },
  }

  static getDerivedStateFromProps(props, state) {
    if (!props.data.loading && !props.data.error) {
      const orderFormContext = props.data

      orderFormContext.message = state.orderFormContext.message

      return {
        orderFormContext,
      }
    }

    return state
  }

  handleUpdateAndRefetchOrderForm = vars => {
    return this.props.updateOrderForm(vars).then(() => {
      return this.props.data.refetch()
    })
  }

  handleMessageUpdate = message => {
    const context = this.state.orderFormContext
    context.message = message

    this.setState({ orderFormContext: context })
  }

  render() {
    const state = this.state

    state.orderFormContext.updateToastMessage = this.handleMessageUpdate
    state.orderFormContext.updateAndRefetchOrderForm = this.handleUpdateAndRefetchOrderForm
    state.orderFormContext.updateOrderForm = this.props.updateOrderForm
    state.orderFormContext.addItem = this.props.addItem
    state.orderFormContext.updateOrderFormProfile = this.props.updateOrderFormProfile
    state.orderFormContext.updateOrderFormShipping = this.props.updateOrderFormShipping
    state.orderFormContext.updateOrderFormCheckin = this.props.updateOrderFormCheckin

    return <Provider value={this.state}>{this.props.children}</Provider>
  }
}

const options = {
  options: () => ({
    ssr: false,
  }),
}

export default compose(
  graphql(orderForm, options),
  graphql(addToCart, { name: 'addItem' }),
  graphql(updateItems, { name: 'updateOrderForm' }),
  graphql(updateOrderFormProfile, { name: 'updateOrderFormProfile' }),
  graphql(updateOrderFormShipping, { name: 'updateOrderFormShipping' }),
  graphql(updateOrderFormCheckin, { name: 'updateOrderFormCheckin' })
)(OrderFormProvider)

```


[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 store/react/components/WrapperContainer.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React from 'react'

const WrapperContainer = ({ children, className }) => (
  <div className={className}>
    <div className="flex flex-column min-vh-100 w-100">{children}</div>
  </div>
)

export default WrapperContainer

```


[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 store/react/components/NetworkStatusToast.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
/* eslint-disable no-restricted-imports */
import { path, pathOr } from 'ramda'
import { useCallback, useContext, useEffect, useState, useRef } from 'react'
import { injectIntl, intlShape } from 'react-intl'
import { ToastContext } from 'vtex.styleguide'

function NetworkStatusToast({ intl }) {
  const [offline, setOffline] = useState(false)
  // Useful to dismissable toast flow.
  const [showingOffline, setShowingOffline] = useState(false)
  const { showToast, hideToast, toastState } = useContext(ToastContext)

  const toastConfig = useRef({
    message: '',
    dismissable: true,
    duration: Infinity,
  })

  const updateStatus = useCallback(() => {
    if (navigator) {
      setOffline(!pathOr(true, ['onLine'], navigator))
    }
  }, [])

  useEffect(() => {
    if (window) {
      window.addEventListener('online', updateStatus)
      window.addEventListener('offline', updateStatus)
    }
    updateStatus()
    return function cleanUp() {
      if (window) {
        window.removeEventListener('online', updateStatus)
        window.removeEventListener('offline', updateStatus)
      }
    }
  }, [updateStatus])

  useEffect(() => {
    if (offline && !toastState.currentToast) {
      const message = intl.formatMessage({
        id: 'store/store.network-status.offline',
      })
      toastConfig.current.message = message

      if (!showingOffline) {
        showToast(toastConfig.current)
      }
      setShowingOffline(!showingOffline)
    } else if (
      !offline &&
      toastState.isToastVisible &&
      path(['currentToast', 'message'], toastState) ===
        toastConfig.current.message
    ) {
      hideToast()
      setShowingOffline(false)
    }
  }, [
    offline,
    toastState,
    toastConfig,
    showingOffline,
    showToast,
    hideToast,
    intl,
  ])

  return null
}

NetworkStatusToast.propTypes = {
  intl: intlShape.isRequired,
}

export default injectIntl(NetworkStatusToast)

```


[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 store/react/components/VTEXAdsProvider.tsx from the store VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useState } from 'react'
import { AdsProvider } from '@vtex/ads-react'
import { Offer } from '@vtex/ads-core'
import productSearchV3 from 'vtex.store-resources/QueryProductSearchV3'
import { useApolloClient } from 'react-apollo'
import { useRuntime } from 'vtex.render-runtime'

import {
  getSessionPromiseFromWindow,
  getUserData,
  SessionResponse,
} from '../hooks/getUserData'

interface VTEXAdsProviderProps {
  children?: React.ReactNode
}

interface Product {
  items: Array<{
    ean: string
    itemId: string
    sellers: Array<{ sellerId: string }>
  }>
}

const matcher = (product: Product, offer: Offer): boolean => {
  const productSku = product.items.find(
    item =>
      item.itemId === offer.skuId &&
      item.sellers.some(seller => seller.sellerId === offer.sellerId)
  )

  if (productSku === undefined) {
    return false
  }

  const seller = productSku.sellers.find(
    item => item.sellerId === offer.sellerId
  )

  if (!seller) {
    return false
  }

  productSku.sellers = [seller]
  product.items = [productSku]

  return true
}

export const VTEXAdsProvider = ({ children }: VTEXAdsProviderProps) => {
  const { account, getSettings } = useRuntime()
  const publisherId = getSettings('vtex.store')?.publisherId

  const [userId, setUserId] = useState<string | undefined>(undefined)
  const [sessionId, setSessionId] = useState<string>('session-id')

  useEffect(() => {
    getSessionPromiseFromWindow()
      .then((data: SessionResponse) => {
        const profileFields = data?.response?.namespaces?.profile

        if (!profileFields) {
          return
        }

        setSessionId(data.response?.id ?? 'session-id')

        const userData = getUserData(profileFields)
        setUserId(userData.id as string | undefined)
      })
      .catch(() => {})
  }, [])

  const client = useApolloClient()
  const fetcher = async (offers: Offer[]): Promise<Product[]> => {
    if (offers.length === 0) {
      return []
    }

    try {
      const skuIds = offers.map(o => o.skuId).join(';')
      const { data } = await client.query<{
        productSearch: { products: Product[] }
      }>({
        query: productSearchV3,
        variables: { fullText: `sku.id:${skuIds}` },
      })
      return data?.productSearch.products ?? []
    } catch {
      return []
    }
  }

  if (!publisherId) {
    return children
  }

  return (
    <AdsProvider
      identity={{
        accountName: account,
        publisherId,
        userId,
        sessionId,
        channel: 'site',
      }}
      hydrationStrategy={{ fetcher, matcher, key: 'sf' }}
    >
      {children}
    </AdsProvider>
  )
}

```


[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 store/react/components/PageViewPixel.tsx from the store VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable no-restricted-globals */
import { useMemo } from 'react'
import { useRuntime, canUseDOM } from 'vtex.render-runtime'

import useDataPixel from '../hooks/useDataPixel'

interface UsePageViewArgs {
  title?: string
  cacheKey?: string
  skip?: boolean
}

export const usePageView = ({
  title,
  cacheKey,
  skip,
}: UsePageViewArgs = {}) => {
  const { route, account } = useRuntime()
  const pixelCacheKey = cacheKey ?? route.routeId

  const eventData = useMemo(() => {
    if (!canUseDOM || skip) {
      return null
    }

    return {
      event: 'pageView',
      pageTitle: title ?? document.title,
      pageUrl: location.href,
      referrer:
        document.referrer.indexOf(location.origin) === 0
          ? undefined
          : document.referrer,
      accountName: account,
      routeId: route?.routeId ? route.routeId : '',
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [account, title, canUseDOM, pixelCacheKey])

  useDataPixel(skip ? null : eventData, pixelCacheKey)
}

// Those pages already use the hook above (`usePageView`)
// They need to handle the pageView event because they set the page title async
const SKIP_PAGES = ['store.search', 'store.product']

/** When you navigate to a new page, the route object will remain the one from the previous route.
 * So we save the ref on the first mount. After that, we wait for the first time route changes to send a page view with the correct title.
 * A possible better implementation for the future, is add a loading state in the route object.
 */
const PageViewPixel = ({ title }: Partial<UsePageViewArgs>) => {
  const { route } = useRuntime()

  const skip =
    route && SKIP_PAGES.some(routeId => route.routeId.indexOf(routeId) === 0)
  usePageView({ title, skip })

  return null
}

export default PageViewPixel

```


[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 store/react/__tests__/ProductWrapper.test.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
/* eslint-disable jest/no-mocks-import */
/* eslint-env jest */
import React, { useContext } from 'react'
import { render } from '@vtex/test-tools/react'

import { getProduct } from '../__mocks__/productMock'
import ProductWrapper from '../ProductWrapper'
import { ProductContext } from '../__mocks__/vtex.product-context'

const ProductPageMock = () => {
  const { selectedItem, product, selectedQuantity } = useContext(ProductContext)
  return (
    <div>
      <div>Product Page</div>
      <div>Selected Item id: {selectedItem && selectedItem.itemId}</div>
      <div>Selected Item name: {selectedItem && selectedItem.name}</div>
      <div>product slug: {product && product.linkText}</div>
      <div>Selected Quantity: {selectedQuantity}</div>
    </div>
  )
}

const descriptionId = 'description'

describe('ProductWrapper component', () => {
  const getProps = customProps => {
    const product = getProduct()
    const productQuery = {
      product,
      loading: false,
    }
    const props = {
      params: { slug: product.linkText },
      productQuery,
      query: {},
      ...customProps,
    }
    return props
  }
  const renderComponent = customProps => {
    const component = render(
      <ProductWrapper {...getProps(customProps)}>
        <ProductPageMock />
      </ProductWrapper>
    )
    const { getByText } = component
    return {
      ...component,
      getTitleTag: product => getByText(new RegExp(product.titleTag)),
    }
  }

  it('should render with correct title and no meta', () => {
    const product = getProduct()
    const { queryByTestId, getTitleTag } = renderComponent()
    getTitleTag(product)
    // Doesnt have metatag description, <meta> should not be rendered
    expect(queryByTestId(descriptionId)).toBeNull()
  })

  it('should render with correct title and meta', () => {
    const product = getProduct({ metaTagDescription: 'MetaDescription' })
    const { getTitleTag, getByTestId } = renderComponent({
      product,
      params: { slug: product.linkText },
      productQuery: { product, loading: false },
    })
    getByTestId(descriptionId)
    getTitleTag(product)
  })

  it('product wont break if category tree is an empty array', () => {
    const product = getProduct({ categoryTree: [] })
    const { getTitleTag } = renderComponent({
      product,
      params: { slug: product.linkText },
      productQuery: { product, loading: false },
    })
    getTitleTag(product)
  })
})

```


[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 store/react/__tests__/SearchWrapper.test.ts from the store VTEX app.

[Assistant]
Here's the implementation:

```typescript
import queryString from 'query-string'

import { getHelmetLink } from '../SearchWrapper'

describe('getHelmetLink function', () => {
  it('should return null if no canonical is provided', () => {
    const result = getHelmetLink({
      canonicalLink: null,
      page: 1,
      rel: 'canonical',
    })

    // Cannot generate meta links if there's no canonical link to use
    expect(result).toBeNull()
  })

  it('should return null if resulting page is less than 1', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: -1,
      rel: 'canonical',
    })

    const nextLinkResult = getHelmetLink({
      canonicalLink,
      page: -1,
      rel: 'next',
    })

    const prevLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      rel: 'prev',
    })

    expect(canonicalLinkResult).toBeNull()
    expect(nextLinkResult).toBeNull()
    expect(prevLinkResult).toBeNull()
  })

  it('should not return page number if page is equal to 1', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      rel: 'canonical',
    })

    const nextLinkResult = getHelmetLink({
      canonicalLink,
      page: 0,
      rel: 'next',
    })

    const prevLinkResult = getHelmetLink({
      canonicalLink,
      page: 2,
      rel: 'prev',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
    expect(nextLinkResult).toHaveProperty('href', expectedResult)
    expect(prevLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should return canonical link with page querystring appended to it', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const page = 2

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page,
      rel: 'canonical',
    })

    const nextLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      rel: 'next',
    })

    const prevLinkResult = getHelmetLink({
      canonicalLink,
      page: 3,
      rel: 'prev',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
      query: {
        page,
      },
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
    expect(nextLinkResult).toHaveProperty('href', expectedResult)
    expect(prevLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should not return the map on the canonical url of department pages', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      map: 'c',
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should not return the map on the canonical url of category pages', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const map = 'c,c'
    const page = 2

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page,
      map,
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
      query: {
        page,
      },
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should not return the map on the canonical url of subcategory pages', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const map = 'c,c,c'
    const page = 3

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page,
      map,
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
      query: {
        page,
      },
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should not return the map on the canonical url of brand pages', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const map = 'b'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      map,
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should return the map on the canonical url when map has more than 4 categories', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const map = 'c,c,c,c,c'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      map,
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
      query: {
        map,
      },
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should return the map on the canonical url when map has category and brand', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const map = 'c,b'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      map,
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
      query: {
        map,
      },
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })

  it('should return the map on the canonical url when map has any weird value', () => {
    const canonicalLink = 'https://storetheme.vtex.com/apparel---accessories/'
    const map = 'productClusterIds,c'

    const canonicalLinkResult = getHelmetLink({
      canonicalLink,
      page: 1,
      map,
      rel: 'canonical',
    })

    const expectedResult = queryString.stringifyUrl({
      url: canonicalLink,
      query: {
        map,
      },
    })

    expect(canonicalLinkResult).toHaveProperty('href', expectedResult)
  })
})

```


[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 store/react/__tests__/navigation.test.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { normalizeNavigation } from '../utils/navigation'

describe('Navigation route modifier', () => {
  window.__RUNTIME__ = {
    route: {
      domain: 'store',
    },
  }

  it('should lowercase the path', () => {
    const path = '/Category1/category2/Category3'
    const query =
      'map=c,c,c,specificationFilter_1&query=/Category1/category2/Category3/xpto'
    const expectedPath = path.toLocaleLowerCase()
    const expectedQuery = query
    const result = normalizeNavigation({ path, query })

    expect(result).toEqual({ path: expectedPath, query: expectedQuery })
  })
  it('should sort specification filters', () => {
    const path = '/Category1/category2/Category3'
    const query =
      'map=c,c,c,specificationFilter_2,specificationFilter_0,specificationFilter_1&query=/Category1/category2/Category3/xpto2/xpto0/xpto1'
    const expectedPath = path.toLocaleLowerCase()
    const expectedQuery =
      'map=c,c,c,specificationFilter_0,specificationFilter_1,specificationFilter_2&query=/Category1/category2/Category3/xpto0/xpto1/xpto2'
    const result = normalizeNavigation({ path, query })

    expect(result).toEqual({ path: expectedPath, query: expectedQuery })
  })
  it('intelligent search queries should have the following order: /[category hierarchy/alphabetically]/[brand alphabetically]/[specs alphabetically]', () => {
    const path = '/departmentvalue/categoryvalue1/categoryvalue2'
    const query =
      'map=specificationFilter,category-2,category-2,brand,category-1,brand,&query=/specvalue/categoryvalue2/categoryvalue1/brandvalue2/departmentvalue/brandvalue1'
    const expectedPath = path.toLocaleLowerCase()
    const expectedQuery =
      'map=category-1,category-2,category-2,brand,brand,specificationFilter&query=/departmentvalue/categoryvalue1/categoryvalue2/brandvalue1/brandvalue2/specvalue'
    const result = normalizeNavigation({ path, query })

    expect(result).toEqual({ path: expectedPath, query: expectedQuery })
  })
  it('should preserve case for new routes pattern', () => {
    const path = '/foo/bar/nice_Bar'
    const expectedPath = '/foo/bar/nice_Bar'
    const ignore = { 'nice-bar': { path: 'nice_Bar' } }
    const result = normalizeNavigation({ path, ignore })
    expect(result).toEqual({ path: expectedPath, ignore, query: undefined })
  })
})

```


[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 store/react/hooks/useCanonicalLink.ts from the store VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { RuntimeWithRoute, useRuntime } from 'vtex.render-runtime'

export function useCanonicalLink() {
  const { route, rootPath = '' } = useRuntime() as RuntimeWithRoute
  const { canonicalPath } = route

  const canonicalHost =
    window.__hostname__ || (window.location && window.location.hostname)

  if (!canonicalHost || !canonicalPath) {
    return null
  }

  const canonicalLink = `https://${canonicalHost}${rootPath}${canonicalPath}`

  return canonicalLink
}

```


[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 store/react/hooks/getUserData.tsx from the store VTEX app.

[Assistant]
Here's the implementation:

```tsx
const fields = [
  'firstName',
  'lastName',
  'document',
  'id',
  'email',
  'phone',
  'isAuthenticated',
] as const

export interface SessionResponse {
  response: {
    id: string
    namespaces: {
      profile?: {
        firstName?: {
          value: string
        }
        lastName?: {
          value: string
        }
        document?: {
          value: string
        }
        id?: {
          value: string
        }
        email?: {
          value: string
        }
        phone?: {
          value: string
        }
        isAuthenticated?: {
          value: string
        }
      }
    }
  }
}

export const getSessionPromiseFromWindow: any = () =>
  !(window as any).__RENDER_8_SESSION__ ||
  !(window as any).__RENDER_8_SESSION__.sessionPromise
    ? Promise.resolve(null)
    : (window as any).__RENDER_8_SESSION__.sessionPromise

const toBoolean = (value: string) => value.toLowerCase() === 'true'

export function getUserData(
  profileFields: SessionResponse['response']['namespaces']['profile']
) {
  if (!profileFields) {
    return {}
  }

  return fields.reduce<Record<string, string | boolean>>((acc, key) => {
    const value = profileFields[key]?.value

    if (value) {
      acc[key] = key === 'isAuthenticated' ? toBoolean(value) : value
    }

    return acc
  }, {})
}

```


[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 store/react/hooks/useDataPixel.tsx from the store VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable no-restricted-imports */
import { useEffect, useRef } from 'react'
import { usePixel } from 'vtex.pixel-manager/PixelContext'
import { isEmpty } from 'ramda'

type Data = unknown[] | unknown

const useDataPixel = (data: Data, pageIdentifier = '', isLoading = false) => {
  const { push } = usePixel()
  const previousIdRef = useRef<string | null>(null)

  const previousId = previousIdRef.current

  useEffect(() => {
    if (pageIdentifier && !isLoading && previousId !== pageIdentifier) {
      if (!data || isEmpty(data)) {
        return
      }
      if (Array.isArray(data)) {
        data.forEach(push)
      } else {
        push(data)
      }

      previousIdRef.current = pageIdentifier
    }
  }, [data, isLoading, pageIdentifier, previousId, push])
}

export default useDataPixel

```


[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 store/react/scripts/gtm.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
export const gtmScript = gtmId => `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmId}')`

export const gtmFrame = gtmId =>
  `<iframe src="https://www.googletagmanager.com/ns.html?id=${gtmId}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`

```


[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 store/react/modules/capitalize.ts from the store VTEX app.

[Assistant]
Here's the implementation:

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

```


[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 store/react/modules/searchMetadata.ts from the store VTEX app.

[Assistant]
Here's the implementation:

```typescript
// eslint-disable-next-line no-restricted-imports
import { zipObj } from 'ramda'

import { SearchQueryData, CategoriesTrees, Facets } from './searchTypes'

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,
  page?: number,
  maxItemsPerPage?: number
) => {
  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)

  const products = searchQuery?.products?.map(product => {
    return {
      productId: product.productId,
    }
  })

  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,
    products,
    page,
    maxItemsPerPage,
  }
}

```


[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 store/react/modules/session.ts from the store VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { SessionPromise } from 'vtex.render-runtime'

export function getSession() {
  return window &&
    (window as any).__RENDER_8_SESSION__ &&
    (window as any).__RENDER_8_SESSION__.sessionPromise
    ? ((window as any).__RENDER_8_SESSION__.sessionPromise as Promise<
        SessionPromise
      >)
    : null
}

```


[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 store/react/modules/searchTypes.ts from the store VTEX app.

[Assistant]
Here's the implementation:

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

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

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

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

export interface Breadcrumb {
  name: string
  href: string
}

export interface Product {
  productId: string
}

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

interface QueryArgs {
  query: string
  map: string
}

```


[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 store/react/modules/searchMetadata.test.ts from the store VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  getDepartmentMetadata,
  getCategoryMetadata,
  getSearchMetadata,
} from './searchMetadata'

test('should get department metadata', () => {
  const searchQuery = {
    facets: {
      categoriesTrees: [
        {
          id: '1',
          name: 'foo',
          selected: true,
          children: [
            {
              id: '2',
              name: 'bar',
              selected: false,
              children: [],
            },
          ],
        },
      ],
    },
  }

  const result = getDepartmentMetadata(searchQuery)

  expect(result!.id).toBe('1')
  expect(result!.name).toBe('foo')
})

test('should get category metadata', () => {
  const searchQuery = {
    facets: {
      categoriesTrees: [
        {
          id: '1',
          name: 'foo',
          selected: true,
          children: [
            {
              id: '2',
              name: 'bar',
              selected: true,
              children: [],
            },
          ],
        },
      ],
    },
  }

  const result = getCategoryMetadata(searchQuery)

  expect(result!.id).toBe('2')
  expect(result!.name).toBe('bar')
})

test('should not get category metadata if none is selected', () => {
  const searchQuery = {
    facets: {
      categoriesTrees: [
        {
          id: '1',
          name: 'foo',
          selected: true,
          children: [
            {
              id: '2',
              name: 'bar',
              selected: false,
              children: [],
            },
          ],
        },
      ],
    },
  }

  const result = getCategoryMetadata(searchQuery)

  expect(result).toBeUndefined()
})

test('should get deepest category metadata', () => {
  const searchQuery = {
    facets: {
      categoriesTrees: [
        {
          id: '1',
          name: 'foo',
          selected: true,
          children: [
            {
              id: '2',
              name: 'bar',
              selected: true,
              children: [
                {
                  id: '3',
                  name: 'baz',
                  selected: true,
                  children: [],
                },
              ],
            },
          ],
        },
      ],
    },
  }

  const result = getCategoryMetadata(searchQuery)

  expect(result!.id).toBe('3')
  expect(result!.name).toBe('baz')
})

test('should get the searched metadata', () => {
  const searchQuery = {
    productSearch: {
      recordsFiltered: 3,
      breadcrumb: [
        {
          name: 'Top',
          href: '/electronics/top?map=c,ft',
        },
      ],
      operator: 'and',
      searchState: 'placeholder',
      correction: { misspelled: false },
    },
    facets: {
      categoriesTrees: [
        {
          id: '1',
          name: 'foo',
          selected: true,
          children: [],
        },
      ],
      queryArgs: {
        query: 'Top',
        map: 'ft',
      },
    },
  }

  const result = getSearchMetadata(searchQuery)

  expect(result!.term).toBe('Top')
  expect(result!.category!.id).toBe('1')
  expect(result!.category!.name).toBe('foo')
  expect(result!.results).toBe(3)
  expect(result!.operator).toBe('and')
  expect(result!.searchState).toBe('placeholder')
  expect(result!.correction!.misspelled).toBe(false)
})

test('should get the searched metadata without category', () => {
  const searchQuery = {
    productSearch: {
      recordsFiltered: 3,
      breadcrumb: [
        {
          name: 'Top',
          href: '/electronics/top?map=c,ft',
        },
      ],
      operator: 'and',
      searchState: 'placeholder',
      correction: { misspelled: true },
    },
    facets: {
      categoriesTrees: [
        {
          id: '1',
          name: 'foo',
          selected: false,
          children: [],
        },
      ],
      queryArgs: {
        query: 'Top',
        map: 'ft',
      },
    },
  }

  const result = getSearchMetadata(searchQuery)

  expect(result!.term).toBe('Top')
  expect(result!.category).toBeNull()
  expect(result!.results).toBe(3)
  expect(result!.operator).toBe('and')
  expect(result!.searchState).toBe('placeholder')
  expect(result!.correction!.misspelled).toBe(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 store/react/modules/search.js from the store VTEX app.

[Assistant]
Here's the implementation:

```javascript
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',
  },
]

// Quick function to get querystring
// https://stackoverflow.com/a/901144/5313009
// TODO: Replace this with a better function
const getParameterByName = (name, url) => {
  if (!url) url = window && window.location && window.location.href
  name = name.replace(/[[\]]/g, '\\$&')

  const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`)
  const results = regex.exec(url)

  if (!results) return null
  if (!results[2]) return ''

  return (
    window &&
    window.decodeURIComponent &&
    window.decodeURIComponent(results[2].replace(/\+/g, ' '))
  )
}

export function getMapFromURL(url) {
  getParameterByName('map', url)
}

export function createInitialMap(params) {
  if (params.subcategory) {
    return 'c,c,c'
  }
  if (params.category) {
    return 'c,c'
  }
  if (params.department) {
    return 'c'
  }
  if (params.brand) {
    return 'b'
  }
  if (params.term) {
    return 'ft'
  }

  return params.terms
    .split('/')
    .map(() => 'ft')
    .join(',')
}

export function initializeMap(params, url) {
  return getMapFromURL(url) || createInitialMap(params)
}

```


[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 console/messages/pt.json from the console VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "console.menu.title": "Console",
  "console.submenu.metrics": "Métricas",
  "console.submenu.publishes": "Publicações",
  "console.admin.tabs.metrics": "Métricas",
  "console.admin.tabs.errors": "Erros",
  "console.admin.metrics.button.add": "Adicionar Novo",
  "console.context": "Contexto",
  "console.newMetric": "Nova Métrica",
  "console.available.apps": "Apps Disponíveis",
  "console.app.version": "Versão",
  "console.app.region": "Região",
  "console.app.environment": "Ambiente",
  "console.any": "Qualquer",
  "console.envPicker.production": "Produção",
  "console.envPicker.development": "Desenvolvimento",
  "console.empty.time.range.headline": "Por favor defina um intervalo de tempo",
  "console.empty.time.range.explanation": "Por favor defina um intervalo de tempo para analisar sua métrica",
  "console.button.set.time.range": "Definir Intervalo de Tempo",
  "console.button.apply.time.range": "Aplicar",
  "console.date.picker.from": "De",
  "console.date.picker.to": "Até",
  "console.range.step.picker.stepSize": "Passo",
  "console.cpuUsage.lineChart": "Uso de Cpu (percentual) durante o Tempo",
  "console.latency.lineChart": "Latência (milisegundos) durante o Tempo",
  "console.memoryUsage.lineChart": "Consumo de Memória (bytes) durante o Tempo",
  "console.empty.context.headline": "Por favor selecione um contexto",
  "console.empty.context.explanation": "Por favor selecione o contexto no qual suas métricas serão analisadas",
  "console.time.controller.absolute": "Absoluto",
  "console.time.controller.relative": "Relativo",
  "console.statusCode.barChart": "Distribuição de Http Status Code",
  "console.statusCode.lineChart": "Http Status Code (percentual) durante o tempo",
  "console.time.controller.relative.earliest": "De",
  "console.time.controller.relative.earliestModifier.seconds.ago": "Segundos Atrás",
  "console.time.controller.relative.earliestModifier.minutes.ago": "Minutos Atrás",
  "console.time.controller.relative.earliestModifier.hours.ago": "Horas Atrás",
  "console.time.controller.relative.earliestModifier.days.ago": "Dias Atrás",
  "console.time.controller.relative.earliestModifier.months.ago": "Meses Atrás",
  "console.time.controller.relative.earliestModifier.years.ago": "Anos Atrás"
}

```


[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 console/messages/en.json from the console VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "console.menu.title": "Console",
  "console.submenu.metrics": "Metrics",
  "console.submenu.publishes": "Publishes",
  "console.admin.tabs.metrics": "Metrics",
  "console.admin.tabs.errors": "Errors",
  "console.admin.metrics.button.add": "Add New",
  "console.context": "Context",
  "console.newMetric": "New Metric",
  "console.available.apps": "Available Apps",
  "console.app.version": "Version",
  "console.app.region": "Region",
  "console.app.environment": "Environment",
  "console.any": "Any",
  "console.envPicker.production": "Production",
  "console.envPicker.development": "Development",
  "console.empty.time.range.headline": "Please set a time range",
  "console.empty.time.range.explanation": "Please set a time range to analyze your metric",
  "console.button.set.time.range": "Set Time Range",
  "console.button.apply.time.range": "Apply",
  "console.date.picker.from": "From",
  "console.date.picker.to": "To",
  "console.range.step.picker.stepSize": "Step",
  "console.cpuUsage.lineChart": "Cpu usage (percentage) over Time",
  "console.latency.lineChart": "Latency (miliseconds) over Time",
  "console.memoryUsage.lineChart": "Memory (bytes) consumption over Time",
  "console.empty.context.headline": "Please select a context",
  "console.empty.context.explanation": "Please select the context in which your metrics will be analyzed",
  "console.time.controller.absolute": "Absolute",
  "console.time.controller.relative": "Relative",
  "console.statusCode.barChart": "Http Status Code Distribution",
  "console.statusCode.lineChart": "Http Status Code (percentage) over Time",
  "console.time.controller.relative.earliest": "From",
  "console.time.controller.relative.earliestModifier.seconds.ago": "Seconds Ago",
  "console.time.controller.relative.earliestModifier.minutes.ago": "Minutes Ago",
  "console.time.controller.relative.earliestModifier.hours.ago": "Hours Ago",
  "console.time.controller.relative.earliestModifier.days.ago": "Days Ago",
  "console.time.controller.relative.earliestModifier.months.ago": "Months Ago",
  "console.time.controller.relative.earliestModifier.years.ago": "Years Ago"
}

```


[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 console/messages/context.json from the console VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "console.menu.title": "",
  "console.submenu.metrics": "",
  "console.submenu.publishes": "",
  "console.admin.tabs.metrics": "",
  "console.admin.tabs.errors": "",
  "console.context": "",
  "console.newMetric": "",
  "console.available.apps": "",
  "console.app.version": "",
  "console.app.region": "",
  "console.app.environment": "",
  "console.any": "",
  "console.envPicker.production": "",
  "console.envPicker.development": "",
  "console.empty.time.range.headline": "",
  "console.empty.time.range.explanation": "",
  "console.button.set.time.range": "",
  "console.button.apply.time.range": "",
  "console.date.picker.from": "",
  "console.date.picker.to": "",
  "console.range.step.picker.stepSize": "",
  "console.cpuUsage.lineChart": "",
  "console.latency.lineChart": "",
  "console.memoryUsage.lineChart": "",
  "console.empty.context.headline": "",
  "console.empty.context.explanation": "",
  "console.time.controller.absolute": "",
  "console.time.controller.relative": "",
  "console.statusCode.barChart": "",
  "console.statusCode.lineChart": "",
  "console.time.controller.relative.earliest": "",
  "console.time.controller.relative.earliestModifier.seconds.ago": "",
  "console.time.controller.relative.earliestModifier.minutes.ago": "",
  "console.time.controller.relative.earliestModifier.hours.ago": "",
  "console.time.controller.relative.earliestModifier.days.ago": "",
  "console.time.controller.relative.earliestModifier.months.ago": "",
  "console.time.controller.relative.earliestModifier.years.ago": ""
}

```


[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 console/docs/README.md from the console VTEX app.

[Assistant]
Here's the implementation:

```markdown
# React+GraphQL
Example app to show how to create an app using React and GraphQL.

This App acts as a catalog management system and uses some advanced VTEX IO GraphQL features, like `@autopersisted` and `@cacheControl` directives.

## Autopersisted Types
Once a GraphQL type is decorated with the `@autopersisted` directive, VTEX IO Builders automatically generates all CRUD operations for that type. If you want to know more about autopersisted types, read our [wiki](https://github.com/vtex/graphql-server/wiki/Features#autopersisted-types)

## Cached Types
VTEX IO GraphQL increases the performance of your queries by caching types decorated with `@cacheControl` hints directly in the CDN. To know more about GraphQL cache hints, visit [apollo](https://www.apollographql.com/docs/engine/caching.html)

```


[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 console/pages/pages.json from the console VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "routes": {
    "admin/console": {
      "path": "/admin/console"
    },
    "admin/console/publishes": {
      "path": "/admin/console/publishes"
    },
    "admin/console/tab": {
      "path": "/admin/console/*tab"
    }
  },
  "extensions": {
    "admin/console": {
      "component": "vtex.render-runtime/LayoutContainer",
      "props": {
        "elements": [
          "__children__"
        ]
      }
    },
    "admin/console/tab": {
      "component": "Console"
    },
    "admin/console/publishes": {
      "component": "vtex.builder-log/Publishes"
    },
    "admin/navigation/analytics/console": {
      "component": "vtex.admin/InjectNavigationData",
      "props": {
        "icon": "extensions-ic",
        "id": "38",
        "tag": "appframe.new",
        "titleId": "console.menu.title",
        "subItems": [
          {
            "labelId": "console.submenu.metrics",
            "path": "/admin/console/metrics"
          },
          {
            "labelId": "console.submenu.publishes",
            "path": "/admin/console/publishes"
          }
        ]
      }
    }
  }
}

```


[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 console/react/copiedcss.global.css from the console VTEX app.

[Assistant]
Here's the implementation:

```css
@import '~react-select/dist/react-select.css';

@import 'datePicker.css';

html, body {
  height: 100%;
}

.track-1 {
  letter-spacing: 0.2px;
}

.min-h-2 {
  min-height: 2rem;
}

.render-provider {
  height: 100%;
  background-color: #fff;
}

.editor-provider {
  height: 100%;
}

.editor-provider .preview-button {
  display: none;
}

.shadow-editor {
  -webkit-box-shadow: 0px -2px 1px 0px rgba(0, 0, 0, 0.25);
  -moz-box-shadow: 0px -2px 1px 0px rgba(0, 0, 0, 0.25);
  box-shadow: 0px -2px 1px 0px rgba(0, 0, 0, 0.25);
}

.form-group {
  padding-top: 10px;
  padding-bottom: 10px;
}

.form-group.field.field-object > label {
  border-top: 2px solid #f0f2f4;
  color: #c3c4c5;
  font-weight: 700;
  margin-top: 10px;
  padding: 20px 0px 5px;
  text-transform: uppercase;
}

.form-group.field.field-object:first-child > label {
  border-top: none;
  margin-top: 0;
  padding-top: 0;
}

.checkbox span {
  padding-left: 5px;
  font-size: 0.875rem;
}

.editor-form {
  padding: 15px 24px 0px;
  overflow-x: hidden;
}

.field-description {
  font-size: 12px;
  color: #979899;
  margin-top: 0px;
  font-style: italic;
}

.editor-form > label {
  padding: 0px !important;
  margin: 0px !important;
}

.form-control {
  border: 2px solid #e1e3e5;
  height: 40px;
  width: 100%;
  font-size: 14px;
  padding-left: 12px;
  background-color: #ffffff;
}

.draggable {
  cursor: move;
}

.h-3em {
  height: 48px;
}

.build-status {
  top: 0 !important;
  left: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background-color: #fff !important;
  margin: 11px !important;
  padding: 0 !important;
}

.build-status.reload {
  margin-top: 0 !important;
  width: 100% !important;
  height: 46px !important;
}

.build-status.fail {
  margin-top: 0 !important;
  width: 100% !important;
  height: 46px !important;
}

.radio-inline > span > span {
  padding-left: 5px;
  padding-right: 15px;
}

.editor-form .vtex-textarea textarea {
  max-width: 100%;
  min-width: 100%;
}

.field-range-wrapper > input {
  width: 80%;
}

.field-range-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.field-range-wrapper > span {
  font-size: 16px;
  font-weight: 700;
  padding-right: 3px;
  color: #368df7;
}

.panel-danger {
  position: fixed;
  width: 100%;
}

@media only screen and (max-width: 40em) {
  .size-editor {
    bottom: 0;
    height: 100%;
  }
}

@media only screen and (min-width: 40em) {
  .field-range-wrapper > input {
    width: 85%;
  }
  .form-schema {
    min-height: 300px;
  }
  .size-editor {
    max-width: 450px;
  }
  .shadow-editor-desktop {
    -webkit-box-shadow: 0px 4px 10px 0px rgba(86, 88, 107, 0.5);
    -moz-box-shadow: 0px 4px 10px 0px rgba(86, 88, 107, 0.5);
    box-shadow: 0px 4px 10px 0px rgba(86, 88, 107, 0.5);
  }
}

.calc--height-relative {
  height: calc(100% - 3em);
}

/* Non small */
@media screen and (min-width: 30em) {
  .h-3em-ns {
    height: 3em;
  }
  .calc--height-ns {
    height: calc(100vh - 3em);
  }
  .calc--height-relative-ns {
    height: calc(100% - 3em);
  }
  .top-3em-ns {
    top: 3em;
  }
  .calc--width-ns {
    width: calc(100% - 18em);
  }
  .calc--minified-width-ns {
    width: calc(100% - 3em);
  }
  .w-3em-ns {
    width: 3em;
  }
  .w-18em-ns {
    width: 18em;
  }

  .admin-sidebar {
    border-left: 2px solid #f2f4f5;
  }

  .admin-sidebar::-webkit-scrollbar,
  .admin-sidebar::-webkit-scrollbar-track {
    width: 2px;
    background: #f2f4f5;
  }

  .admin-sidebar::-webkit-scrollbar-thumb {
    width: 2px;
    background: rgba(0, 0, 0, 0.2);
    border-radius: 2px;
  }
}

.mobile-preview {
  width: 360px;
  height: 640px;
  overflow-x: hidden;
  box-shadow: 1px 4px 8px rgba(0, 0, 0, 0.2);
}

.tablet-preview {
  width: 768px;
  height: 1024px;
  overflow-x: hidden;
  box-shadow: 1px 4px 8px rgba(0, 0, 0, 0.2);
}

.stroke-blue {
  stroke: #368df7;
}

.stroke-mid-gray {
  stroke: #727273;
}

.fill-blue {
  fill: #368df7;
}

.fill-mid-gray {
  fill: #727273;
}

.accordion-list-container--sorting .accordion-item {
  pointer-events: none;
}

.accordion-item {
  transition: height 300ms ease-in-out, opacity 150ms ease-in-out;
  background-color: white;
}

.accordion-item--dragged {
  z-index: 999;
}

.accordion-label {
  display: flex;
  position: relative;
  justify-content: space-between;
  margin: 0 -24px 0;
  height: 57px;
  padding: 19px 16.5px 14px 16px;
  cursor: pointer;
  user-select: none;
}

.accordion-content .accordion-label {
  margin-left: 0;
}

.accordion-content .accordion-content {
  padding-left: 14px;
}

.accordion-item--dragged .accordion-label,
.accordion-label:hover {
  background-color: #f2f4f5;
  padding-left: 26px;
}

.accordion-item--handle-hidden .accordion-label {
  padding-left: 16px;
}

.accordion-item--dragged .accordion-label {
  box-shadow: 4px 4px 8px 0 rgba(0, 0, 0, 0.2);
}

.accordion-label-buttons {
  display: none;
}

.accordion-label:hover .accordion-label-buttons {
  display: flex;
}

.accordion-label-title {
  color: #727273;
  font-weight: bold;
  cursor: pointer;
}

.accordion-icon-button {
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}

.accordion-icon-button--remove {
  margin-left: 17px;
}

.accordion-icon-button--down {
  margin-left: 8px;
}

.editor-icon--stroke path,
.editor-icon--stroke circle {
  stroke: #727273;
}

.editor-icon--fill path,
.editor-icon--fill circle {
  fill: #727273;
}

.accordion-icon-button:hover .editor-icon--stroke path,
.accordion-icon-button:hover .editor-icon--stroke circle {
  stroke: #368df7;
}

.accordion-icon-button:hover .editor-icon--fill path,
.accordion-icon-button:hover .editor-icon--fill circle {
  fill: #368df7;
}

.accordion-handle {
  display: none;
  position: absolute;
  left: 5px;
  padding: 3px;
}

.accordion-item--dragged .accordion-handle,
.accordion-label:hover .accordion-handle {
  display: block;
}

.accordion-item--dragged .accordion-content {
  display: none;
}

.iframe-pointer-none {
  pointer-events: none;
}

```


[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 console/react/datePicker.css from the console VTEX app.

[Assistant]
Here's the implementation:

```css
@charset "UTF-8";
.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow,
.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle,
.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle {
  margin-left: -8px;
  position: absolute;
}
.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow,
.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle,
.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle,
.react-datepicker__year-read-view--down-arrow::before,
.react-datepicker__month-read-view--down-arrow::before,
.react-datepicker__month-year-read-view--down-arrow::before,
.react-datepicker-popper[data-placement^="top"]
  .react-datepicker__triangle::before,
.react-datepicker-popper[data-placement^="bottom"]
  .react-datepicker__triangle::before {
  box-sizing: content-box;
  position: absolute;
  border: 8px solid transparent;
  height: 0;
  width: 1px;
}
.react-datepicker__year-read-view--down-arrow::before,
.react-datepicker__month-read-view--down-arrow::before,
.react-datepicker__month-year-read-view--down-arrow::before,
.react-datepicker-popper[data-placement^="top"]
  .react-datepicker__triangle::before,
.react-datepicker-popper[data-placement^="bottom"]
  .react-datepicker__triangle::before {
  content: "";
  z-index: -1;
  border-width: 8px;
  left: -8px;
  border-bottom-color: #e3e4e6;
}

.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle {
  top: 0;
  margin-top: -8px;
}
.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle,
.react-datepicker-popper[data-placement^="bottom"]
  .react-datepicker__triangle::before {
  border-top: none;
  border-bottom-color: #f0f0f0;
}
.react-datepicker-popper[data-placement^="bottom"]
  .react-datepicker__triangle::before {
  top: -1px;
  border-bottom-color: #e3e4e6;
}

.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow,
.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle {
  bottom: 0;
  margin-bottom: -8px;
}
.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow,
.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle,
.react-datepicker__year-read-view--down-arrow::before,
.react-datepicker__month-read-view--down-arrow::before,
.react-datepicker__month-year-read-view--down-arrow::before,
.react-datepicker-popper[data-placement^="top"]
  .react-datepicker__triangle::before {
  border-bottom: none;
  border-top-color: #fff;
}
.react-datepicker__year-read-view--down-arrow::before,
.react-datepicker__month-read-view--down-arrow::before,
.react-datepicker__month-year-read-view--down-arrow::before,
.react-datepicker-popper[data-placement^="top"]
  .react-datepicker__triangle::before {
  bottom: -1px;
  border-top-color: #e3e4e6;
}

.react-datepicker-wrapper {
  display: inline-block;
}

.react-datepicker {
  font-family: Fabriga, -apple-system, BlinkMacSystemFont, avenir next, avenir,
    helvetica neue, helvetica, ubuntu, roboto, noto, segoe ui, arial, sans-serif;
  font-size: 0.8rem;
  background-color: white;
  color: #142032;
  border: 1px solid #e3e4e6;
  border-radius: 0.3rem;
  display: inline-block;
  position: relative;
}

.react-datepicker--time-only .react-datepicker__triangle {
  left: 35px;
}
.react-datepicker--time-only .react-datepicker__time-container {
  border-left: 0;
}
.react-datepicker--time-only .react-datepicker__time {
  border-radius: 0.3rem;
}
.react-datepicker--time-only .react-datepicker__time-box {
  border-radius: 0.3rem;
}

.react-datepicker__triangle {
  position: absolute;
  left: 50px;
}

.react-datepicker-popper {
  z-index: 1;
}
.react-datepicker-popper[data-placement^="bottom"] {
  margin-top: 10px;
}
.react-datepicker-popper[data-placement^="top"] {
  margin-bottom: 10px;
}
.react-datepicker-popper[data-placement^="right"] {
  margin-left: 8px;
}
.react-datepicker-popper[data-placement^="right"] .react-datepicker__triangle {
  left: auto;
  right: 42px;
}
.react-datepicker-popper[data-placement^="left"] {
  margin-right: 8px;
}
.react-datepicker-popper[data-placement^="left"] .react-datepicker__triangle {
  left: 42px;
  right: auto;
}

.react-datepicker__header {
  text-align: center;
  background-color: #f0f0f0;
  border-bottom: 1px solid #e3e4e6;
  border-top-left-radius: 0.3rem;
  border-top-right-radius: 0.3rem;
  padding-top: 8px;
  position: relative;
}
.react-datepicker__header--time {
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

.react-datepicker__year-dropdown-container--select,
.react-datepicker__month-dropdown-container--select,
.react-datepicker__month-year-dropdown-container--select,
.react-datepicker__year-dropdown-container--scroll,
.react-datepicker__month-dropdown-container--scroll,
.react-datepicker__month-year-dropdown-container--scroll {
  display: inline-block;
  margin: 0 2px;
}

.react-datepicker__current-month,
.react-datepicker-time__header {
  margin-top: 0;
  color: #000;
  font-weight: bold;
  font-size: 0.944rem;
}

.react-datepicker-time__header {
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}

.react-datepicker__navigation {
  background: none;
  line-height: 1.7rem;
  text-align: center;
  cursor: pointer;
  position: absolute;
  top: 10px;
  width: 0;
  padding: 0;
  border: 0.45rem solid transparent;
  z-index: 1;
}
.react-datepicker__navigation--previous {
  left: 10px;
  border-right-color: #ccc;
}
.react-datepicker__navigation--previous:hover {
  border-right-color: #b3b3b3;
}
.react-datepicker__navigation--previous--disabled,
.react-datepicker__navigation--previous--disabled:hover {
  border-right-color: #e6e6e6;
  cursor: default;
}
.react-datepicker__navigation--next {
  right: 10px;
  border-left-color: #ccc;
}
.react-datepicker__navigation--next--with-time:not(.react-datepicker__navigation--next--with-today-button) {
  right: 80px;
}
.react-datepicker__navigation--next:hover {
  border-left-color: #b3b3b3;
}
.react-datepicker__navigation--next--disabled,
.react-datepicker__navigation--next--disabled:hover {
  border-left-color: #e6e6e6;
  cursor: default;
}
.react-datepicker__navigation--years {
  position: relative;
  top: 0;
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.react-datepicker__navigation--years-previous {
  top: 4px;
  border-top-color: #ccc;
}
.react-datepicker__navigation--years-previous:hover {
  border-top-color: #b3b3b3;
}
.react-datepicker__navigation--years-upcoming {
  top: -4px;
  border-bottom-color: #ccc;
}
.react-datepicker__navigation--years-upcoming:hover {
  border-bottom-color: #b3b3b3;
}

.react-datepicker__month-container {
  float: left;
}

.react-datepicker__month {
  margin: 0.4rem;
  text-align: center;
}

.react-datepicker__time-container {
  float: right;
  border-left: 1px solid #e3e4e6;
  width: 70px;
}
.react-datepicker__time-container--with-today-button {
  display: inline;
  border: 1px solid #e3e4e6;
  border-radius: 0.3rem;
  position: absolute;
  right: -72px;
  top: 0;
}
.react-datepicker__time-container .react-datepicker__time {
  position: relative;
  background: white;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box {
  width: 70px;
  overflow-x: hidden;
  margin: 0 auto;
  text-align: center;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list {
  list-style: none;
  margin: 0;
  height: calc(195px + (1.7rem / 2));
  overflow-y: scroll;
  padding-right: 30px;
  padding-left: 0px;
  width: 100%;
  box-sizing: content-box;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item {
  padding: 5px 10px;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item:hover {
  cursor: pointer;
  background-color: #f0f0f0;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item--selected {
  background-color: #368df7;
  color: white;
  font-weight: bold;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item--selected:hover {
  background-color: #368df7;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item--disabled {
  color: #ccc;
}
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item--disabled:hover {
  cursor: default;
  background-color: transparent;
}

.react-datepicker__week-number {
  color: #ccc;
  display: inline-block;
  width: 1.7rem;
  line-height: 1.7rem;
  text-align: center;
  margin: 0.166rem;
}
.react-datepicker__week-number.react-datepicker__week-number--clickable {
  cursor: pointer;
}
.react-datepicker__week-number.react-datepicker__week-number--clickable:hover {
  border-radius: 0.3rem;
  background-color: #f0f0f0;
}

.react-datepicker__day-names,
.react-datepicker__week {
  white-space: nowrap;
}

.react-datepicker__day-name,
.react-datepicker__day,
.react-datepicker__time-name {
  color: #000;
  display: inline-block;
  width: 1.7rem;
  line-height: 1.7rem;
  text-align: center;
  margin: 0.166rem;
}

.react-datepicker__day {
  cursor: pointer;
}
.react-datepicker__day:hover {
  border-radius: 0.3rem;
  background-color: #f0f0f0;
}
.react-datepicker__day--today {
  font-weight: bold;
}
.react-datepicker__day--highlighted {
  border-radius: 0.3rem;
  background-color: #3dcc4a;
  color: #fff;
}
.react-datepicker__day--highlighted:hover {
  background-color: #32be3f;
}
.react-datepicker__day--highlighted-custom-1 {
  color: magenta;
}
.react-datepicker__day--highlighted-custom-2 {
  color: green;
}
.react-datepicker__day--selected,
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range {
  border-radius: 0.3rem;
  background-color: #368df7;
  color: #fff;
}
.react-datepicker__day--selected:hover,
.react-datepicker__day--in-selecting-range:hover,
.react-datepicker__day--in-range:hover {
  background-color: #2a6dbf;
}
.react-datepicker__day--keyboard-selected {
  border-radius: 0.3rem;
  background-color: #368df7;
  color: #fff;
}
.react-datepicker__day--keyboard-selected:hover {
  background-color: #2a6dbf;
}
.react-datepicker__day--in-selecting-range:not(.react-datepicker__day--in-range) {
  background-color: rgba(33, 107, 165, 0.5);
}
.react-datepicker__month--selecting-range
  .react-datepicker__day--in-range:not(.react-datepicker__day--in-selecting-range) {
  background-color: #f0f0f0;
  color: #000;
}
.react-datepicker__day--disabled {
  cursor: default;
  color: #ccc;
}
.react-datepicker__day--disabled:hover {
  background-color: transparent;
}

.react-datepicker__input-container {
  position: relative;
  display: inline-block;
  color: #3f3f40;
  font-size: 0.875rem;
  border-width: 0.125rem;
  border-color: #e3e4e6;
}

.react-datepicker__year-read-view,
.react-datepicker__month-read-view,
.react-datepicker__month-year-read-view {
  border: 1px solid transparent;
  border-radius: 0.3rem;
}
.react-datepicker__year-read-view:hover,
.react-datepicker__month-read-view:hover,
.react-datepicker__month-year-read-view:hover {
  cursor: pointer;
}
.react-datepicker__year-read-view:hover
  .react-datepicker__year-read-view--down-arrow,
.react-datepicker__year-read-view:hover
  .react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-read-view:hover
  .react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view:hover
  .react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view:hover
  .react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-year-read-view:hover
  .react-datepicker__month-read-view--down-arrow {
  border-top-color: #b3b3b3;
}
.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow {
  border-top-color: #ccc;
  float: right;
  margin-left: 20px;
  top: 8px;
  position: relative;
  border-width: 0.45rem;
}

.react-datepicker__year-dropdown,
.react-datepicker__month-dropdown,
.react-datepicker__month-year-dropdown {
  background-color: #f0f0f0;
  position: absolute;
  width: 50%;
  left: 25%;
  top: 30px;
  z-index: 1;
  text-align: center;
  border-radius: 0.3rem;
  border: 1px solid #e3e4e6;
}
.react-datepicker__year-dropdown:hover,
.react-datepicker__month-dropdown:hover,
.react-datepicker__month-year-dropdown:hover {
  cursor: pointer;
}
.react-datepicker__year-dropdown--scrollable,
.react-datepicker__month-dropdown--scrollable,
.react-datepicker__month-year-dropdown--scrollable {
  height: 150px;
  overflow-y: scroll;
}

.react-datepicker__year-option,
.react-datepicker__month-option,
.react-datepicker__month-year-option {
  line-height: 20px;
  width: 100%;
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.react-datepicker__year-option:first-of-type,
.react-datepicker__month-option:first-of-type,
.react-datepicker__month-year-option:first-of-type {
  border-top-left-radius: 0.3rem;
  border-top-right-radius: 0.3rem;
}
.react-datepicker__year-option:last-of-type,
.react-datepicker__month-option:last-of-type,
.react-datepicker__month-year-option:last-of-type {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  border-bottom-left-radius: 0.3rem;
  border-bottom-right-radius: 0.3rem;
}
.react-datepicker__year-option:hover,
.react-datepicker__month-option:hover,
.react-datepicker__month-year-option:hover {
  background-color: #ccc;
}
.react-datepicker__year-option:hover
  .react-datepicker__navigation--years-upcoming,
.react-datepicker__month-option:hover
  .react-datepicker__navigation--years-upcoming,
.react-datepicker__month-year-option:hover
  .react-datepicker__navigation--years-upcoming {
  border-bottom-color: #b3b3b3;
}
.react-datepicker__year-option:hover
  .react-datepicker__navigation--years-previous,
.react-datepicker__month-option:hover
  .react-datepicker__navigation--years-previous,
.react-datepicker__month-year-option:hover
  .react-datepicker__navigation--years-previous {
  border-top-color: #b3b3b3;
}
.react-datepicker__year-option--selected,
.react-datepicker__month-option--selected,
.react-datepicker__month-year-option--selected {
  position: absolute;
  left: 15px;
}

.react-datepicker__close-icon {
  background-color: transparent;
  border: 0;
  cursor: pointer;
  display: inline-block;
  height: 0;
  outline: 0;
  padding: 0;
  vertical-align: middle;
}
.react-datepicker__close-icon::after {
  background-color: #368df7;
  border-radius: 50%;
  bottom: 0;
  box-sizing: border-box;
  color: #fff;
  content: "×";
  cursor: pointer;
  font-size: 12px;
  height: 16px;
  width: 16px;
  line-height: 1;
  margin: -8px auto 0;
  padding: 2px;
  position: absolute;
  right: 7px;
  text-align: center;
  top: 50%;
}

.react-datepicker__today-button {
  background: #f0f0f0;
  border-top: 1px solid #e3e4e6;
  cursor: pointer;
  text-align: center;
  font-weight: bold;
  padding: 5px 0;
  clear: left;
}

.react-datepicker__portal {
  position: fixed;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.8);
  left: 0;
  top: 0;
  justify-content: center;
  align-items: center;
  display: flex;
  z-index: 2147483647;
}
.react-datepicker__portal .react-datepicker__day-name,
.react-datepicker__portal .react-datepicker__day,
.react-datepicker__portal .react-datepicker__time-name {
  width: 3rem;
  line-height: 3rem;
}
@media (max-width: 400px), (max-height: 550px) {
  .react-datepicker__portal .react-datepicker__day-name,
  .react-datepicker__portal .react-datepicker__day,
  .react-datepicker__portal .react-datepicker__time-name {
    width: 2rem;
    line-height: 2rem;
  }
}
.react-datepicker__portal .react-datepicker__current-month,
.react-datepicker__portal .react-datepicker-time__header {
  font-size: 1.44rem;
}
.react-datepicker__portal .react-datepicker__navigation {
  border: 0.81rem solid transparent;
}
.react-datepicker__portal .react-datepicker__navigation--previous {
  border-right-color: #ccc;
}
.react-datepicker__portal .react-datepicker__navigation--previous:hover {
  border-right-color: #b3b3b3;
}
.react-datepicker__portal .react-datepicker__navigation--previous--disabled,
.react-datepicker__portal
  .react-datepicker__navigation--previous--disabled:hover {
  border-right-color: #e6e6e6;
  cursor: default;
}
.react-datepicker__portal .react-datepicker__navigation--next {
  border-left-color: #ccc;
}
.react-datepicker__portal .react-datepicker__navigation--next:hover {
  border-left-color: #b3b3b3;
}
.react-datepicker__portal .react-datepicker__navigation--next--disabled,
.react-datepicker__portal .react-datepicker__navigation--next--disabled:hover {
  border-left-color: #e6e6e6;
  cursor: default;
}

/*# sourceMappingURL=react-datepicker.css.map */

```


[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 console/react/package.json from the console VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "apollo-client": "^2.4.8",
    "graphql": "^14.0.2",
    "moment": "^2.22.2",
    "prop-types": "^15.6.2",
    "ramda": "^0.26.1",
    "react": "^16.5.2",
    "react-apollo": "^2.2.4",
    "react-datepicker": "^1.7.0",
    "react-intl": "^2.7.1",
    "react-vega": "^4.0.2",
    "recharts": "^1.4.2",
    "semver": "^5.6.0",
    "vega-lib": "^4.3.0"
  },
  "devDependencies": {
    "@types/history": "^4.7.2",
    "@types/moment": "^2.13.0",
    "@types/node": "^10.12.0",
    "@types/ramda": "^0.25.47",
    "@types/react": "^16.4.17",
    "@types/react-intl": "^2.3.11",
    "@types/recharts": "^1.1.6",
    "@types/semver": "^5.5.0",
    "@types/vega": "^0.0.30",
    "tslint": "^5.11.0",
    "tslint-config-vtex": "^2.0.0",
    "typescript": "3.7.3"
  },
  "scripts": {
    "lint": "tsc --noEmit && tslint -c tslint.json './**/*.ts'"
  },
  "version": "0.6.1"
}

```


[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 console/react/Console.tsx from the console VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { pluck } from 'ramda'
import React, { Component } from 'react'
import { InjectedIntlProps, injectIntl } from 'react-intl'
import { withRuntimeContext } from 'render'
import { PageHeader, Tab, Tabs } from 'vtex.styleguide'

import Errors from './components/Errors'
import Metrics from './components/Metrics'
import StylesContainer from './components/StylesContainer'

interface Props extends InjectedIntlProps {
  params: {
    tab: string
  }
  runtime: RenderContext
}

interface Field {
  path: string
  name: string
  titleId: string
}

const DivHeight = { minHeight: 'calc(100vh - 3em)' }

const fields: Field[] = [
  {
    name: 'metrics',
    path: 'metrics',
    titleId: 'console.admin.tabs.metrics',
  },
]

class Console extends Component<Props, {}> {

  public componentDidMount() {
    window.postMessage({ action: { type: 'STOP_LOADING' } }, '*')
  }

  public render() {
    const {
      params: { tab },
      intl,
      runtime: { navigate },
    } = this.props

    if (!pluck('name', fields).includes(tab)) {
      navigate({ to: '/admin/console/metrics' })
    }

    return (
      <div className="bg-muted-5" style={DivHeight}>
        <div className="w-90 center">
          <PageHeader title="IO Console" />
          <Tabs>
            {fields.map(({ name, path, titleId }: Field) => (
              <Tab
                key={name}
                label={intl.formatMessage({ id: titleId })}
                active={tab === path}
                onClick={() => navigate({ to: `/admin/console/${path}` })}
              />
            ))}
          </Tabs>
        </div>
        <div>
          <StylesContainer>
            {tab === 'metrics' && <Metrics />}
          </StylesContainer>
        </div>
      </div>
    )
  }
}

export default withRuntimeContext(injectIntl(Console))

```


[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 console/react/typings/events.d.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface EventWithValue extends Event {
  value: 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 console/react/typings/render.d.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'render' {
  import { Component, ReactElement } from 'react'

  export interface NavigationOptions {
    page: string
    params?: any
  }

  export interface RenderContextProps {
    runtime: {
      navigate: (options: NavigationOptions) => void
    }
  }

  export const ExtensionPoint: ReactElement
  export const Helmet: ReactElement
  export const Link: ReactElement
  export const NoSSR: ReactElement
  export const RenderContextConsumer: ReactElement
  export const canUseDOM: boolean
  export const withRuntimeContext: <TOriginalProps extends {}>(
    Component: ComponentType<TOriginalProps & RenderContextProps>
  ) => ComponentType<TOriginalProps>

  export const buildCacheLocator = (app: string, type: string, cacheId: string) => string

  interface RenderComponent<P = {}, S = {}> extends Component<P, S> {
    getCustomMessages?: (locale: string) => any
    schema: ComponentSchema
    getSchema?: (a: any, b: any?) => ComponentSchema
    uiSchema: UISchema
  }

  export interface ComponentsRegistry {
    [component: string]: RenderComponent<any, any>
  }

  export interface Window extends Window {
    __RENDER_7_COMPONENTS__: ComponentsRegistry
  }

  let global: Window
}

```


[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 console/react/typings/gql.d.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.graphql' {
  import { DocumentNode } from 'graphql'

  const value: DocumentNode
  export default 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 console/react/typings/global.d.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface RenderContext {
  account: RenderRuntime['account']
  components: RenderRuntime['components']
  culture: RenderRuntime['culture']
  device: ConfigurationDevice
  emitter: RenderRuntime['emitter']
  extensions: RenderRuntime['extensions']
  fetchComponent: (component: string) => Promise<void>
  getSettings: (app: string) => any
  history: any | null
  navigate: (options: NavigateOptions) => boolean
  onPageChanged: (location: Location) => void
  page: RenderRuntime['page']
  pages: RenderRuntime['pages']
  prefetchPage: (name: string) => Promise<void>
  production: RenderRuntime['production']
  setDevice: (device: ConfigurationDevice) => void
  updateComponentAssets: (availableComponents: Components) => void
  updateExtension: (name: string, extension: Extension) => void
  updateRuntime: (options?: PageContextOptions) => Promise<void>
  workspace: RenderRuntime['workspace']
}

interface NavigateOptions {
  page?: string
  params?: any
  query?: any
  to?: string
  scrollOptions?: RenderScrollOptions
  fallbackToWindowLocation?: boolean
}

interface AppController {
  appName?: string
  appVersion?: string
  region?: string
  production?: string
}

interface TimeController {
  startDate?: Date
  endDate?: Date
  mode?: TimeRange
}

type TimeRange = 'absolute' | 'relative'

type SetTimeControllers = (timeControllers: TimeController) => void

type SetAppControllers = (appControllers: AppController) => void

```


[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 console/react/typings/vtex.styleguide.d.ts from the console VTEX app.

[Assistant]
Here's the implementation:

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

  const Badge: ReactElement
  const Button: ReactElement
  const Checkbox: ReactElement
  const DatePicker: ReactElement
  const Dropdown: ReactElement
  const EmptyState: ReactElement
  const IconCaretRight: ReactElement
  const Input: ReactElement
  const Layout: ReactElement
  const NumericStepper: ReactElement
  const Tab: ReactElement
  const Tabs: ReactElement
  const Textarea: ReactElement
  const Radio: ReactElement
  const RadioGroup: ReactElement
  const Spinner: ReactElement
  const PageHeader: ReactElement
  const PageBlock: ReactElement

  export { Button, Dropdown, DatePicker, EmptyState, Input, Layout, NumericStepper, Tab, Tabs, Radio, RadioGroup, Spinner, PageBlock, PageHeader }
}

```


[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 console/react/components/Errors.tsx from the console VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { EmptyState } from 'vtex.styleguide'

const Errors = () => {
  return (
    <EmptyState title="Coming Soon">
      <p>
        Coming soon!
      </p>
    </EmptyState>
  )
}

export default Errors

```


[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 console/react/components/StylesContainer.tsx from the console VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface Props {
  children: React.ReactNode
}

const StylesContainer: React.SFC<Props> = (props) => (
  <div className="w-90 mt7 mr-auto ml-auto">{props.children}</div>
)

export default StylesContainer

```


[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 console/react/common/utils.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { compose, map, uniqWith } from 'ramda'
import { InjectedIntl } from 'react-intl'

export interface Option {
  label: string
  value: string
}

export const adjustStartDate = (earliestSize: number, earliestModifier: string) => {
  const startDate: Date = new Date()
  switch (earliestModifier) {
    case 'Seconds Ago':
      startDate.setSeconds(startDate.getSeconds() - earliestSize)
      return startDate
    case 'Minutes Ago':
      startDate.setMinutes(startDate.getMinutes() - earliestSize)
      return startDate
    case 'Hours Ago':
      startDate.setHours(startDate.getHours() - earliestSize)
      return startDate
    case 'Days Ago':
      startDate.setDate(startDate.getDate() - earliestSize)
      return startDate
    case 'Months Ago':
      startDate.setMonth(startDate.getMonth() - earliestSize)
      return startDate
    case 'Years Ago':
      startDate.setFullYear(startDate.getFullYear() - earliestSize)
      return startDate
    default:
      startDate.setHours(startDate.getHours() - earliestSize)
      return startDate
  }
}

export const adjustStartDateHour = () => {
  const date = new Date()
  date.setHours(date.getHours() - 1)
  return date
}

export const adjustEndDate = (endDate: Date) => {
  // always decrease one second to avoid taking the next bucket
  endDate.setSeconds(endDate.getSeconds() - 1)
  return endDate
}

export const getAppVersion = (chosenMajor: string, chosenMinor: string, chosenPatch: string) => {
  return (chosenMajor && chosenMinor && chosenPatch)
    ? `${chosenMajor}.${chosenMinor}.${chosenPatch}`
    : undefined
}

const strEq = (str1: string, str2: string) => str1 === str2

export const dropdownOptions = (options: string[]) => compose(
  map((optionName: string) => ({ value: optionName, label: optionName })),
  uniqWith(strEq)
)(options)

export const formattedDropdownOptions = (options: Option[], intl: InjectedIntl) => map(
  (option: Option) => {
    return {
      label: intl.formatMessage({ id: option.label, defaultMessage: option.label }),
      value: option.value,
    }
  },
  options)

```


[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 console/react/common/constants.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const CHART_PROPERTIES = {
  height: 250,
  width: '100%',
}

export const colors = ['#1f77b4', '#17becf', '#2ca02c', '#ff7f0e', '#d62728', '#bcbd22', '#8c564b', '#e377c2', '#9467bd', '#7f7f7f']

```


[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 console/react/common/layoutContent.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
import CpuUsageLineChart from '../components/Metrics/DataAnalysis/Charts/CpuUsageLineChart'
import MemoryUsageLineChart from '../components/Metrics/DataAnalysis/Charts/MemoryUsageLineChart'
import StatusCodeBarChart from '../components/Metrics/DataAnalysis/Charts/StatusCodeBarChart'
import StatusCodeLineChart from '../components/Metrics/DataAnalysis/Charts/StatusCodeLineChart'

export default [
  {
    ChartComponent: MemoryUsageLineChart,
    chartType: 'LineChart',
    id: 1,
    storedash: {
      metricParams: {
        fields: 'data.summary.external, data.summary.heapTotal, data.summary.heapUsed, data.summary.rss, count',
        metricName: 'memoryUsage',
        operation: 'sum',
      },
      name: 'runtime',
    },
  },
  {
    ChartComponent: StatusCodeBarChart,
    chartType: 'BarChart',
    id: 2,
    storedash: {
      metricParams: {
        aggregateBy: 'data.key.httpStatus',
        fields: 'data.summary.count',
        metricName: 'routeStats',
        operation: 'sum',
      },
      name: 'runtime',
    },
  },
  {
    ChartComponent: CpuUsageLineChart,
    chartType: 'LineChart',
    id: 3,
    storedash: {
      metricParams: {
        fields: 'data.summary.system, data.summary.user, count',
        metricName: 'cpuUsage',
        operation: 'sum',
      },
      name: 'runtime',
    },
  },
  {
    ChartComponent: StatusCodeLineChart,
    chartType: 'LineChart',
    id: 4,
    storedash: {
      metricParams: {
        aggregateBy: 'data.key.httpStatus',
        fields: 'data.summary.count',
        metricName: 'routeStats',
        operation: 'sum',
      },
      name: 'runtime',
    },
  },
]

```


[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 console/react/common/dataAnalysis.ts from the console VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { addIndex, has, isEmpty, isNil, map } from 'ramda'
import { InjectedIntl } from 'react-intl'

export const isNilOrEmpty = (x: any) => isEmpty(x) || isNil(x)

export const mapIndexed = addIndex(map)

const periodName: string[] = ['s', 'm', 'h', 'd', 'M', 'y']

const periodDuration: number[] = [1, 60, 60 * 60, 24 * 60 * 60, 30 * 24 * 60 * 60, 12 * 30 * 24 * 60 * 60]

const adjustRangeStep = (rangeStepSize: number): string => {
  let i: number = 1
  while (i <= periodName.length && rangeStepSize > periodDuration[i]) {
    i++
  }
  i--
  rangeStepSize = Math.round(rangeStepSize / periodDuration[i])
  return rangeStepSize + periodName[i]
}

export const getRangeStep = (startDate: Date, endDate: Date): string => {
  const elapsedTime: number = ((endDate.getTime() + 1000) - startDate.getTime()) / 1000
  const rangeStepSize = Math.round(elapsedTime / 12)
  const rangeStep = adjustRangeStep(rangeStepSize)
  return rangeStep
}

export const getStepModifier = (metricParams: any): string => {
  let stepModifier = ''
  if (has('interval', metricParams)) {
    stepModifier = metricParams.interval[metricParams.interval.length - 1]
  }
  return stepModifier
}

export const getFormattedTime = (date: any, intl: InjectedIntl, stepModifier: string): string => {
  switch (stepModifier) {
    case 's':
      return intl.formatTime(date, {
        hour: 'numeric',
        minute: 'numeric',
        second: 'numeric',
      })
    case 'm':
      return intl.formatTime(date, {
        hour: 'numeric',
        minute: 'numeric',
      })
    case 'h':
      return intl.formatTime(date, {
        hour: 'numeric',
        minute: 'numeric',
      })
    case 'd':
      return intl.formatDate(date, {
        day: 'numeric',
        month: 'numeric',
        year: 'numeric',
      })
    case 'M':
      return intl.formatDate(date, {
        month: 'numeric',
        year: 'numeric',
      })
    case 'y':
      return intl.formatDate(date, {
        year: 'numeric',
      })
    default:
      return intl.formatDate(date, {
        day: 'numeric',
        hour: 'numeric',
        minute: 'numeric',
        month: 'numeric',
        year: 'numeric',
      })
  }
}

// Source: stackoverflow.com/questions/2685911/is-there-a-way-to-round-numbers-into-a-reader-friendly-format-e-g-1-1k
export const abbrNum = (value: number, decPlaces: number): string => {
  decPlaces = Math.pow(10, decPlaces)
  const abbrev = [' k', ' M', ' G', ' T']

  let tickValue: string = '0'
  for (let i = abbrev.length - 1; i >= 0; i--) {
    const size = Math.pow(10, (i + 1) * 3)

    if (size <= value) {
      value = Math.round((value * decPlaces) / size) / decPlaces

      if (value === 1000 && i < abbrev.length - 1) {
        value = 1
        i++
      }

      tickValue = value + abbrev[i]

      break
    }
  }

  return tickValue
}

export const abbrPerc = (value: any, intl: InjectedIntl): string => {
  return intl.formatNumber(
    Number(value),
    {
      maximumFractionDigits: 2,
      style: 'percent',
    }
  )
}

```


[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 console/react/graphql/data.graphql from the console VTEX app.

[Assistant]
Here's the implementation:

```graphql
query GetData($name: String!, $params:StoreDashInput) {
  data(
    name:$name,
    params: $params
  )
}

```


[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 console/react/components/Metrics/index.tsx from the console VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { Location } from 'history'
import React, { Component } from 'react'
import { FormattedMessage, InjectedIntlProps, injectIntl } from 'react-intl'
import { withRuntimeContext } from 'render'
import { EmptyState } from 'vtex.styleguide'

import layoutContent from '../../common/layoutContent'
import { AppContext } from './Contexts/AppContext'
import { TimeContext } from './Contexts/TimeContext'
import Controllers from './Controllers'
import DataAnalysis from './DataAnalysis'

interface Props extends InjectedIntlProps {
  runtime: RenderContext
}

interface State {
  appControllers: AppController
  timeControllers: TimeController
}

class Metrics extends Component<Props, State> {
  private searchParams: URLSearchParams = new URLSearchParams()
  constructor(props: Props) {
    super(props)
    this.props.runtime.history.listen(this.listenChangesInHistoryLocation)
    this.state = this.stateFromUrl(this.props.runtime.history.location)
  }

  public render() {
    const { appControllers: { appName } } = this.state
    const { timeControllers: { startDate, endDate } } = this.state
    const appContextValue = {
      appControllers: this.state.appControllers,
      setAppControllers: this.setAppControllers,
    }
    const timeContextValue = {
      setTimeControllers: this.setTimeControllers,
      timeControllers: this.state.timeControllers,
    }

    return (
      <AppContext.Provider value={appContextValue}>
        <TimeContext.Provider value={timeContextValue} >
          <div className="flex flex-wrap w-100">
            <div className="w-100">
              <Controllers />
            </div>
            <div className="w-100">
              {appName && startDate && endDate && Array.isArray(layoutContent)
                ? (
                  <DataAnalysis layout={layoutContent} />
                ) : (
                  <EmptyState title={this.props.intl.formatMessage({ id: 'console.empty.context.headline' })}>
                    <FormattedMessage id="console.empty.context.explanation" />
                  </EmptyState>
                )
              }
            </div>
          </div>
        </TimeContext.Provider>
      </AppContext.Provider>
    )
  }

  private setAppControllers = (appControllers: AppController) => {
    if (appControllers.appName) {
      this.searchParams.set('appName', appControllers.appName)
    }
    if (appControllers.appVersion) {
      this.searchParams.set('appVersion', appControllers.appVersion)
    }
    if (appControllers.production) {
      this.searchParams.set('production', appControllers.production)
    }
    if (appControllers.region) {
      this.searchParams.set('region', appControllers.region)
    }

    if (!appControllers.appVersion && this.searchParams.has('appVersion')) {
      this.searchParams.delete('appVersion')
    }

    if (!appControllers.production && this.searchParams.has('production')) {
      this.searchParams.delete('production')
    }

    if (!appControllers.region && this.searchParams.has('region')) {
      this.searchParams.delete('region')
    }

    this.changeCurrentLocationInHistory()
  }

  private setTimeControllers = (timeControllers: TimeController) => {
    if (timeControllers.startDate) {
      this.searchParams.set('startDate', timeControllers.startDate.toString())
    }
    if (timeControllers.endDate) {
      this.searchParams.set('endDate', timeControllers.endDate.toString())
    }
    if (timeControllers.mode) {
      this.searchParams.set('mode', timeControllers.mode)
    }

    this.changeCurrentLocationInHistory()
  }

  private changeCurrentLocationInHistory = () => {
    const { runtime: { history } } = this.props
    const newRelativePathQuery = history.location.pathname + '?' + this.searchParams.toString()
    history.push(newRelativePathQuery)
  }

  private listenChangesInHistoryLocation = (location: Location<any>) => {
    this.setState(this.stateFromUrl(location))
  }

  private stateFromUrl = (location: Location<any>) => {
    this.searchParams = new URLSearchParams(location.search)
    const startDate = this.searchParams.get('startDate')
    const endDate = this.searchParams.get('endDate')
    const mode = this.searchParams.get('mode')
    return {
      appControllers: {
        appName: this.searchParams.get('appName') || '',
        appVersion: this.searchParams.get('appVersion') || '',
        production: this.searchParams.get('production') || '',
        region: this.searchParams.get('region') || '',
      },
      timeControllers: {
        endDate: endDate ? new Date(endDate) : undefined,
        mode: mode as TimeRange,
        startDate: startDate ? new Date(startDate) : undefined,
      },
    }
  }
}

export default withRuntimeContext(injectIntl(Metrics))

```


[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 console/react/components/Metrics/Contexts/TimeContext.tsx from the console VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface TimeContextInterface {
  timeControllers: TimeController
  setTimeControllers: SetTimeControllers
}

export const TimeContext = React.createContext<TimeContextInterface>({
  setTimeControllers: (timeControllers: TimeController) => undefined,
  timeControllers: {
    endDate: new Date(),
    mode: undefined,
    startDate: new Date(),
  },
})

```


[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 console/react/components/Metrics/Contexts/AppContext.tsx from the console VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface AppContextInterface {
  appControllers: AppController
  setAppControllers: SetAppControllers
}

export const AppContext = React.createContext<AppContextInterface>({
  appControllers: {
    appName: '',
    appVersion: '',
    production: 'true',
    region: 'Any',
  },
  setAppControllers: (appControllers: AppController) => undefined,
})

```