[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-locator/cypress/support/commands.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import 'cypress-file-upload'
import selectors from './common/selectors'
import storelocatorSelectors, { getAddressLink } from './selectors.js'

const storelocatorJson = '.storelocator.json'
const fileName = 'pickups.xls'

// Save pickupPoint
Cypress.Commands.add(
  'setPickupPointItem',
  (pickupPointItem, pickupPointValue) => {
    cy.readFile(storelocatorJson).then((items) => {
      items[pickupPointItem] = pickupPointValue
      cy.writeFile(storelocatorJson, items)
    })
  }
)

// Get pickupPoint
Cypress.Commands.add('getPickupPointItem', () => {
  cy.readFile(storelocatorJson).then((items) => {
    return items
  })
})

Cypress.Commands.add('visitStore', () => {
  cy.intercept('**/event-api/v1/*/event').as('events')
  cy.visit('/api/io/stores')
  cy.wait('@events')

  cy.get(selectors.ProfileLabel, { timeout: 20000 })
    .should('be.visible')
    .should('have.contain', `Hello,`)
})

Cypress.Commands.add('verifyPickupPointsInStore', () => {
  cy.getVtexItems().then((vtex) => {
    cy.intercept('POST', `${vtex.baseUrl}/**`, (req) => {
      if (req.body.operationName === 'Session') {
        req.continue()
      }
    }).as('Session')
    cy.visitStore()
    cy.wait('@Session', { timeout: 40000 })
    cy.get(storelocatorSelectors.LoadStores).should('be.visible').click()
    cy.get(storelocatorSelectors.VtexStoreName).contains('pickup example 1')
    cy.get(storelocatorSelectors.VtexStoreName).contains('pickup example 2')
  })
})

Cypress.Commands.add('uploadXLS', () => {
  cy.visit('/admin/app/pickup-points')
  cy.get(storelocatorSelectors.VtexButton).first().should('be.visible')
  cy.contains('Upload a XLS').click()
  cy.get(storelocatorSelectors.UploadInput).attachFile(fileName)
  cy.get(storelocatorSelectors.CloseIcon).should('be.visible').click()
  cy.get(storelocatorSelectors.VtexAlert, { timeout: 15000 }).should(
    'be.visible'
  )
})

Cypress.Commands.add('verifyDetailsInDetailPage', () => {
  cy.get(storelocatorSelectors.VtexStoreName).then(($els) => {
    const storeLocatorsNames = [...$els].map((el) => el.innerText)
    const indexOfNsmr = storeLocatorsNames.indexOf('pickup example 2')

    cy.get(getAddressLink(indexOfNsmr)).click()
    cy.get(storelocatorSelectors.HoursContainer).should('be.visible')
  })
})

```


[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-locator/cypress/support/common.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { updateRetry } from './common/support'
import storeLocatorSelectors from './selectors.js'
import { INTIAL_PICKUP_POINTS_ENV } from './api_testcase'
import selectors from './common/selectors'

export function addPickUpPoint(pickPointName) {
  cy.visit('/admin/app/pickup-points')

  cy.get(storeLocatorSelectors.AddPickUpButton)
    .contains('Add Pickup Point')
    .click()
  cy.get(selectors.PickUpPointName).clear().type(pickPointName)
  cy.get(selectors.PickUpPointId).should('be.visible').type('1')
  cy.get('select')
    .select('United States of America')
    .should('have.value', 'USA')
  /* eslint-disable cypress/no-unnecessary-waiting */
  cy.wait(1000)
  /* eslint-disable cypress/no-unnecessary-waiting */
  cy.get(selectors.PickUpAddress)
    .type('1279 Shinn Street Fremont CA,USA', { delay: 50 })
    .wait(500)
    .type('{downarrow}{enter}')
  cy.get(selectors.CheckBox).click()
  cy.get(selectors.WorkStartTime).eq(1).type('10:00')
  cy.get(selectors.WorkEndTime).eq(1).type('19:00')
  cy.get(storeLocatorSelectors.SaveChanges).contains('Save Changes').click()
  cy.get(storeLocatorSelectors.ChangesSaved, { timeout: 10000 })
    .should('be.visible')
    .contains('Changes saved')
}

export function clickLoadAllStores() {
  cy.get('body').then(($body) => {
    if ($body.find(storeLocatorSelectors.LoadStores).length) {
      cy.get(storeLocatorSelectors.LoadStores, { timeout: 15000 })
        .should('be.visible')
        .click()
    }
  })
}

export function verifyAllPickUpPoint() {
  cy.visitStore()
  cy.get(storeLocatorSelectors.ListOfStores).should('be.visible')
  clickLoadAllStores()

  cy.getPickupPointItem().then((pickupCount) => {
    cy.get(storeLocatorSelectors.MoreItems).should(
      'have.length',
      pickupCount[INTIAL_PICKUP_POINTS_ENV] + 4
    )
    cy.get(storeLocatorSelectors.MoreItems)
      .its('length')
      .then((itemLen) => {
        for (let i = 0; i < itemLen; i++) {
          clickLoadAllStores()
          cy.get(storeLocatorSelectors.MoreItems)
            .eq(i)
            .scrollIntoView()
            .should('be.visible')
            .click()
          cy.get(storeLocatorSelectors.AddressContainer, {
            timeout: 20000,
          }).should('be.visible')
          cy.get(storeLocatorSelectors.HoursContainer).should('be.visible')
          cy.get(storeLocatorSelectors.BackToPickUpPoint)
            .should('be.visible')
            .click()
          cy.get(storeLocatorSelectors.MoreItems).should('be.visible')
        }
      })
  })
}

export function updateShippingPolicyStatus(status) {
  it('Link pickup point', updateRetry(2), () => {
    cy.visit('/admin/app/shipping-strategy/shipping-policy/?id=sha1920ede3r')
    cy.get('#name').should('be.visible')
    cy.get('body').then(($body) => {
      if (
        $body.find(storeLocatorSelectors.ShippingPolicyActiveStatus).length > 0
      ) {
        if (status === true) {
          cy.log('Shipping policy already in active status')
        } else {
          cy.get(storeLocatorSelectors.ShippingPolicyStatusToggle).click()
          cy.get(storeLocatorSelectors.ShippingPolicySaveChanges).click()
        }
      } else if (status === true) {
        cy.get(storeLocatorSelectors.ShippingPolicyStatusToggle).click()
        cy.get(storeLocatorSelectors.ShippingPolicySaveChanges).click()
      } else {
        cy.log('Shipping policy already in inactive status')
      }
    })
  })
}

```


[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-locator/cypress/support/apis.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
export default {
  getPickupPoints: (baseUrl) => {
    return `${baseUrl}/api/logistics/pvt/configuration/pickuppoints`
  },
  createPickupPoint: (baseUrl) => {
    return `${baseUrl}/api/logistics/pvt/configuration/pickuppoints`
  },
  updatePickupPoint: (baseUrl) => {
    return `${baseUrl}/api/logistics/pvt/configuration/pickuppoints`
  },
  getPickupPointById: (baseUrl, pickupPointid) => {
    return `${baseUrl}/api/logistics/pvt/configuration/pickuppoints/${pickupPointid}`
  },
  deletePickupPoint: (baseUrl, pickupPointid) => {
    return `${baseUrl}/api/logistics/pvt/configuration/pickuppoints/${pickupPointid}`
  },
  searchPickupPoint: (baseUrl) => {
    return `${baseUrl}/api/logistics/pvt/configuration/pickuppoints/_search`
  },
}

```


[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-locator/cypress/support/graphql_testcase.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
export function updateShippingPolicy(data, { status = false, pickup = true }) {
  data.shippingPolicy.isActive = status
  data.shippingPolicy.deliveryChannel = pickup ? 'pickup-in-point' : 'delivery'
  const query =
    'mutation' +
    '( $shippingPolicy: ShippingPolicyInput!)' +
    '{updateShippingPolicy(shippingPolicy:$shippingPolicy){id, name}}'

  return {
    query,
    queryVariables: data,
  }
}

export function getStores(latitude, longitude) {
  const query =
    'query' +
    '( $latitude: Float, $longitude: Float )' +
    '{getStores(latitude:$latitude,longitude:$longitude){items{id name instructions isActive address{postalCode country city state location{latitude longitude}} businessHours{dayOfWeek openingTime closingTime} pickupHolidays{date hourBegin hourEnd}}}}'

  return {
    query,
    queryVariables: { latitude, longitude },
  }
}

```


[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-locator/public/metadata/messages/es-AR.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "Store Locator",
  "headline": "Muestra las tiendas comerciales según los puntos de recogida.",
  "overview": "La aplicación Store Locator obtiene los datos del punto de recogida para mostrar la ubicación de la dirección de las tiendas minoristas.",
  "features": [
    "Importar automáticamente ubicaciones y su información desde el punto de recogida",
    "Generar páginas y rutas para cada tienda",
    "Un puñado de \"bloques\" para usar en cualquier plantilla"
  ],
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://help-tickets.vtex.com/en/support?app=vtex.store-locator"
  }
}

```


[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-locator/public/metadata/messages/pt-BR.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "Store Locator",
  "headline": "Exibe mapa de lojas com base nos pickup points.",
  "overview": "O aplicativo Store Locator busca os dados do pickup points para exibir a localização das lojas.",
  "features": [
    "Importa automaticamente os locais e suas informações do pickup points",
    "Gera páginas e rotas para cada loja",
    "Gera \"blocos\" para usar em qualquer modelo no template"
  ],
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://help-tickets.vtex.com/en/support?app=vtex.store-locator"
  }
}

```


[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-locator/public/metadata/messages/en-US.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "Store Locator",
  "headline": "Displays merchant stores based on the pickup points.",
  "overview": "The Store Locator app fetches the pickup point data in order to display address location for retail stores.",
  "features": [
    "Automatically import locations and its info from the pickup point",
    "Generate pages and routes for each store",
    "Handful \"blocks\" to use in any template"
  ],
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://help-tickets.vtex.com/en/support?app=vtex.store-locator"
  }
}

```


[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-locator/node/clients/index.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { IOClients } from '@vtex/api'

import RequestHub from '../utils/Hub'
import Sitemap from '../utils/Sitemap'

// Extend the default IOClients implementation with our own custom clients.
export class Clients extends IOClients {
  public get hub() {
    return this.getOrSet('hub', RequestHub)
  }

  public get sitemap() {
    return this.getOrSet('sitemap', Sitemap)
  }
}

```


[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-locator/node/utils/Binding.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { TenantClient } from '@vtex/api'

export const TENANT_CACHE_TTL_S = 60 * 10
export const STORE_PRODUCT = 'vtex-storefront'

export const getStoreBindings = async (tenant: TenantClient) => {
  const { bindings } = await tenant.info({
    forceMaxAge: TENANT_CACHE_TTL_S,
  })

  const storeBindings = bindings.filter(
    (binding) => binding.targetProduct === STORE_PRODUCT
  )

  return storeBindings
}

```


[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-locator/node/utils/Hub.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { InstanceOptions, IOContext } from '@vtex/api'
import { ExternalClient } from '@vtex/api'

const BASE_PATH =
  'http://logistics.vtexcommercestable.com.br/api/logistics/pvt/configuration/pickuppoints/'

const routes = {
  getAll: (
    { keyword, latitude, longitude, page = 1 }: any,
    account: string
  ) => {
    let path = `_search?an=${account}`

    if (keyword) {
      path += `&keyword=${keyword}`
    } else if (latitude && longitude) {
      path = `_searchsellers?an=${account}&lat=${Number(latitude).toFixed(
        2
      )}&lon=${Number(longitude).toFixed(2)}&maxDistance=200`
    }

    path += `&pageSize=100&page=${page}`

    return `${BASE_PATH}${path}`
  },
}

export default class RequestHub extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super('', context, {
      ...options,
      headers: {
        Accept: 'application/json',
        'Proxy-Authorization': context.authToken,
        Authorization: context.authToken,
        VtexIdclientAutCookie: context.authToken,
      },
    })
  }

  public getStores(data: any) {
    return this.http.getRaw(routes.getAll(data, this.context.account))
  }
}

```


[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-locator/node/utils/Sitemap.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { InstanceOptions, IOContext } from '@vtex/api'
import { AppGraphQLClient } from '@vtex/api'

const saveIndexMutation = `mutation SaveIndex($index: String!) {
    saveIndex(index: $index)
}`

export default class Sitemap extends AppGraphQLClient {
  constructor(ctx: IOContext, opts?: InstanceOptions) {
    super('vtex.store-sitemap@2.x', ctx, opts)
  }

  public hasSitemap() {
    return this.http
      .get(
        `http://${this.context.workspace}--${this.context.account}.myvtex.com/sitemap.xml`
      )
      .then((ret: string) => ret.indexOf('store-locator') !== -1)
  }

  public async saveIndex() {
    const { tenant } = this.context

    return this.graphql.mutate(
      {
        mutate: saveIndexMutation,
        variables: { index: 'store-locator' },
      },
      {
        headers: {
          ...this.options?.headers,
          'Proxy-Authorization': this.context.authToken,
          VtexIdclientAutCookie: this.context.authToken,
          'x-vtex-tenant': tenant,
        },
        metric: 'storelocator-save-root-index',
      }
    )
  }
}

```


[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-locator/node/utils/GraphQLError.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
export default class GraphQLError extends Error {
  public extensions: any

  constructor(message: string, details?: any) {
    super(message)
    this.extensions = { message, ...details }
  }
}

```


[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-locator/node/graphql/index.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable vtex/prefer-early-return */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { method } from '@vtex/api'
import slugify from 'slugify'

import { getStoreBindings } from '../utils/Binding'

const Slugify = (str: string) => {
  return slugify(str, { lower: true, remove: /[*+~.()'"!:@]/g })
}

const stripTrailingSlash = (str: string) => {
  return str.endsWith('/') ? str.slice(0, -1) : str
}

export const resolvers = {
  Routes: {
    getSitemap: [
      method({
        GET: async (ctx: Context) => {
          const {
            clients: { tenant },
            vtex: { logger },
          } = ctx

          try {
            const stores: any = await resolvers.Query.getStores(
              null,
              {
                keyword: null,
                latitude: null,
                longitude: null,
              },
              ctx
            ).catch((error) => {
              logger.error({ error, message: 'getSitemap-getStores-error' })

              return null
            })

            const [storeBindings] = await getStoreBindings(tenant)

            const { canonicalBaseAddress } = storeBindings
            const baseUrl =
              canonicalBaseAddress.indexOf('myvtex') === -1
                ? String(canonicalBaseAddress)
                : String(ctx.vtex.host)

            const lastMod = new Date().toISOString()
            const storesMap = `
              <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
                ${stores?.items
                  .filter((item: any) => {
                    return !!item.isActive
                  })
                  .map((item: any) => {
                    return `<url>
                  <loc>https://${stripTrailingSlash(baseUrl)}/store/${Slugify(
                      `${item.name} ${item.address.state} ${item.address.postalCode}`
                    )}/${String(item.id).replace('1_', '')}</loc>
                  <lastmod>${lastMod}</lastmod>
                  <changefreq>daily</changefreq>
                  <priority>0.8</priority>
               </url>`
                  })
                  .join('')}
              </urlset>`

            ctx.set('Content-Type', 'text/xml')
            ctx.body = storesMap
            ctx.status = 200
          } catch (e) {
            ctx.body = e
            ctx.status = 500
          }
        },
      }),
    ],
  },
  Query: {
    getStores: async (_: any, param: any, ctx: Context) => {
      const {
        clients: { hub, sitemap, vbase },
        vtex: { logger },
      } = ctx

      const APP_NAME = 'store-locator'
      const SCHEMA_NAME = 'sitemap'

      const saveInVbase = async () => {
        try {
          const res: any = await sitemap.saveIndex()

          if (res?.data?.saveIndex) {
            await vbase.saveJSON(APP_NAME, SCHEMA_NAME, {
              alreadyHasSitemap: true,
            })

            return true
          }

          return false
        } catch (err) {
          logger.error({ error: err, message: 'getStores-saveInBase-error' })

          return false
        }
      }

      sitemap.hasSitemap().then((has: any) => {
        if (has === false) {
          vbase
            .getJSON(APP_NAME, SCHEMA_NAME, true)
            .then((getResponse: any) => {
              const { alreadyHasSitemap = false } = getResponse ?? {}

              !alreadyHasSitemap && saveInVbase()
            })
            .catch((err: any) =>
              logger.error({ error: err, message: 'getStores-getJSON-error' })
            )
        }
      })

      let result = await hub.getStores(param).catch((error) => {
        logger.error({
          error,
          message: 'getStores-error',
          param,
        })

        return null
      })

      if (!result?.data.length && !param.keyword) {
        result = await hub.getStores({}).catch((error) => {
          logger.error({
            error,
            message: 'getStores-error',
            param: {},
          })

          return null
        })
      }

      // accounts for different reponse structure for Logistics _search and _searchsellers endpoints
      const {
        data,
        data: { paging = { pages: 0 } },
      } = result ?? { data: { items: [], paging: { pages: 0 } } }

      const pickuppoints = data.items ? data : { items: data }

      const results = [] as any

      // API will return errors starting at ?page=100
      const limitPagesTo99 = paging.pages > 99 ? 99 : paging.pages

      for (let i = 2; i <= limitPagesTo99; i++) {
        results.push(
          hub.getStores({ ...param, page: i }).catch((error) => {
            logger.error({
              error,
              message: 'getStores-error',
              param: { ...param, page: i },
            })

            return null
          })
        )
      }

      const remainingData = await Promise.all(results)

      remainingData.forEach((newResult: any) => {
        pickuppoints.items.push(...newResult.data.items)
      })

      // include for usage statistics
      logger.info({ message: 'getStores', items: pickuppoints?.items?.length })

      return {
        items: pickuppoints.items
          .map((item: any) => {
            return {
              ...item,
              address: {
                ...item.address,
                country: item.address.acronym,
              },
            }
          })
          .filter((item: any) => {
            return !!item.isActive
          }),
      }
    },
  },
}

```


[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-locator/react/contexts/OptionsContext.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

export const OptionsContext = React.createContext(false)

```


[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-locator/react/typings/global.d.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface BusinessHours {
  openingTime: string
  dayOfWeek: string
  closingTime: string
}
interface HolidayHours {
  date: string
  hourBegin: string
  hourEnd: string
}
interface Address {
  addressId: string
  cacheId: string
  id: string
  userId: string
  receiverName: string
  complement: string
  neighborhood: string
  country: string
  state: string
  number: string
  street: string
  geoCoordinates: [number, number]
  postalCode: string
  city: string
  reference: string
  addressName: string
  addressType: string
}
interface SpecificationGroup {
  businessHours: [BusinessHours]
  pickupHolidays: [HolidayHours]
  isActive: boolean
  distance: number
  friendlyName: string
  id: string
  instructions: string
  seller: string
  address: Address
}

```


[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-locator/react/typings/graphql.d.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

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

  const value: DocumentNode
  export default value
}

declare module '*.gql' {
  import type { 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 store-locator/react/typings/vtex.styleguide.d.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.styleguide' {
  export const PageHeader
  export const Alert
  export const Modal
  export const Box
  export const Card
  export const Checkbox
  export const Dropdown
  export const Spinner
  export const Table
  export const Button
  export const ButtonPlain
  export const IconWarning
  export const IconCheck
  export const Input
  export const InputButton
  export const InputSearch
  export const IconCaretDown
  export const IconCaretUp
  export const IconArrowDown
  export const IconArrowBack
  export const IconArrowUp
  export const IconClose
  export const IconExternalLink
  export const IconSearch
  export const IconSuccess
  export const IconCopy
  export const IconCog
  export const Tooltip
  export const ToastConsumer
  export const ToastProvider
  export const withToast
  export const ButtonWithIcon
  export const Pagination
  export const Collapsible
  export const Textarea
  export const NumericStepper
  export const EmptyState
  export const Tab
  export const Tag
  export const Toggle
  export const Layout
  export const Tabs
  export const Divider
  export const ModalDialog
  export const PageBlock
}

```


[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-locator/react/queries/getStores.gql from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getStores($latitude: Float, $longitude: Float, $filterByTag: String) {
  getStores(latitude: $latitude, longitude: $longitude, keyword: $filterByTag)
    @context(provider: "vtex.store-locator") {
    items {
      distance
      name
      instructions
      id
      isActive
      address {
        postalCode
        country
        city
        state
        neighborhood
        street
        number
        complement
        reference
        location {
          latitude
          longitude
        }
      }
      pickupHolidays {
        date
        hourBegin
        hourEnd
      }
      businessHours {
        dayOfWeek
        openingTime
        closingTime
      }
    }
  }
}

```


[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-locator/react/queries/orderForm.gql from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```graphql
query {
  orderForm @context(provider: "vtex.store-graphql") {
    shippingData {
      address {
        postalCode
        geoCoordinates
      }
    }
  }
}

```


[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-locator/react/queries/getStore.gql from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getStore($id: String!) {
  pickupPoint(id: $id) @context(provider: "vtex.store-graphql") {
    businessHours {
      openingTime
      dayOfWeek
      closingTime
    }
    pickupHolidays {
      date
      hourBegin
      hourEnd
    }
    isActive
    distance
    friendlyName
    id
    instructions
    seller
    address {
      addressId
      cacheId
      id
      userId
      receiverName
      complement
      neighborhood
      country
      state
      number
      street
      geoCoordinates
      postalCode
      city
      reference
      addressName
      addressType
    }
  }
}

```


[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-locator/react/queries/GetGoogleMapsKey.graphql from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getGoogleMapsKey {
  logistics @context(provider: "vtex.store-graphql") {
    googleMapsKey
  }
}

```


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

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
import React, { useState } from 'react'
import { FormattedMessage } from 'react-intl'
import {
  GoogleMap,
  Marker,
  InfoWindow,
  useJsApiLoader,
} from '@react-google-maps/api'
import slugify from 'slugify'
import { useRuntime } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'

const Slugify = (str: string) => {
  return slugify(str, { lower: true, remove: /[*+~.()'"!:@]/g })
}

const CSS_HANDLES = [
  'markerInfo',
  'markerInfoStoreName',
  'markerInfoAddress',
  'markerInfoLink',
] as const

// let initialLoad = false
const Pinpoints = (props: any) => {
  const { isLoaded } = useJsApiLoader({
    id: 'google-map-script',
    googleMapsApiKey: props.apiKey,
  })

  const [state, setState] = useState({
    markerState: {},
  })

  const handles = useCssHandles(CSS_HANDLES)

  const { navigate } = useRuntime()

  const handleMarkState = (id: string) => {
    const markerState = !state.markerState[id]
      ? {
          [id]: true,
        }
      : {}

    setState({
      markerState,
    })
  }

  const [lng, lat] = props.center
  const { zoom } = props

  const goTo = (item: any) => {
    const { state: _state, postalCode } = item.address

    navigate({
      page: 'store.storedetail',
      params: {
        slug: `${Slugify(`${item.name} ${_state} ${postalCode}`)}`,
        store_id: String(item.id).replace('1_', ''),
      },
    })
  }

  let icon: any = {
    url:
      props.icon ??
      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAANbY1E9YMgAABPBJREFUWIWtl3tMW1Ucxw+0hfEorwIDhdFSKJRnaSnl0ZZXKa9CC4wCo1RhPESWuUQTFd2cuKiJ07hItrnBmFFnXOaymZllWZwic1uMYzGZyZZgMrc/xCnExCjh1Z+/c90qwr0Tj5J8cnO59/zO9/7O9/x+pwQACB8/dzjIrLuB3G6zkfM1xeSdEgN5WZ8lcicrDIkhwYM+Pj4jhJCjxIeMKEKCdzoT4wtfM2SLjxTnkbPVZvI9jqPjaRyhOSiCD+4LuIOBvqwvJ7u06TmxQYHnxL6+SzmR4dCZkgg7MlTQhVddVASIRaLl2KCAC89q1IZxWykn/H8RMOt2kGc06kfwa+cbFHHwTaMVPD1OgMe2ePH0tMC3TVXQqkzAiGTpiQxV/8y98f9JwHzXZrI3X9OJQeGIOQ+gHyfsawXPVicsbW32sozQ/9PnH5QVAC4PvJSbOUDHMwv4wVVPzlSacnHyhaMlBoCBdm6ipQfACRlwwXFLIc2E54Sl0DSNcZgEXG2wkmxZ2LlGTDv0//PkK4HH28GtUoAqVDrxld0iZhLwqj7LJPL1hWtNlQC9reuenBPQ2wI3W2pBIvKFndq0SiYBmsjw5zNl4Vyw1V9/qb4cHkX3ywIDuCu95/OEIToSkkOlQ0wC8O+wE11NjbX6C+mkYrHYC71fkwUc15WaSAONsAoY605V8gqgX75SAL3nE7AjK4UGGmMVcLBBEc/tc9YMuFRyGugQkwBTbNRTyWFSWO52snkAvZOFHtJGRTzHJGC4SKfFgjI/XleOhmr7d7sADfh1g5UWJM/e/Gwjk4CLdWXEGBN1zBQThcvQBp5u57omX+7+M/1V8bG0R5wet5WxFaLpdjvB1Cr9RaLZodwMLuh6ihEtWq/nawBryK+f2UrT7mIcJgEzXC9opm3Ygkaa21eo5d0Rq403WpxHjbd4wKirW8BeMMPaC+hAygKKOGTSN9GGdKbKzC0H/7q3wQSakTYizEDn/UbE3oza673MdW4m29KTd8s2+MN0hwMA2+/fJkd//N7VDMqQYGhPShimon9yOchdl52DScCtVpuX22115M6WOlFKWMjl9iT5mtpAU48HFgj39/vuelNV6K3WWjLVUuOFScAkdsOV3GiupktRRpdisvGvBgV4OPkRsxKIBWm3LqNryllDruH7K2EScKG2ZA1X7BaikYV/4lRu8maBfv0redkQ4e93E7eu/2V8hx7hVsJcB1Zz1VFB3izIqcCtCbgknBcWcd8rpEHQp1Y+OdloJV/ge6thEnDaalzDx8gpq1Ei9ZNM4XJwp59Ldgvd83OnrEUJVxzl5GJ92RqYBBwvL+AFj2mk9KHot2ilg+1uPHCkg1waNEGX6GyVmRcmAaNmPS/vlRrI9gxVdVTABlhEDxRsjAS7/OHBkxVF+CyfFyYBh016XkbNeeSN/JzYQIn4t89tpbARO+KgJs34Pk40hj9K+GAS8KIug5ehe2BRuvG0Rg14/WVfgVZGhQmJZhLwgjZdkD25mSQxRPqpPloGm4KDrr+Np/eDRh05IACTgF61UhAsywQPmx8GSSSQFCo9jz9CCJpRECYBPalKQQbSkkmWLGw/rYrykOCPXMly0qLcJAiTgP2YOiGosezyuF1UQEVczPAxNKDQrqEwCaCuFuKkpYj0qZPcVECHSr7tREUheRe3pxAPEvAHoSjT1B9h9DoAAAAASUVORK5CYII=',
  }

  if (props.iconWidth && props.iconHeight) {
    icon = {
      ...icon,
      scaledSize: {
        width: props.iconWidth,
        height: props.iconHeight,
      },
    }
  }

  if (!isLoaded) return null

  return (
    <GoogleMap
      zoom={zoom}
      center={{ lat, lng }}
      mapContainerStyle={{ height: '100%' }}
      mapContainerClassName={props.className}
    >
      {props.items.map((item: any, i: number) => {
        const { latitude, longitude } = item.address.location

        return (
          <Marker
            key={`marker_${i}`}
            icon={icon}
            position={{ lat: latitude, lng: longitude }}
            onClick={() => {
              handleMarkState(item.id)
            }}
          >
            {state.markerState[item.id] && (
              // ||
              //   (Object.getOwnPropertyNames(state.markerState).length === 0 &&
              //     lat === latitude &&
              //     lng === longitude)
              <InfoWindow
                position={{ lat: latitude, lng: longitude }}
                onCloseClick={() => {
                  handleMarkState(item.id)
                }}
              >
                <div className={`t-mini ${handles.markerInfo}`}>
                  <span className={`b ${handles.markerInfoStoreName}`}>
                    {item.name}
                  </span>
                  <br />
                  <span className={handles.markerInfoAddress}>
                    {item.address.number ? `${item.address.number} ` : ''}
                    {item.address.street}
                    {item.address.city ? `, ${item.address.city}` : ''}
                    {item.address.state ? `, ${item.address.state}` : ''}
                    {item.address.postalCode
                      ? ` - ${item.address.postalCode}`
                      : ''}
                  </span>
                  <br />
                  <span
                    className={`mt2 link c-link underline-hover pointer ${handles.markerInfoLink}`}
                    onClick={(e) => {
                      e.preventDefault()
                      goTo(item)
                    }}
                  >
                    <FormattedMessage id="store/more-details" />
                  </span>
                </div>
              </InfoWindow>
            )}
          </Marker>
        )
      })}
    </GoogleMap>
  )
}

export default Pinpoints

```


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

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import type { FC } from 'react'
import React from 'react'
import { injectIntl, FormattedMessage } from 'react-intl'
import PropTypes from 'prop-types'
import slugify from 'slugify'
import { useRuntime } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'

const CSS_HANDLES = [
  'addressList',
  'addressListItem',
  'addressListFirstItem',
  'addressStoreName',
  'addressStoreAddress',
  'addressStoreAddressGroupA',
  'addressStoreAddressNumber',
  'addressStoreAddressStreet',
  'addressListLink',
] as const

const Slugify = (str: string) => {
  return slugify(str, { lower: true, remove: /[*+~.()'"!:@]/g })
}

const Listing: FC<any> = ({ items, onChangeCenter }) => {
  const handles = useCssHandles(CSS_HANDLES)
  const { navigate } = useRuntime()

  const handleChangeCenter = (item: any, zoom: number) => {
    const { latitude, longitude } = item.address.location

    onChangeCenter([longitude, latitude], zoom)
  }

  const goTo = (item: any) => {
    const { state: _state, postalCode } = item.address

    navigate({
      page: 'store.storedetail',
      params: {
        slug: `${Slugify(`${item.name} ${_state} ${postalCode}`)}`,
        store_id: String(item.id).replace('1_', ''),
      },
    })
  }

  return (
    items.length && (
      <ul className={`list ph3 mt0 ${handles.addressList}`}>
        {items.map((item: any, i: number) => {
          return (
            <li
              key={`key_${i}`}
              className={`pointer mb0 ph3 pv5 ${
                !i ? handles.addressListFirstItem : ''
              } ${handles.addressListItem} ${
                !i ? 'bt' : ''
              } bb bl br b--light-gray hover-bg-light-gray`}
              onClick={() => {
                handleChangeCenter(item, 12)
              }}
            >
              <span className={`t-mini b ${handles.addressStoreName}`}>
                {item.name}
              </span>
              <br />
              <span className={`t-mini ${handles.addressStoreAddress}`}>
                <span className={handles.addressStoreAddressGroupA}>
                  <span className={handles.addressStoreAddressNumber}>
                    {item.address.number ? `${item.address.number} ` : ''}
                  </span>
                  <span className={handles.addressStoreAddressStreet}>
                    {item.address.street}
                  </span>
                </span>
                {item.address.city ? `, ${item.address.city}` : ''}
                {item.address.state ? `, ${item.address.state}` : ''}
                {item.address.postalCode ? ` - ${item.address.postalCode}` : ''}
              </span>
              <br />
              <span
                className={`mt2 link c-link underline-hover pointer ${handles.addressListLink}`}
                onClick={(e) => {
                  e.stopPropagation()
                  goTo(item)
                }}
              >
                <FormattedMessage id="store/more-details" />
              </span>
            </li>
          )
        })}
      </ul>
    )
  )
}

Listing.propTypes = {
  items: PropTypes.array,
  onChangeCenter: PropTypes.func,
}

export default injectIntl(Listing)

```


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

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react'
import { GoogleMap, Marker, useJsApiLoader } from '@react-google-maps/api'

const Map = (props: any) => {
  const { zoom } = props
  const { isLoaded } = useJsApiLoader({
    id: 'google-map-script',
    googleMapsApiKey: props.apiKey,
  })

  const [lng, lat] = props.center
  let icon: any = {
    url: props.icon ?? null,
  }

  if (props.iconWidth && props.iconHeight) {
    icon = {
      ...icon,
      scaledSize: {
        width: props.iconWidth,
        height: props.iconHeight,
      },
    }
  }

  if (!isLoaded) return null

  return (
    <GoogleMap
      zoom={zoom}
      center={{ lat, lng }}
      mapContainerStyle={{ height: '100%' }}
    >
      <Marker icon={icon} position={{ lat, lng }} />
    </GoogleMap>
  )
}

export default 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 store-locator/react/__tests__/index.test.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
describe('Orders List Scenarios', () => {
  it('should work', () => {
    expect(1).toBe(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 paypalcp-checkout-ui-settings/checkout-ui-custom/checkout5-custom.css from the paypalcp-checkout-ui-settings VTEX app.

[Assistant]
Here's the implementation:

```css
/* /files/checkout5-custom.css */

/* Displays the option to enter a foreign document */
.document-box { display: block; }

/* Displays the option to enter an international phone */
.phone-box { display: block; }

```


[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 paypalcp-checkout-ui-settings/checkout-ui-custom/checkout6-custom.js from the paypalcp-checkout-ui-settings VTEX app.

[Assistant]
Here's the implementation:

```javascript
/* eslint-disable camelcase */
/* eslint-disable no-undef */
const MAX_TIME_EXPIRATION = 1000 * 60 * 5 // 5 minutes
const GRAPHQL_ENDPOINT = '/_v/private/graphql/v1'
const ISO3_ENDPOINT =
  '/_v/vtex.connector-paypal-commerce-platform/v0/country-code/'

// const GATEWAY_CALLBACK_ENDPOINT = '/api/checkout/pub/gatewayCallback/'
const SETTINGS_ENDPOINT = `/_v/vtex.connector-paypal-commerce-platform/v0/settings`
const OrderFormFragment = `id
    items {
      additionalInfo {
        brandName
      }
      attachments {
        name
        content
      }
      attachmentOfferings {
        name
        required
        schema
      }
      bundleItems {
        additionalInfo {
            brandName
          }
          attachments {
            name
            content
          }
          attachmentOfferings {
            name
            required
            schema
          }
          availability
          detailUrl
          id
          imageUrls {
            at1x
            at2x
            at3x
          }
          listPrice
          measurementUnit
          name
          offerings {
            id
            name
            price
            type
            attachmentOfferings {
              name
              required
              schema
            }
          }
          price
          productCategories
          productCategoryIds
          productRefId
          productId
          quantity
          seller
          sellingPrice
          skuName
          skuSpecifications {
            fieldName
            fieldValues
          }
          unitMultiplier
          uniqueId
          refId
      }
      parentAssemblyBinding
      parentItemIndex
      sellingPriceWithAssemblies
      options {
        assemblyId
        id
        quantity
        seller
        inputValues
        options {
          assemblyId
          id
          quantity
          seller
          inputValues
          options {
            assemblyId
            id
            quantity
            seller
            inputValues
          }
        }
      }
      availability
      detailUrl
      id
      imageUrls {
        at1x
        at2x
        at3x
      }
      listPrice
      manualPrice
      measurementUnit
      modalType
      name
      offerings {
        id
        name
        price
        type
        attachmentOfferings {
          name
          required
          schema
        }
      }
      price
      priceTags {
        identifier
        isPercentual
        name
        rawValue
        value
      }
      productCategories
      productCategoryIds
      productRefId
      productId
      quantity
      seller
      sellingPrice
      skuName
      skuSpecifications {
        fieldName
        fieldValues
      }
      unitMultiplier
      uniqueId
      refId
      priceTags {
        identifier
        isPercentual
        rawValue
        value
        name
        ratesAndBenefitsIdentifier {
          description
          id
          featured
          name
          matchedParameters
        }
      }
      isGift
      priceDefinition {
        calculatedSellingPrice
        total
        sellingPrices {
          quantity
          value
        }
      }
    }
    canEditData
    loggedIn
    userProfileId
    userType
    marketingData {
    coupon
    utmCampaign
    utmMedium
    utmSource
    utmiCampaign
    utmiPart
    utmiPage
    }
    totalizers {
    id
    name
    value
    }
    shipping {
    countries
    availableAddresses {
        addressId
        addressType
        city
        complement
        country
        neighborhood
        number
        postalCode
        receiverName
        reference
        state
        street
        isDisposable
        geoCoordinates
    }
    selectedAddress {
        addressId
        addressType
        city
        complement
        country
        neighborhood
        number
        postalCode
        receiverName
        reference
        state
        street
        isDisposable
        geoCoordinates
    }
    deliveryOptions {
        id
        deliveryChannel
        price
        estimate
        isSelected
    }
    pickupOptions {
        id
        address {
            addressId
            addressType
            city
            complement
            country
            neighborhood
            number
            postalCode
            receiverName
            reference
            state
            street
            isDisposable
            geoCoordinates
        }
        deliveryChannel
        price
        estimate
        isSelected
        friendlyName
        additionalInfo
        storeDistance
        transitTime
        businessHours {
        dayNumber
        closed
        closingTime
        openingTime
        }
    }
    isValid
    }
    paymentData {
    paymentSystems {
        id
        name
        groupName
        validator {
        regex
        mask
        cardCodeRegex
        cardCodeMask
        weights
        useCvv
        useExpirationDate
        useCardHolderName
        useBillingAddress
        }
        stringId
        requiresDocument
        isCustom
        description
        requiresAuthentication
        dueDate
    }
    payments {
        paymentSystem
        bin
        accountId
        tokenId
        installments
        referenceValue
        value
    }
    installmentOptions {
        paymentSystem
        installments {
        count
        hasInterestRate
        interestRate
        value
        total
        }
    }
    availableAccounts {
        accountId
        paymentSystem
        paymentSystemName
        cardNumber
        bin
    }
    isValid
    }
    clientProfileData {
    email
    firstName
    lastName
    document
    documentType
    phone
    isValid
    }
    clientPreferencesData {
    locale
    optInNewsletter
    }
    messages {
    couponMessages {
        code
    }
    generalMessages {
        code
        text
        status
    }
    }
    value
    allowManualPrice
    customData {
    customApps {
        fields
        id
        major
    }
    }`

const CREATE_ORDER_MUTATION = `mutation CreateOrder($input: CreateOrderInput!) {
    createOrder(input: $input)
      @context(provider: "vtex.connector-paypal-commerce-platform")
  }`

const UPDATE_ORDER_MUTATION = `mutation UpdateOrder($input: UpdateOrderInput!) {
    updateOrder(input: $input)
      @context(provider: "vtex.connector-paypal-commerce-platform")
  }
  `

const PLACE_ORDER_MUTATION = `mutation PlaceOrder($orderFormId: String!, $paypalOrderId: String!) {
    placeOrder(
      input: { orderFormId: $orderFormId, paypalOrderId: $paypalOrderId }
    ) @context(provider: "vtex.connector-paypal-commerce-platform") {
      orderGroup
      checkoutAuth
    }
  }
  `

const COMPLETE_ORDER_MUTATION = `mutation CompleteOrder($orderFormId: String!, $orderGroup: String!, $checkoutAuth: String!) {
    completeOrder(
      input: { orderFormId: $orderFormId, orderGroup: $orderGroup, checkoutAuth: $checkoutAuth }
    ) @context(provider: "vtex.connector-paypal-commerce-platform") {
      orderGroup
      checkoutAuth
    }
  }
  `

const ORDERFORM_QUERY = `query getOrderForm($orderFormId: ID) {
    orderForm(orderFormId: $orderFormId, refreshOutdatedData: true)
      @context(provider: "vtex.checkout-graphql", scope: "private") {
      ${OrderFormFragment}
    }
  }`

const ESTIMATE_SHIPPING_MUTATION = `mutation estimateShipping($addressInput: AddressInput) {
    estimateShipping(address: $addressInput)
      @context(provider: "vtex.checkout-graphql") {
      ${OrderFormFragment}
    }
  }`

const SELECT_DELIVERY_OPTION_MUTATION = `mutation selectDeliveryOption($deliveryOptionId: String) {
    selectDeliveryOption(deliveryOptionId: $deliveryOptionId)
      @context(provider: "vtex.checkout-graphql") {
      ${OrderFormFragment}
    }
  }`

const SELECT_PICKUP_OPTION_MUTATION = `mutation selectPickupOption($pickupOptionId: String) {
    selectPickupOption(pickupOptionId: $pickupOptionId)
      @context(provider: "vtex.checkout-graphql") {
      ${OrderFormFragment}
    }
  }`

const generateItemsArray = (orderForm, currency) => {
  let hasDeliveryErrors = false

  const returnArray = orderForm.items.map((item) => {
    if (item.availability === 'cannotBeDelivered') {
      hasDeliveryErrors = true
    }

    const name =
      item.name.length > 127 ? `${item.name.substring(0, 124)}...` : item.name

    const description =
      item.skuName.length > 127
        ? `${item.skuName.substring(0, 124)}...`
        : item.skuName

    return {
      name,
      unit_amount: {
        value: item.isGift ? '0.00' : (item.price / 100).toFixed(2),
        currency_code: currency,
      },
      quantity: item.quantity * item.unitMultiplier,
      description,
      sku: item.id,
    }
  })

  if (hasDeliveryErrors) return []

  return returnArray
}

const generateShippingOptions = (orderForm, currency, pickupEnabled) => {
  if (
    !orderForm?.shipping?.deliveryOptions?.length &&
    (!pickupEnabled || !orderForm?.shipping?.pickupOptions?.length)
  ) {
    return []
  }

  const shippingOptions = orderForm.shipping.deliveryOptions.map((option) => {
    return {
      id: option.id,
      label: option.id,
      type: 'SHIPPING',
      selected: option.isSelected,
      amount: {
        value: (option.price / 100).toFixed(2),
        currency_code: currency,
      },
    }
  })

  const pickupOptions = pickupEnabled
    ? orderForm.shipping.pickupOptions.map((option) => {
        return {
          id: option.id,
          label: option.friendlyName,
          type: 'PICKUP',
          selected: option.isSelected,
          amount: {
            value: (option.price / 100).toFixed(2),
            currency_code: currency,
          },
        }
      })
    : []

  return [...pickupOptions, ...shippingOptions]
}

const getSelectedPickupLocation = (orderForm) => {
  if (!orderForm?.shipping?.pickupOptions?.length) {
    return null
  }

  return orderForm.shipping.pickupOptions.filter(
    (option) => option.isSelected
  )[0]
}

const generateBreakdown = (totalizers, currency) => {
  const breakdown = {}
  let totalTax = 0

  totalizers.forEach((totalizer) => {
    if (totalizer.id === 'Items') {
      breakdown.item_total = {
        value: (totalizer.value / 100).toFixed(2),
        currency_code: currency,
      }

      return
    }

    if (totalizer.id === 'Shipping') {
      breakdown.shipping = {
        value: (totalizer.value / 100).toFixed(2),
        currency_code: currency,
      }

      return
    }

    if (totalizer.id === 'Discounts') {
      breakdown.discount = {
        value: Math.abs(totalizer.value / 100).toFixed(2),
        currency_code: currency,
      }

      return
    }

    if (totalizer.id.toLowerCase().includes('tax')) {
      totalTax += totalizer.value
    }
  })

  breakdown.tax_total = {
    value: (totalTax / 100).toFixed(2),
    currency_code: currency,
  }

  return breakdown
}

!(() => {
  console.info('PayPal Smart Buttons')
  let checkPayPalSettings = null

  // Used to remove cache from requests
  const isWorkspace = () => {
    return window.__RUNTIME__.workspace !== 'master'
  }

  let payPalSettings
  const storedPayPalSettings = JSON.parse(
    window.sessionStorage.getItem('paypal-settings')
  )

  if (storedPayPalSettings?.time) {
    const now = new Date().getTime()
    const sessionStorageCheckoutTime = new Date(
      storedPayPalSettings.time
    ).getTime()

    if (now - sessionStorageCheckoutTime < MAX_TIME_EXPIRATION) {
      payPalSettings = storedPayPalSettings
    }
  }

  window.payPalSettings = window.payPalSettings || payPalSettings

  const handleShippingUpdate = async (address, rootPath) => {
    const { city, country_code, postal_code, state } = address

    const countryCode =
      country_code.length === 2
        ? await fetch(`${rootPath}${ISO3_ENDPOINT}${country_code}`)
            .then((response) => response.json())
            .then((response) => response.code)
        : country_code

    const addressInput = {
      neighborhood: 'N/A',
      city,
      country: countryCode,
      postalCode: postal_code,
      state,
      isDisposable: true,
    }

    return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
      method: 'POST',
      body: JSON.stringify({
        query: ESTIMATE_SHIPPING_MUTATION,
        variables: { addressInput },
      }),
    })
  }

  const handleSelectShippingOption = async (data, rootPath) => {
    const { selected_shipping_option } = data

    if (selected_shipping_option.type === 'PICKUP') {
      return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
        method: 'POST',
        body: JSON.stringify({
          query: SELECT_PICKUP_OPTION_MUTATION,
          variables: { pickupOptionId: selected_shipping_option.id },
        }),
      })
    }

    return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
      method: 'POST',
      body: JSON.stringify({
        query: SELECT_DELIVERY_OPTION_MUTATION,
        variables: { deliveryOptionId: selected_shipping_option.id },
      }),
    })
  }

  const checkSelectedShippingOption = async (currentOrderForm, rootPath) => {
    if (
      !currentOrderForm?.shipping?.deliveryOptions?.length ||
      currentOrderForm.shipping.deliveryOptions.some((opt) => opt.isSelected)
    ) {
      return currentOrderForm
    }

    const {
      city,
      country: country_code,
      postalCode: postal_code,
      state,
    } = currentOrderForm.shipping.selectedAddress

    await handleShippingUpdate(
      {
        city,
        country_code,
        postal_code,
        state,
      },
      rootPath
    )

    return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
      method: 'POST',
      body: JSON.stringify({
        query: SELECT_DELIVERY_OPTION_MUTATION,
        variables: {
          deliveryOptionId: currentOrderForm.shipping.deliveryOptions[0].id,
        },
      }),
    })
      .then((response) => response.json())
      .then(({ data: selectResult }) => {
        const newOrderForm = selectResult?.selectDeliveryOption

        if (!newOrderForm) {
          return currentOrderForm
        }

        return newOrderForm
      })
  }

  const renderButtons = async () => {
    if (
      typeof paypal === 'undefined' ||
      $('#paypal-button-container').children().length
    ) {
      return
    }
    const rootPath = window?.vtex?.renderRuntime?.rootPath ?? ''

    const {
      layout,
      color,
      shape,
      showTagline,
      immediateCapture,
      sellerEmail,
      merchantId,
      enablePickup = false,
    } = window.payPalSettings

    const { orderFormId } = vtexjs.checkout
    const currency = window?.vtexjs?.checkout?.orderForm?.storePreferencesData?.currencyCode || 'USD'

    paypal
      .Buttons({
        style: {
          layout,
          color,
          shape,
          ...(layout === 'horizontal' ? { tagline: showTagline } : {}),
        },
        createOrder(_data, _actions) {
          return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
            method: 'POST',
            body: JSON.stringify({
              query: ORDERFORM_QUERY,
              variables: {
                orderFormId,
              },
            }),
          })
            .then((response) => response.json())
            .then(({ data }) => {
              const { orderForm } = data

              return checkSelectedShippingOption(orderForm, rootPath).then(
                (newOrderForm) => {
                  const items = generateItemsArray(newOrderForm, currency)

                  if (!items.length) return null

                  const shippingOptions = generateShippingOptions(
                    newOrderForm,
                    currency,
                    enablePickup
                  )

                  const breakdown = generateBreakdown(
                    newOrderForm.totalizers,
                    currency
                  )

                  return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
                    method: 'POST',
                    body: JSON.stringify({
                      query: CREATE_ORDER_MUTATION,
                      variables: {
                        input: {
                          intent: immediateCapture ? 'CAPTURE' : 'AUTHORIZE',
                          amount: {
                            value: (newOrderForm.value / 100).toFixed(2),
                            currency_code: currency,
                            breakdown,
                          },
                          payee: {
                            email_address: sellerEmail,
                            merchant_id: merchantId,
                          },
                          items,
                          shipping: {
                            options:
                              shippingOptions && shippingOptions.length > 0
                                ? shippingOptions
                                : null,
                          },
                        },
                      },
                    }),
                  })
                    .then((response) => response.json())
                    .then(({ data: newData }) => {
                      if (!newData) return null

                      return newData.createOrder
                    })
                }
              )
            })
        },
        onShippingChange(data, actions) {
          const { shipping_address } = data

          // always run the shipping estimate mutation to make sure we have the latest orderForm
          return handleShippingUpdate(shipping_address, rootPath)
            .then((response) => response.json())
            .then(({ data: result }) => {
              if (!result) {
                return actions.reject()
              }

              let newOrderForm = result.estimateShipping

              if (!newOrderForm) {
                return actions.reject()
              }

              const { shipping, totalizers } = newOrderForm

              if (
                !shipping?.deliveryOptions?.length &&
                !shipping?.pickupOptions?.length
              ) {
                return actions.reject()
              }

              const newItems = generateItemsArray(newOrderForm, currency)

              if (!newItems?.length) return actions.reject()

              // if the selected shipping option in paypal hasn't been selected in VTEX,
              // select it and then patch the paypal order with the new orderForm data.
              // This conditional is for delivery options, see below for pickup
              if (
                data.selected_shipping_option?.id &&
                shipping.deliveryOptions.find(
                  (option) =>
                    option.id === data.selected_shipping_option.id &&
                    (option.price / 100).toFixed(2) ===
                      data.selected_shipping_option.amount.value &&
                    !option.isSelected
                )
              ) {
                return handleSelectShippingOption(data, rootPath)
                  .then((response) => response.json())
                  .then(({ data: selectResult }) => {
                    if (!selectResult) {
                      return actions.reject()
                    }

                    newOrderForm = selectResult.selectDeliveryOption

                    if (!newOrderForm) {
                      return actions.reject()
                    }

                    const { totalizers: newTotalizers } = newOrderForm

                    const newShippingOptions = generateShippingOptions(
                      newOrderForm,
                      currency,
                      enablePickup
                    )

                    const newBreakdown = generateBreakdown(
                      newTotalizers,
                      currency
                    )

                    const input = {
                      orderId: data.orderID,
                      amount: {
                        value: (newOrderForm.value / 100).toFixed(2),
                        currency_code: currency,
                        breakdown: newBreakdown,
                      },
                      payee: {
                        email_address: sellerEmail,
                        merchant_id: merchantId,
                      },
                      items: newItems,
                      shipping: {
                        options: newShippingOptions,
                      },
                    }

                    return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
                      method: 'POST',
                      body: JSON.stringify({
                        query: UPDATE_ORDER_MUTATION,
                        variables: { input },
                      }),
                    })
                      .then((response) => response.json())
                      .then(({ data: updateOrderResult }) => {
                        if (!updateOrderResult?.updateOrder) {
                          return actions.reject()
                        }

                        return actions.resolve()
                      })
                  })
              }

              // pickup
              if (
                data.selected_shipping_option?.id &&
                shipping.pickupOptions?.find(
                  (option) =>
                    option.id === data.selected_shipping_option.id &&
                    (option.price / 100).toFixed(2) ===
                      data.selected_shipping_option.amount.value &&
                    !option.isSelected
                )
              ) {
                return handleSelectShippingOption(data, rootPath)
                  .then((response) => response.json())
                  .then(({ data: selectResult }) => {
                    if (!selectResult) {
                      return actions.reject()
                    }

                    newOrderForm = selectResult.selectPickupOption

                    if (!newOrderForm) {
                      return actions.reject()
                    }

                    const { totalizers: newTotalizers } = newOrderForm

                    const newShippingOptions = generateShippingOptions(
                      newOrderForm,
                      currency,
                      enablePickup
                    )

                    const newBreakdown = generateBreakdown(
                      newTotalizers,
                      currency
                    )

                    const pickupLocation = getSelectedPickupLocation(
                      newOrderForm
                    )

                    if (!pickupLocation) {
                      return actions.reject()
                    }

                    const input = {
                      orderId: data.orderID,
                      amount: {
                        value: (newOrderForm.value / 100).toFixed(2),
                        currency_code: currency,
                        breakdown: newBreakdown,
                      },
                      payee: {
                        email_address: sellerEmail,
                        merchant_id: merchantId,
                      },
                      items: newItems,
                      shipping: {
                        options: newShippingOptions,
                        name: {
                          full_name: `S2S ${pickupLocation.friendlyName}`,
                        },
                        address: {
                          address_line_1: pickupLocation.address.street,
                          admin_area_2: pickupLocation.address.city,
                          admin_area_1: pickupLocation.address.state,
                          postal_code: pickupLocation.address.postalCode,
                          country_code: data.shipping_address.country_code,
                        },
                      },
                    }

                    return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
                      method: 'POST',
                      body: JSON.stringify({
                        query: UPDATE_ORDER_MUTATION,
                        variables: { input },
                      }),
                    })
                      .then((response) => response.json())
                      .then(({ data: updateOrderResult }) => {
                        if (!updateOrderResult?.updateOrder) {
                          return actions.reject()
                        }

                        return actions.resolve()
                      })
                  })
              }

              const newShippingOptions = generateShippingOptions(
                newOrderForm,
                currency,
                enablePickup
              )

              const newBreakdown = generateBreakdown(totalizers, currency)

              const isPickup = data.selected_shipping_option?.type === 'PICKUP'

              const pickupLocation = getSelectedPickupLocation(newOrderForm)

              if (isPickup && !pickupLocation) {
                return actions.reject()
              }

              const input = {
                orderId: data.orderID,
                amount: {
                  value: (newOrderForm.value / 100).toFixed(2),
                  currency_code: currency,
                  breakdown: newBreakdown,
                },
                payee: {
                  email_address: sellerEmail,
                  merchant_id: merchantId,
                },
                items: newItems,
                shipping: {
                  options: newShippingOptions,
                  ...(isPickup && {
                    name: {
                      full_name: `S2S ${pickupLocation.friendlyName}`,
                    },
                    address: {
                      address_line_1: pickupLocation.address.street,
                      admin_area_2: pickupLocation.address.city,
                      admin_area_1: pickupLocation.address.state,
                      postal_code: pickupLocation.address.postalCode,
                      country_code: data.shipping_address.country_code,
                    },
                  }),
                },
              }

              return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
                method: 'POST',
                body: JSON.stringify({
                  query: UPDATE_ORDER_MUTATION,
                  variables: { input },
                }),
              })
                .then((response) => response.json())
                .then(({ data: updateOrderResult }) => {
                  if (!updateOrderResult?.updateOrder) {
                    return actions.reject()
                  }

                  return actions.resolve()
                })
            })
            .catch(() => {
              return actions.reject()
            })
        },
        onApprove(data) {
          vtex.checkout.MessageUtils.showPaymentMessage()

          fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
            method: 'POST',
            body: JSON.stringify({
              query: PLACE_ORDER_MUTATION,
              variables: {
                orderFormId,
                paypalOrderId: data.orderID,
              },
            }),
          })
            .then((response) => response.json())
            .then(async (result) => {
              if (
                !result?.data?.placeOrder?.orderGroup ||
                !result?.data?.placeOrder?.checkoutAuth
              ) {
                vtex.checkout.MessageUtils.hidePaymentMessage()
                vtex.checkout.MessageUtils.showPaymentUnauthorizedMessage()

                return
              }

              document.cookie = result.data.placeOrder.checkoutAuth

              return fetch(`${rootPath}${GRAPHQL_ENDPOINT}`, {
                method: 'POST',
                body: JSON.stringify({
                  query: COMPLETE_ORDER_MUTATION,
                  variables: {
                    orderFormId,
                    orderGroup: result.data.placeOrder.orderGroup,
                    checkoutAuth: result.data.placeOrder.checkoutAuth,
                  },
                }),
              })
                .then((response) => response.json())
                .then(async (finalResult) => {
                  if (!finalResult?.data?.completeOrder?.orderGroup) {
                    vtex.checkout.MessageUtils.hidePaymentMessage()
                    vtex.checkout.MessageUtils.showPaymentUnauthorizedMessage()

                    return
                  }

                  vtex.checkout.MessageUtils.hidePaymentMessage()

                  window.location = `${rootPath}/checkout/orderPlaced/?og=${result.data.placeOrder.orderGroup}`
                })
            })
            .catch(() => {
              vtex.checkout.MessageUtils.hidePaymentMessage()
              vtex.checkout.MessageUtils.showPaymentUnauthorizedMessage()
            })
        },
        onCancel() {
          vtexjs.checkout
            .getOrderForm()
            .then(() => console.info('User closed PayPal Checkout'))
        },
      })
      .render('#paypal-button-container')
  }

  const createDiv = () => {
    if (
      $('#paypal-button-container').size()
    ) {
      return
    }
    const [buttonContainer] = document.getElementsByClassName('cart-links')
    const paypalDiv = document.createElement('div')

    paypalDiv.id = 'paypal-button-container'

    if (buttonContainer) {
      buttonContainer.appendChild(paypalDiv)
    }
  }

  const loadPayPalScript = async () => {
    const {
      production,
      productionClientId,
      productionBNCode,
      sandboxClientId,
      sandboxBNCode,
      merchantId,
      immediateCapture,
      disablePayPalCredit,
      disableCards,
    } = window.payPalSettings

    const currency = window?.vtexjs?.checkout?.orderForm?.storePreferencesData?.currencyCode || 'USD'

    const script = document.createElement('script')

    const disabledPayments = []

    if (disableCards) disabledPayments.push('card')
    if (disablePayPalCredit) disabledPayments.push('credit')

    script.src = `https://www.paypal.com/sdk/js?client-id=${
      production ? productionClientId : sandboxClientId
    }&merchant-id=${merchantId}&currency=${currency}&intent=${
      immediateCapture ? 'capture' : 'authorize'
    }&commit=true${
      disabledPayments.length
        ? `&disable-funding=${disabledPayments.join(',')}`
        : ``
    }`
    script.setAttribute(
      'data-partner-attribution-id',
      production ? productionBNCode : sandboxBNCode
    )
    document.body.appendChild(script)
  }

  const initializePayPal = async () => {
    if (!window.payPalSettings?.showOnCartPage) {
      return
    }

    if (window.location.hash !== '#/cart') {
      const paypalButtons = document.getElementById('paypal-button-container')

      if (paypalButtons) {
        paypalButtons.remove()
      }

      return
    }

    createDiv()
    await loadPayPalScript()
    const checkPayPalScript = setInterval(() => {
      if (typeof paypal !== 'undefined') {
        clearInterval(checkPayPalScript)
        renderButtons()
      }
    }, 500)
  }

  const handlePayPalSettings = () => {
    if (!payPalSettings) return

    window.payPalSettings = payPalSettings
    initializePayPal()
  }

  const fetchPayPalSettings = () => {
    const rootPath = window?.vtex?.renderRuntime?.rootPath ?? ''

    const ts = new Date().getTime()

    $.ajax({
      url: `${rootPath}${SETTINGS_ENDPOINT}${isWorkspace() ? `?v=${ts}` : ''}`,
    }).then((response) => {
      if (Object.keys(response).length === 0) {
        window.sessionStorage.removeItem('paypal-settings')

        return
      }

      response.time = new Date().toISOString()

      window.sessionStorage.setItem('paypal-settings', JSON.stringify(response))
      payPalSettings = response
      handlePayPalSettings()
    })
  }

  // Wait until we have the vtex runtime to call the functions
  checkPayPalSettings = setInterval(() => {
    if (typeof window?.vtex?.renderRuntime !== 'undefined') {
      clearInterval(checkPayPalSettings)
      if (isWorkspace() || !payPalSettings) {
        fetchPayPalSettings()
      } else {
        handlePayPalSettings()
      }
    }
  }, 500)

  $(window).on("orderFormUpdated.vtex", function(evt, orderForm) {
    initializePayPal()
  })

})();

```


[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 paypalcp-checkout-ui-settings/checkout-ui-custom/checkout-confirmation-custom.js from the paypalcp-checkout-ui-settings VTEX app.

[Assistant]
Here's the implementation:

```javascript
// WARNING: THE USAGE OF CUSTOM SCRIPTS IS NOT SUPPORTED. VTEX IS NOT LIABLE FOR ANY DAMAGES THIS MAY CAUSE.
// THIS MAY BREAK YOUR STORE AND STOP SALES. IN CASE OF ERRORS, PLEASE DELETE THE CONTENT OF THIS SCRIPT.

```


[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 paypalcp-checkout-ui-settings/checkout-ui-custom/checkout5-custom.js from the paypalcp-checkout-ui-settings VTEX app.

[Assistant]
Here's the implementation:

```javascript
// WARNING: THE USAGE OF CUSTOM SCRIPTS IS NOT SUPPORTED. VTEX IS NOT LIABLE FOR ANY DAMAGES THIS MAY CAUSE. THIS MAY BREAK YOUR STORE AND STOP SALES. IN CASE OF ERRORS, PLEASE DELETE THE CONTENT OF THIS SCRIPT.

```


[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 paypalcp-checkout-ui-settings/docs/README.md from the paypalcp-checkout-ui-settings VTEX app.

[Assistant]
Here's the implementation:

```markdown
📢 Use this project, [contribute](https://github.com/vtex-apps/paypalcp-checkout-ui-settings) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).

# PayPalCP Checkout UI Settings

<!-- DOCS-IGNORE:start -->
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

[![All Contributors](https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square)](#contributors-)

<!-- ALL-CONTRIBUTORS-BADGE:END -->
<!-- DOCS-IGNORE:end -->

An app to inject the necessary scripts to render PayPal Smart Payment Buttons in Checkout V6.

For more information see the [PayPal Commerce Platform app documentation](https://developers.vtex.com/docs/guides/vtex-connector-paypal-commerce-platform).

<!-- DOCS-IGNORE:start -->

## Contributors ✨

Thanks goes to these wonderful people:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!

<!-- DOCS-IGNORE:end -->

```


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

[Assistant]
Here's the implementation:

```markdown
📢 Use this project, [contribute](https://github.com/vtex-apps/elfsight) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).

# Elfsight

<!-- DOCS-IGNORE:start -->
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<!-- DOCS-IGNORE:end -->

Elfsight first party integration app. The [solution](https://elfsight.com/) provides widgets that help website owners to increase sales, engage visitors, collect leads and more.

![image](https://user-images.githubusercontent.com/284515/87573824-dbee0700-c6a3-11ea-9ca2-0f03809b785b.png)

## Configuration

1. Adding the app as a theme dependency in the `manifest.json` file;

```json
"dependencies": {
  "vtex.elfsight": "1.x"
}
```

2. Add the block `elfsight`, responsible for rendering your Elfsight widget, to your theme `blocks.json` file. Notice: the block can be added to any page template you want.
3. Declare in it the prop `appId` whose value must be the app ID of the widget provided by Elfsight. For example:

```diff
   "footer-layout.desktop": {
     "children": [
+      "elfsight#foobar"
     ]
   },

+  "elfsight#foobar": {
+    "props": {
+      "appId": "4a13d81d-20f3-4661-b472-9de777efe3ed"
+    }
+  }
```

### `elfsight` props

| Prop name    | Type            | Description    | Default value                                                                                |
| ------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `appId`      | `string`       | The app ID of the widget provided by Elfsight. The format should be as follows: `XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX`.      | `undefined`        |

You should get the app ID from the Elfsight admin:

![App Id](https://user-images.githubusercontent.com/284515/87574775-3d62a580-c6a5-11ea-8278-3090254b16af.png)

<!-- DOCS-IGNORE:start -->

## Contributors ✨

Thanks goes to these wonderful people:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!

<!-- DOCS-IGNORE:end -->

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'

interface Props {
  appId?: string
}

const Elfsight: FC<Props> = ({ appId }) => {
  if (!appId) {
    return null
  }

  return <div className={`elfsight-app-${appId}`} />
}

export default Elfsight

```


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

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/graphql": "^14.5.0",
    "@types/jest": "^25.1.5",
    "@types/node": "^13.11.0",
    "@types/react": "^16.9.31",
    "@types/react-intl": "^3.0.0",
    "@vtex/test-tools": "^3.1.0",
    "apollo-cache-inmemory": "^1.6.5",
    "apollo-client": "^2.6.8",
    "graphql": "^14.5.4",
    "react-intl": "^3.11.0",
    "typescript": "3.8.3"
  },
  "version": "1.0.0"
}

```


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

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

[Assistant]
Here's the implementation:

```json
{
  "elfsight": {
    "component": "Elfsight"
  }
}

```


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

[Assistant]
Here's the implementation:

```typescript
export interface PixelMessage extends MessageEvent {
  data:
    | ProductViewData
    | ProductClickData
    | OrderPlacedData
    | OrderPlacedTrackedData
    | PageViewData
    | ProductImpressionData
    | AddToCartData
    | RemoveToCartData
    | CartChangedData
    | HomePageInfo
    | ProductPageInfoData
    | SearchPageInfoData
    | UserData
    | CartIdData
}

export interface EventData {
  event: string
  eventName: string
  currency: string
}

export interface PageInfoData extends EventData {
  event: 'pageInfo'
  eventName: 'vtex:pageInfo'
  accountName: string
  pageTitle: string
  pageUrl: string
}

export interface UserData extends PageInfoData {
  eventType: 'userData'
  eventName: 'vtex:userData'
  firstName?: string
  lastName?: string
  document?: string
  id?: string
  email?: string
  phone?: string
  isAuthenticated: boolean
}

export interface CartIdData extends PageInfoData {
  eventType: 'cartId'
  eventName: 'vtex:cartId'
  cartId: string
}

export interface HomePageInfo extends PageInfoData {
  eventType: 'homeView'
}

export interface ProductPageInfoData extends PageInfoData {
  eventType: 'productPageInfo'
}

export interface SearchPageInfoData extends PageInfoData {
  eventType:
    | 'internalSiteSearchView'
    | 'categoryView'
    | 'departmentView'
    | 'emptySearchView'
  category?: CategoryMetaData
  department?: DepartmentMetaData
  search?: SearchMetaData
}

interface CategoryMetaData {
  id: string
  name: string
}

interface DepartmentMetaData {
  id: string
  name: string
}

interface SearchMetaData {
  term: string
  category: CategoryMetaData
  results: number
}

export interface PageViewData extends EventData {
  event: 'pageView'
  eventName: 'vtex:pageView'
  pageTitle: string
  pageUrl: string
  referrer: string
}

export interface AddToCartData extends EventData {
  event: 'addToCart'
  eventName: 'vtex:addToCart'
  items: CartItem[]
}

export interface RemoveToCartData extends EventData {
  event: 'removeFromCart'
  eventName: 'vtex:removeFromCart'
  items: CartItem[]
}

export interface CartChangedData extends EventData {
  event: 'cartChanged'
  eventName: 'vtex:cartChanged'
  items: CartItem[]
}

export interface OrderPlacedData extends Order, EventData {
  event: 'orderPlaced'
  eventName: 'vtex:orderPlaced'
}

export interface OrderPlacedTrackedData extends Order, EventData {
  event: 'orderPlacedTracked'
  eventName: 'vtex:orderPlacedTracked'
}

export interface ProductViewData extends EventData {
  event: 'productView'
  eventName: 'vtex:productView'
  product: Product
}

export interface ProductClickData extends EventData {
  event: 'productClick'
  eventName: 'vtex:productClick'
  product: ProductSummary
}

export interface ProductImpressionData extends EventData {
  event: 'productImpression'
  eventName: 'vtex:productImpression'
  impressions: Impression[]
  product?: ProductSummary // deprecated, use impressions list!
  position?: number // deprecated, use impressions list!
  list: string
}

interface CartItem {
  brand: string
  category: string
  detailUrl: string
  imageUrl: string
  name: string
  price: number
  productId: string
  productRefId: string
  quantity: number
  skuId: string
  variant: string
}

export interface Order {
  accountName: string
  corporateName: string
  coupon: string
  currency: string
  openTextField: string
  orderGroup: string
  salesChannel: string
  visitorAddressCity: string
  visitorAddressComplement: string
  visitorAddressCountry: string
  visitorAddressNeighborhood: string
  visitorAddressNumber: string
  visitorAddressPostalCode: string
  visitorAddressState: string
  visitorAddressStreet: string
  visitorContactInfo: string[]
  visitorContactPhone: string
  visitorType: string
  transactionId: string
  transactionDate: string
  transactionAffiliation: string
  transactionTotal: number
  transactionShipping: number
  transactionSubtotal: number
  transactionDiscounts: number
  transactionTax: number
  transactionCurrency: string
  transactionPaymentType: PaymentType[]
  transactionShippingMethod: ShippingMethod[]
  transactionLatestShippingEstimate: Date
  transactionProducts: ProductOrder[]
  transactionPayment: {
    id: string
  }
}

export interface Impression {
  product: ProductSummary
  position: number
}

export interface PaymentType {
  group: string
  paymentSystemName: string
  installments: number
  value: number
}

export interface ShippingMethod {
  itemId: string
  selectedSla: string
}

export interface ProductOrder {
  id: string
  name: string
  sku: string
  skuRefId: string
  skuName: string
  productRefId: string
  ean: string
  slug: string
  brand: string
  brandId: string
  seller: string
  sellerId: string
  category: string
  categoryId: string
  categoryTree: string[]
  categoryIdTree: string[]
  priceTags: PriceTag[]
  originalPrice: number
  price: number
  sellingPrice: number
  tax: number
  quantity: number
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  components: any[]
  measurementUnit: string
  unitMultiplier: number
}

export interface PriceTag {
  identifier: string
  isPercentual: boolean
  value: number
}

export interface Product {
  brand: string
  brandId: string
  categories: string[]
  categoryId: string
  categoryTree: Array<{ id: string; name: string }>
  detailUrl: string
  items: Item[]
  linkText: string
  productId: string
  productName: string
  productReference: string
  selectedSku: Item
}

export interface Item {
  itemId: string
  name: string
  ean: string
  referenceId: { Key: string; Value: string }
  imageUrl: string
  sellers: Seller[]
}

export interface ProductSummary {
  brand: string
  brandId: string
  categories: string[]
  items: ItemSummary[]
  linkText: string
  productId: string
  productName: string
  productReference: string
  sku: ItemSummary
}

interface ItemSummary {
  itemId: string
  ean: string
  name: string
  referenceId: { Key: string; Value: string }
  seller: Seller
  sellers: Seller[]
}

export interface Seller {
  commertialOffer: CommertialOffer
  sellerId: string
}

export interface CommertialOffer {
  Price: number
  ListPrice: number
  AvailableQuantity: number
}

```


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

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.render-runtime' {
  export const canUseDOM: boolean
}

```


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

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

[Assistant]
Here's the implementation:

```typescript
interface Window extends Window {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  dataLayer: 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 pixel-manager/react/usePixel.ts from the pixel-manager VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useContext } from 'react'

import { PixelContext } from './PixelContext'

const usePixel = () => {
  return useContext(PixelContext)
}

export default usePixel

```


[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 pixel-manager/react/usePixelEventCallback.ts from the pixel-manager VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useEffect, useRef } from 'react'

import type { PixelData } from './PixelEventTypes'

export const shouldCallEventHandler = (
  pixelEventData: PixelData,
  eventId: string | undefined,
  eventName: PixelData['event']
) => {
  const receivedEventId = Boolean(eventId)
  const receivedEventName = Boolean(eventName)
  const hasEventId = Boolean(pixelEventData.id)
  const hasEventName = Boolean(pixelEventData.event)

  // These checks are to make sure that handlers are only called when
  // both the 'eventId' (if received) and the 'eventName' (if received)
  // match the event being processed.
  // If any of those arguments were NOT received, only the one that was
  // received should be taken into account.
  if (receivedEventId && hasEventId && pixelEventData.id === eventId) {
    return (
      !receivedEventName || (hasEventName && pixelEventData.event === eventName)
    )
  }

  if (receivedEventName && hasEventName && pixelEventData.event === eventName) {
    return !receivedEventId || (hasEventId && pixelEventData.id === eventId)
  }

  return false
}

const usePixelEventCallback = ({
  eventId,
  eventName,
  handler,
}: {
  eventId?: string
  eventName?: PixelData['event']
  handler: (e?: MessageEvent) => void
}) => {
  const savedHandler = useRef(handler)

  useEffect(() => {
    savedHandler.current = handler
  }, [handler])

  useEffect(() => {
    const isSupported = Boolean(window?.addEventListener)

    if (!isSupported || (!eventId && !eventName)) {
      return
    }

    const customEventHandler = (e: MessageEvent) => {
      const pixelEventData = e.data as PixelData

      if (shouldCallEventHandler(pixelEventData, eventId, eventName)) {
        savedHandler.current(e)
      }
    }

    window.addEventListener('message', customEventHandler)

    return () => {
      window.removeEventListener('message', customEventHandler)
    }
  }, [eventId, eventName, savedHandler])
}

export default usePixelEventCallback

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.pixel-manager",
  "version": "1.9.0",
  "private": true,
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "graphql": "^14.0.2",
    "hoist-non-react-statics": "^3.2.1",
    "ramda": "^0.26.1",
    "react-apollo": "^2.3.3"
  },
  "devDependencies": {
    "@types/hoist-non-react-statics": "^3.0.1",
    "@types/jest": "^24.0.3",
    "@types/prop-types": "^15.5.8",
    "@types/ramda": "types/npm-ramda#dist",
    "@types/react": "^16.7.17",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.4.4",
    "graphql-tag": "^2.10.0",
    "react": "^16.8.1",
    "react-dom": "^16.8.1",
    "typescript": "3.9.7",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.128.2/public/@types/vtex.render-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 pixel-manager/react/PixelEventTypes.ts from the pixel-manager VTEX app.

[Assistant]
Here's the implementation:

```typescript
export type EventName =
  | 'addToCart'
  | 'cart'
  | 'cartChanged'
  | 'cartId'
  | 'cartLoaded'
  | 'categoryView'
  | 'checkout'
  | 'checkoutOption'
  | 'departmentView'
  | 'finishPayment'
  | 'homeView'
  | 'installWebApp'
  | 'internalSiteSearchView'
  | 'openDrawer'
  | 'orderPlaced'
  | 'otherView'
  | 'pageComponentInteraction'
  | 'pageInfo'
  | 'pageView'
  | 'productClick'
  | 'productComparison'
  | 'productImpression'
  | 'productView'
  | 'promotionClick'
  | 'promoView'
  | 'removeFromCart'
  | 'sendPayments'
  | 'newsletterSubscription'
  | 'viewCart'
  | 'beginCheckout'
  | 'addPaymentInfo'
  | 'addShippingInfo'
  | 'addToWishlist'
  | 'share'
  | 'login'
  | 'search'
  | 'signUp'
  | 'refund'

export interface PixelData {
  id?: string
  event?: EventName
  [data: string]: unknown
}

```


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

[User] Show me the implementation of pixel-manager/react/PixelContext.tsx from the pixel-manager VTEX app.

[Assistant]
Here's the implementation:

```tsx
import hoistNonReactStatics from 'hoist-non-react-statics'
import React, { useContext, createContext, PureComponent } from 'react'

import type { PixelData } from './PixelEventTypes'

interface PixelEvent extends Event {
  data: any
}

export interface PixelContextType {
  push: (data: PixelData) => void
}

declare let process: {
  env: {
    NODE_ENV: 'production' | 'development'
    VTEX_APP_ID: string
  }
}

interface Props {
  currency: string
}

export const PixelContext = createContext<PixelContextType>({
  push: () => undefined,
})

const getDisplayName = <T extends Record<string, any>>(
  comp: React.ComponentType<T>
) => (comp.displayName ?? comp.name) || 'Component'

export const usePixel = () => useContext(PixelContext)

/**
 * withPixel is the HOC Component that provides an event subscription to the
 * Wrapped Component. This component will be used by the installed apps.
 */
export function withPixel<T>(
  WrappedComponent: React.ComponentType<T & PixelContextType>
) {
  const PixelComponent: React.FC<T> = (props) => {
    const { push } = usePixel()

    return <WrappedComponent {...props} push={push} />
  }

  PixelComponent.displayName = `withPixel(${getDisplayName(WrappedComponent)})`

  return hoistNonReactStatics(PixelComponent, WrappedComponent)
}

class PixelProvider extends PureComponent<Props> {
  private pixelContextValue: PixelContextType

  constructor(props: Props) {
    super(props)

    this.pixelContextValue = {
      push: this.push,
    }
  }

  public componentDidMount() {
    window.addEventListener('message', this.handleWindowMessage)
  }

  public componentWillUnmount() {
    window.removeEventListener('message', this.handleWindowMessage)
  }

  /**
   * Push event to iframe
   */
  public push = (data: PixelData) => {
    // Add all events to window when is linking to ease debugging
    // **Don't make those if's one!**
    if (process.env.NODE_ENV === 'development') {
      if (typeof window !== 'undefined') {
        window.pixelManagerEvents = window.pixelManagerEvents || []
        window.pixelManagerEvents.push(data)
      }
    }

    this.handlePixelEvent(data)
  }

  public render() {
    return (
      <PixelContext.Provider value={this.pixelContextValue}>
        {this.props.children}
      </PixelContext.Provider>
    )
  }

  private handleWindowMessage = (e: PixelEvent) => {
    if (e.data.pageComponentInteraction) {
      this.push({
        data: e.data,
        event: 'pageComponentInteraction',
      })
    }
  }

  private enhanceEvent = (event: PixelData, currency: string) => ({
    currency,
    eventName: `vtex:${event.event}`,
    ...event,
  })

  private handlePixelEvent = (event: PixelData) => {
    const eventData = this.enhanceEvent(event, this.props.currency)

    try {
      window.postMessage(eventData, window.origin)
    } catch (e) {
      // IE and Edge have a bug on postMessage inside promises.
      // Ignoring for now, will try to find a workaround that
      // makes postMessage work on those browsers.
      // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14719328/
    }
  }
}

export default {
  Pixel: withPixel,
  withPixel,
  PixelProvider,
  usePixel,
}

```


[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 pixel-manager/react/typings/globals.d.ts from the pixel-manager VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Window extends Window {
  pixelManagerEvents: any[]
}

```