[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 storefront-permissions-components/react/components/customers-admin.tsx from the storefront-permissions-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { FC } from 'react'
import React, { Fragment, useState } from 'react'
import { useIntl, defineMessages } from 'react-intl'
import { useQuery, useMutation, useLazyQuery } from 'react-apollo'
import {
  Button,
  Dropdown,
  Alert,
  Spinner,
  Tabs,
  Tab,
  Table,
} from 'vtex.styleguide'

import OrganizationsAutocomplete from './OrganizationsAutocomplete'
import GET_USER from '../queries/getUser.gql'
import GET_ROLES from '../queries/ListRoles.gql'
import GET_COST from '../queries/costCentersByOrg.gql'
import GET_ORGANIZATIONS from '../queries/getOrganizationsByEmail.graphql'
import ADD_USER from '../mutations/addUser.gql'
import DELETE_USER from '../mutations/deleteUser.gql'
import CostCenterAutocomplete from './CostCentersAutocomplete'

export const messages = defineMessages({
  b2bInfo: {
    id: 'admin/storefront-permissions.b2bInfo.title',
    defaultMessage: 'B2B Information',
  },
  role: {
    id: 'admin/storefront-permissions.tab.roles.name.label',
    defaultMessage: 'Role',
  },
  canImpersonate: {
    id: 'admin/storefront-permissions.tab.users.canImpersonate.label',
    defaultMessage: 'Can impersonate',
  },
  name: {
    id: 'admin/storefront-permissions.tab.users.name.label',
    defaultMessage: 'Name',
  },
  email: {
    id: 'admin/storefront-permissions.tab.users.email.label',
    defaultMessage: 'Email',
  },
  organization: {
    id: 'admin/storefront-permissions.tab.users.organization.label',
    defaultMessage: 'Organization',
  },
  costCenter: {
    id: 'admin/storefront-permissions.tab.users.costCenter.label',
    defaultMessage: 'Cost Center',
  },
  required: {
    id: 'admin/storefront-permissions.required',
    defaultMessage: 'Required',
  },
  cancel: {
    id: 'admin/storefront-permissions.button.cancel',
    defaultMessage: 'Cancel',
  },
  save: {
    id: 'admin/storefront-permissions.button.save',
    defaultMessage: 'Save',
  },
  add: {
    id: 'admin/storefront-permissions.button.add',
    defaultMessage: 'Add',
  },
  remove: {
    id: 'admin/storefront-permissions.button.remove',
    defaultMessage: 'Remove',
  },
  options: {
    id: 'admin/storefront-permissions.label.options',
    defaultMessage: 'Options',
  },
  b2bRoles: {
    id: 'admin/storefront-permissions.label.b2bRoles',
    defaultMessage: 'B2b Roles',
  },
  addNew: {
    id: 'admin/storefront-permissions.button.addNew',
    defaultMessage: 'Add New',
  },
  delete: {
    id: 'admin/storefront-permissions.button.delete',
    defaultMessage: 'Remove B2B Info',
  },
  success: {
    id: 'admin/storefront-permissions.tab.users.success',
    defaultMessage: 'B2B info saved',
  },
  alertPick: {
    id: 'admin/storefront-permissions.alert-pick',
    defaultMessage:
      'You need to pick a cost center before you can save changes',
  },
  error: {
    id: 'admin/storefront-permissions.tab.users.error',
    defaultMessage: 'Error saving B2B info',
  },
  searchOrganizations: {
    id: 'admin/storefront-permissions.searchOrganizations',
    defaultMessage: 'Search organizations...',
  },
})

const parseOptions = (options: any) => {
  return (
    options?.data?.map((orgOrCostCenter: any) => {
      return {
        value: orgOrCostCenter.id,
        label: orgOrCostCenter.name,
      }
    }) ?? []
  )
}

const initialState = {
  message: null,
  id: null,
  roleId: null,
  orgId: null,
  costId: null,
  userId: null,
  clId: null,
  name: null,
  email: null,
  canImpersonate: false,
  organizationName: null,
}

const UserEdit: FC<any> = (props: any) => {
  const { formatMessage } = useIntl()
  const {
    id,
    name = null,
    email = null,
    showName,
    showEmail,
    showCancel,
    onCancel,
    onSave,
  } = props

  const [state, setState] = useState<any>({
    ...initialState,
    clId: id,
    name,
    email,
  })

  const [tabs, setTabs] = useState(0)
  const [organizations, setOrganizations] = useState([] as any)
  const [isRemoving, setIsRemoving] = useState(false)

  const { loading, refetch } = useQuery(GET_USER, {
    skip: !id,
    variables: {
      id,
    },
    fetchPolicy: 'network-only',
    notifyOnNetworkStatusChange: true,
    onCompleted: (res: any) => {
      setState({
        ...state,
        ...res.getUser,
      })
    },
  })

  const handleTabs = (tab: number) => {
    setTabs(tab)
    setState({
      ...state,
      roleId: null,
      orgId: null,
      costId: null,
      message: null,
    })
  }

  const { refetch: refetchOrganizations, loading: loadingOrganizations } =
    useQuery(GET_ORGANIZATIONS, {
      variables: {
        email,
      },
      fetchPolicy: 'network-only',
      notifyOnNetworkStatusChange: true,
      onCompleted: (res: any) => {
        const result = res.getOrganizationsByEmail?.map((organization: any) => {
          return {
            ...organization,
            role: organization.role.name,
          }
        })

        if (result.length === 0) {
          handleTabs(1)
        }

        setOrganizations([
          ...result,
          ...organizations.filter(
            (item: any) =>
              !result.find((subitem: any) => subitem.id !== item.id)
          ),
        ])
      },
    })

  const { loading: loadingRoles, data: dataRoles } = useQuery(GET_ROLES)

  const [saveUser, { loading: saveUserLoading }] = useMutation(ADD_USER)

  const [deleteUser, { loading: deleteUserLoading }] = useMutation(DELETE_USER)

  const [
    getCostCenter,
    { data: dataCostCenter, called, loading: loadingCostCenters },
  ] = useLazyQuery(GET_COST)

  const onMutationError = () => {
    setState({
      ...state,
      message: 'error',
    })
  }

  const roleOptions =
    dataRoles?.listRoles?.map((role: any) => {
      return {
        value: role.id,
        label: role.name,
      }
    }) ?? []

  const optionsCost = parseOptions(
    dataCostCenter?.getCostCentersByOrganizationId
  )

  const handleSaveUser = () => {
    const variables = {
      clId: state.clId,
      userId: state.userId,
      roleId: state.roleId,
      orgId: state.orgId,
      costId: state.costId,
      name: state.name,
      email: state.email,
      canImpersonate: state.canImpersonate,
    }

    const roleName = roleOptions.find(
      (role: any) => role.value === state.roleId
    )?.name

    const costCenterName = optionsCost.find(
      (costCenter: any) => costCenter.value === state.costId
    )?.name

    const { organizationName } = state

    saveUser({
      variables,
    })
      .then((res) => {
        if (onSave) {
          onSave()
        }

        setState({
          ...state,
          id: state.id ?? res?.data?.addUser?.id,
          message: 'success',
        })
        refetchOrganizations()
        setOrganizations([
          ...organizations,
          {
            ...variables,
            id: res?.data?.addUser?.id,
            role: roleName,
            organizationName,
            costCenterName,
          },
        ])
      })
      .catch(onMutationError)
  }

  const handleDeleteUser = (userData: any) => {
    const variables = {
      id: userData.id,
      userId: userData.userId,
      email: state.email,
      clId: userData.clId,
    }

    setIsRemoving(true)

    deleteUser({
      variables,
    })
      .then((res) => {
        if (onSave) {
          onSave()
        }

        setState({
          ...state,
          roleId: null,
          orgId: null,
          costId: null,
          id: state.id ?? res?.data?.deleteUser?.id,
          message: 'success',
        })
        setOrganizations([])
        refetch()
        refetchOrganizations()
      })
      .catch(onMutationError)
      .finally(() => {
        setIsRemoving(false)
      })
  }

  if (state.costId && !called) {
    getCostCenter({
      variables: {
        id: state.orgId,
      },
    })
  }

  if (loading || loadingRoles || loadingCostCenters) {
    return (
      <div className="w-100 pt6 flex items-center justify-center">
        <Spinner />
      </div>
    )
  }

  const customSchema = {
    properties: {
      role: {
        title: formatMessage(messages.role),
      },
      organizationName: {
        title: formatMessage(messages.organization),
      },
      costCenterName: {
        title: formatMessage(messages.costCenter),
      },
      options: {
        title: formatMessage(messages.options),
        // you can customize cell component render (also header component with headerRenderer)
        cellRenderer: ({ rowData }: any) => {
          return (
            <Fragment>
              <div className="mt2 mb2">
                <Button
                  variation="danger"
                  size="small"
                  disabled={isRemoving}
                  onClick={() => handleDeleteUser(rowData)}
                >
                  {formatMessage(messages.remove)}
                </Button>
              </div>
            </Fragment>
          )
        },
      },
    },
  }

  return (
    <div className="w-100 pt6">
      <Tabs fullWidth className="mb4">
        <Tab
          active={tabs === 0}
          label={formatMessage(messages.b2bRoles)}
          onClick={() => handleTabs(0)}
        />
        <Tab
          active={tabs === 1}
          label={formatMessage(messages.addNew)}
          onClick={() => handleTabs(1)}
        />
      </Tabs>
      <div className="pa7">
        {tabs === 0 ? (
          <Fragment>
            <Table
              loading={loadingOrganizations || isRemoving}
              fullWidth
              schema={customSchema}
              items={organizations}
            />
          </Fragment>
        ) : (
          <Fragment>
            {showName && <div className="mb5">{state.name}</div>}
            {showEmail && <div className="mb5">{state.email}</div>}
            {roleOptions.length > 1 && (
              <div className="mb5">
                <Dropdown
                  label={formatMessage(messages.role)}
                  options={roleOptions}
                  value={state.roleId}
                  onChange={(_: any, v: string) => {
                    setState({
                      ...state,
                      roleId: v,
                    })
                  }}
                />
              </div>
            )}

            {dataRoles && state.roleId && (
              <div className="mb5 w-100">
                <div className="flex">
                  <div className="w-100">
                    <label className="h-100">
                      <span className="db mt0 mb3 c-on-base t-small">
                        {formatMessage(messages.organization)}
                      </span>
                      <OrganizationsAutocomplete
                        organizationId={state.orgId}
                        onChange={(event) => {
                          if (event.value === state.orgId) {
                            return
                          }

                          setState({
                            ...state,
                            orgId: event.value,
                            costId: null,
                            organizationName: event.label,
                          })
                          if (!event.value) return
                          getCostCenter({
                            variables: {
                              id: event.value,
                            },
                          })
                        }}
                      />
                    </label>
                  </div>
                </div>
              </div>
            )}

            {state.orgId && (
              <div className="mb5 w-100">
                <div className="flex">
                  <div className="w-100">
                    <label className="h-100">
                      <span className="db mt0 mb3 c-on-base t-small">
                        {formatMessage(messages.costCenter)}
                      </span>
                      <CostCenterAutocomplete
                        organizationId={state.orgId}
                        onChange={(event) => {
                          setState({ ...state, costId: event.value })
                        }}
                      />
                    </label>
                  </div>
                </div>
              </div>
            )}

            {state.orgId && !state.costId ? (
              <div className="mv4">
                <Alert type="error">{formatMessage(messages.alertPick)}</Alert>
              </div>
            ) : null}

            <div className="mv4 flex justify-start">
              {showCancel && onCancel && (
                <div className="mr3">
                  <Button
                    variation="tertiary"
                    disabled={loading}
                    onClick={() => {
                      onCancel()
                    }}
                  >
                    {formatMessage(messages.cancel)}
                  </Button>
                </div>
              )}
              <Button
                variation="primary"
                disabled={
                  loading ||
                  saveUserLoading ||
                  deleteUserLoading ||
                  !state.name ||
                  !state.email ||
                  !state.orgId ||
                  !state.costId ||
                  !state.roleId
                }
                onClick={() => {
                  handleSaveUser()
                }}
              >
                {formatMessage(messages.add)}
              </Button>
            </div>
            {state.message && (
              <Alert
                type={state.message}
                onClose={() => {
                  setState({ ...state, message: null })
                }}
              >
                {state.message === 'success'
                  ? formatMessage(messages.success)
                  : formatMessage(messages.error)}
              </Alert>
            )}
          </Fragment>
        )}
      </div>
    </div>
  )
}

export default UserEdit

```


[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 storefront-permissions-components/react/components/CostCentersAutocomplete.tsx from the storefront-permissions-components VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useState } from 'react'
import { useQuery } from 'react-apollo'
import { useIntl } from 'react-intl'
import { EXPERIMENTAL_Select } from 'vtex.styleguide'

import { messages } from './customers-admin'
import GET_COST_CENTER_BY_ORG from '../queries/costCentersByOrg.gql'
import { SEARCH_TERM_DELAY_MS } from '../constants/debounceDelay'

interface Props {
  onChange: (value: { value: string | null; label: string }) => void
  organizationId?: string
}

const initialState = {
  search: '',
  page: 1,
  pageSize: 25,
  sortOrder: 'ASC',
  sortedBy: 'name',
}

const CostCenterAutocomplete = ({ onChange, organizationId }: Props) => {
  const { formatMessage } = useIntl()
  const [costCenterTextInput, setCostCenterTextInput] = useState('')
  const [debouncedSearchTerm, setDebouncedSearchTerm] =
    useState(costCenterTextInput)

  const { data, loading, refetch } = useQuery(GET_COST_CENTER_BY_ORG, {
    variables: {
      ...initialState,
      id: organizationId,
    },
    ssr: false,
    notifyOnNetworkStatusChange: true,
    skip: !organizationId,
  })

  const options =
    data?.getCostCentersByOrganizationId?.data?.map(
      (costCenter: { id: string; name: string }) => ({
        value: costCenter.id,
        label: costCenter.name,
      })
    ) || []

  const handleSearchInputChange = (searchInput: string | null) => {
    setCostCenterTextInput(searchInput ?? '')
  }

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedSearchTerm(costCenterTextInput)
    }, SEARCH_TERM_DELAY_MS) // 500ms delay

    return () => {
      clearTimeout(handler)
    }
  }, [costCenterTextInput])

  useEffect(() => {
    if (debouncedSearchTerm) {
      refetch({
        ...initialState,
        id: organizationId,
        search: debouncedSearchTerm,
      })
    } else if (debouncedSearchTerm === '') {
      onChange({ value: null, label: '' })
    }
  }, [debouncedSearchTerm])

  const handleChange = (
    selectedOption: { value: string | null; label: string } | null
  ) => {
    if (!selectedOption || !selectedOption.value) {
      setCostCenterTextInput('')
      refetch({
        ...initialState,
        id: organizationId,
        search: '',
      })
    }

    onChange(selectedOption ?? { value: null, label: '' })
  }

  return (
    <EXPERIMENTAL_Select
      onSearchInputChange={handleSearchInputChange}
      onChange={handleChange}
      loading={loading}
      options={options}
      placeholder={formatMessage(messages.costCenter)}
      multi={false}
      valuesMaxHeight={200}
      claerable={true}
    />
  )
}

export default CostCenterAutocomplete

```


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

[Assistant]
Here's the implementation:

```json
{
  "extensions": {
    "checkout/buttons/checkout-button-example": {
      "component": "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 checkout-button-example/react/index.tsx from the checkout-button-example VTEX app.

[Assistant]
Here's the implementation:

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

import CustomButton from './components/CustomButton'

class CheckoutButtonExample extends Component<{}, CheckoutButtonExampleState> {
  /**
   * This component is the one that is referenced in the extension point. To use it
   * as an example, we add an event listener, which updates the state every time the
   * order form changes. This order form is then passed to its children so as to render
   * a table with the items.
   */
  constructor(props: any) {
    super(props)
    this.state = {
      orderForm: null,
    }
  }

  setOrderForm = (_: any, orderForm: OrderForm) => {
    this.setState({ orderForm })
  }

  componentDidMount() {
    $(window).on('orderFormUpdated.vtex', this.setOrderForm)
  }

  componentWillUnmount() {
    $(window).off('orderFormUpdated.vtex', this.setOrderForm)
  }

  render() {
    console.log(window.vtex.i18n.getLocale())

    return <CustomButton {...this.state.orderForm!} />
  }
}

interface CheckoutButtonExampleProps {}

interface CheckoutButtonExampleState {
  orderForm: OrderForm | null
}

export default CheckoutButtonExample

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.checkout-button-example",
  "version": "0.0.3",
  "scripts": {
    "lint": "eslint --ext js,jsx,ts,tsx ."
  },
  "dependencies": {
    "@vtex/styleguide": "^9.96.6"
  },
  "devDependencies": {
    "@types/jquery": "^3.3.38",
    "@types/graphql": "^0.13.3",
    "@types/node": "^9.4.7",
    "@types/prop-types": "^15.5.2",
    "@types/react": "^16.3.16",
    "@types/react-dom": "^16.0.5",
    "@types/react-helmet": "^5.0.5",
    "@types/react-intl": "^2.3.5",
    "eslint": "^6.4.0",
    "eslint-config-vtex": "^11.0.0",
    "eslint-config-vtex-react": "^5.0.1",
    "graphql": "^0.13.0",
    "prettier": "^1.18.2",
    "react": "^16.2.0",
    "react-apollo": "^2.0.4",
    "react-dom": "^16.2.0",
    "react-intl": "^2.4.0",
    "typescript": "3.9.7"
  }
}

```


[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 checkout-button-example/react/orderFormExample.json from the checkout-button-example VTEX app.


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

[Assistant]
Here's the implementation:

```typescript
interface Window extends Window {
  vtex: any
}

interface OrderFormContext {
  orderForm: OrderForm
  loading: boolean
}

interface OrderFormItem {
  additionalInfo: ItemAdditionalInfo
  availability: string
  detailUrl: string
  id: string
  imageUrl: string
  listPrice: number
  measurementUnit: string
  name: string
  price: number
  productId: string
  quantity: number
  sellingPrice: number
  skuName: string
  skuSpecifications: SKUSpecification[]
  uniqueId: string
  productCategories: Record<string, string>
  productCategoryIds: string
  productRefId: string
  refId: string
}

interface ItemAdditionalInfo {
  brandName: string
}

interface SKUSpecification {
  fieldName: string
  fieldValues: string[]
}

interface OrderForm {
  id: string
  items: OrderFormItem[]
  marketingData: MarketingData
  totalizers: Totalizer[]
  value: number
  messages: OrderFormMessages
}

interface MarketingData {
  coupon: string
}

interface Totalizer {
  id: string
  name: string
  value: number
}

interface OrderFormMessages {
  couponMessages: Message[]
  generalMessages: Message[]
}

interface Message {
  code: string
  status: string
  text: string
}

```


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

[User] Show me the implementation of checkout-button-example/react/components/Table.tsx from the checkout-button-example VTEX app.

[Assistant]
Here's the implementation:

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

class Table extends Component<TableProps> {
  constructor(props: any) {
    super(props)
  }
  render() {
    const { items } = this.props
    return (
      <div>
        {items.map(item => (
          <p>{item.name}</p>
        ))}
      </div>
    )
  }
}

interface TableProps {
  items: OrderFormItem[]
}

export default Table

```


[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 checkout-button-example/react/components/CustomButton.tsx from the checkout-button-example VTEX app.

[Assistant]
Here's the implementation:

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

import Table from './Table'

/**
 * This component is responsible for rendering the custom button itself. For instance,
 * we use it to render a table that contains the name of the items that are in the
 * order form.
 */
class CustomButton extends Component<CustomButtonProps, {}> {
  render() {
    const { items } = this.props

    return items ? (
      <div>
        <h2>This is a checkout button</h2>
        <Table items={items} />
      </div>
    ) : (
      <div>Loading...</div>
    )
  }
}

interface CustomButtonProps {
  items: OrderFormItem[]
}

interface CustomButtonState {}

export default CustomButton

```


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

[Assistant]
Here's the implementation:

```markdown
# on-view

<!-- 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 -->

## Usage

```sh
vtex add vtex.on-view@1.x
```

## API

### `useOnView`

The `onView` function is called whenever the HTML element is inside the viewport. It differs from [react-intersection-observer](https://www.npmjs.com/package/react-intersection-observer) in that it uses a callback approach instead of using a `setState`, improving performance by preventing unnecessary re-renders.

```tsx
import React from 'react'
import { useOnView } from 'vtex.on-view'

function MyComponent() {
  const element = useRef<HTMLDivElement | null>(null)

  useOnView({
    ref: element,
    once: true,
    onView: () => {
      console.log('Element is visible')
    },
  })

  return
Hello World

}

export default MyComponent
```

### `useRenderOnView`

It renders a dummy element while the element is not inside the viewport.

```tsx
import React from 'react'
import { useRenderOnView } from 'vtex.on-view'

function MyComponent() {
  const element = useRef<HTMLDivElement | null>(null)

  const { hasBeenViewed, placeholderElement } = useRenderOnView({
    lazyRender: true,
  })

  if (!hasBeenViewed) {
    return placeholderElement
  }

  return
Hello World

}

export default MyComponent
```

<!-- 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 on-view/react/package.json from the on-view VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "on-view",
  "version": "1.0.0",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "apollo-client": "^2.6.8",
    "react": "^16.12.0",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.12.0",
    "react-intl": "^3.12.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/jest": "^25.1.4",
    "@types/node": "^13.9.8",
    "@types/react": "^16.9.31",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.4.4",
    "apollo-cache-inmemory": "^1.6.5",
    "graphql": "^14.6.0",
    "typescript": "3.9.7"
  }
}

```


[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 on-view/react/useRenderOnView.tsx from the on-view VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useRef } from 'react'

import useOnView from './useOnView'

const useRenderOnView = ({
  lazyRender = false,
  height = 400,
  offset = 200,
  waitForUserInteraction = true,
}) => {
  const placeholder = useRef<HTMLDivElement | null>(null)
  const [hasBeenViewed, setHasBeenViewed] = useState(false)

  useOnView({
    ref: placeholder,
    onView: () => setHasBeenViewed(true),
    once: true,
    initializeOnInteraction: waitForUserInteraction,
    bailOut: !lazyRender,
  })

  const placeholderElement = (
    <div
      style={{
        width: '100%',
        height,
        position: 'relative',
      }}
    >
      <div
        ref={placeholder}
        style={{
          /** Allows detecting the view a bit earlier, allowing rendering before the user
           * sees the whitespace where the component should be */
          top: -offset,
          bottom: 0,
          left: 0,
          right: 0,
          position: 'absolute',
        }}
      />
    </div>
  )

  return { hasBeenViewed: hasBeenViewed || !lazyRender, placeholderElement }
}

export default useRenderOnView

```


[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 on-view/react/useOnView.ts from the on-view VTEX app.

[Assistant]
Here's the implementation:

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

interface IntersectionEvent {
  entry: IntersectionObserverEntry
  unobserve: () => void
}

interface HookOptions {
  ref: MutableRefObject<HTMLElement | null>
  onView?: (event: IntersectionEvent) => any
  threshold?: number
  once?: boolean
  bailOut?: boolean
  initializeOnInteraction?: boolean
}

/** Hook for detecting when an element is inside the viewport.
 * Differs from react-intersection-observer (https://www.npmjs.com/package/react-intersection-observer)
 * in that this hook doesn't use setState, using a callback approach instead, to improve
 * performance by preventing re-rendering.
 */
const useOnView = ({
  ref,
  onView,
  threshold = 0,
  once = false,
  bailOut = false,
  initializeOnInteraction = false,
}: HookOptions) => {
  const isObserving = useRef(false)
  const didIntersect = useRef(false)

  useEffect(() => {
    const initializeObserver = () => {
      const element = ref.current

      if (
        bailOut ||
        isObserving.current ||
        !element ||
        !onView ||
        (once && didIntersect.current)
      ) {
        return () => {}
      }

      isObserving.current = true

      const unobserve = () => {
        if (isObserving.current) {
          // eslint-disable-next-line @typescript-eslint/no-use-before-define
          observer.unobserve(element)
          isObserving.current = false
        }
      }

      const observer = new IntersectionObserver(([entry]) => {
        if (!entry.isIntersecting) {
          return
        }

        if (entry.intersectionRatio < threshold) {
          return
        }

        if (once) {
          unobserve()
        }

        didIntersect.current = true
        onView({ entry, unobserve })
      })

      observer.observe(element)

      return unobserve
    }

    if (initializeOnInteraction) {
      const cleanUpEvents = () => {
        // eslint-disable-next-line @typescript-eslint/no-use-before-define
        window?.document?.removeEventListener('scroll', handleInteraction)
        // eslint-disable-next-line @typescript-eslint/no-use-before-define
        window?.document?.removeEventListener('mouseover', handleInteraction)
      }

      let unobserve = () => {
        cleanUpEvents()
      }

      const handleInteraction = () => {
        cleanUpEvents()
        unobserve = initializeObserver()
      }

      window?.document?.addEventListener('scroll', handleInteraction)
      window?.document?.addEventListener('mouseover', handleInteraction)

      return unobserve
    }

    return initializeObserver()
  }, [bailOut, initializeOnInteraction, onView, once, ref, threshold])
}

export default useOnView

```


[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 on-view/react/__tests__/index.test.tsx from the on-view 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 adserver-graphql/docs/README.md from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```markdown
# VTEX Adserver Graphql

`vtex.adserver-graphql` is the Graphql schema for the Adserver feature.

Check the full documentation to learn how to create a adserver for your account.

<!-- TODO: add link to the documentation -->

```


[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 adserver-graphql/graphql/schema.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Query {
  sponsoredProducts(
    """
    Search term. It can contain any character
    """
    query: String
    """
    Page number
    """
    page: Int
    """
    Number of items per page. **Warning:** Use `sponsoredCount` to limit the number of sponsored products.
    """
    count: Int
    """
    Sort the result by a criteria
    """
    sort: String
    """
    Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
    """
    operator: Operator
    """
    Indicates how the search engine will correct misspelled words by using fuzzy logic.
    It can be a number representing the max number of misspelled letters, or the string `auto` suggesting that the search-engine should set this value by itself.
    """
    fuzzy: String
    """
    As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
    The possible values in this field are defined by each search engine.
    """
    searchState: String
    """
    If the search has a redirect enabled, this allows (`true`) or not (`false`) the redirect to be used.
    """
    allowRedirect: Boolean
    """
    Indicates the user region. Useful for regionalized accounts.
    """
    regionId: String
    """
    If you want faster searches and do not care about most up to date prices and promotions, use skip value.
    """
    simulationBehavior: SimulationBehavior
    """
    If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel. Will override any given salesChannel arg
    """
    hideUnavailableItems: Boolean
    """
    List of the selected facets

    The order in which the terms appear is not relevant to the search.

    You can also repeat the same `facetKey` several times for different values.
    """
    selectedFacets: [SelectedFacetInput]
    """
    Rules for pormoting, demoting, adding or removing products
    """
    dynamicRules: [DynamicRuleInput]
    """
    Identifier for users, logged in or not. Used for A/B tests.
    """
    anonymousId: String
    """
    Identifier for user device, used for analytics purposes.
    """
    macId: String
    """
    Identifier for user ID if logged in, used for analytics purposes.
    """
    userId: String
    """
    Where the sponsored product in being shown. Used for analytics purposes.
    """
    placement: String
    """
    Maximum number of sponsored products that should be returned.
    """
    sponsoredCount: Int
    """
    SKU identifier used to segment the ads.
    """
    skuId: String
  ): [SponsoredProduct] @cacheControl(scope: PUBLIC, maxAge: SHORT)
  sponsoredBanners(
    """
    Maximum number of sponsored banners that should be returned.
    """
    sponsoredCount: Int
    """
    Placement of the banner. Used for analytics purposes.
    """
    placement: Placement
    """
    Banner dimensions.
    """
    adUnit: AdUnit
    """
    Channel where the banner is being shown. Used for analytics purposes.
    """
    channel: Channel
    """
    Identifier for users, logged in or not. Used for A/B tests.
    """
    anonymousId: String
  ): [SponsoredBanner] @cacheControl(scope: PUBLIC, maxAge: SHORT)
}

```


[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 adserver-graphql/node/package.json from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "search-graphql",
  "description": "Don't delete this file, it's necessary to generate the TypeScript types of the GraphQL"
}

```


[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 adserver-graphql/graphql/types/Channel.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
enum Channel {
  website
  android
  ios
  msite
  whatsapp
}

```


[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 adserver-graphql/graphql/types/DynamicRule.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
enum BoostAction {
  add
  remove
  promote
  demote
}

enum BoostType {
  term
  id
  skuId
  skuEan
  skuReference
  productLink
  product
  sku
  productId
  attribute
}

type DynamicRule {
  """
  Rule action that will be applied to the products
  """
  action: BoostAction
  """
  Type of identifier
  """
  type: BoostType
  """
  Value related to the identifier
  """
  value: String
}

input DynamicRuleInput {
  """
  Rule action that will be applied to the products
  """
  action: BoostAction
  """
  Type of identifier
  """
  type: BoostType
  """
  Value related to the identifier
  """
  value: String
}

```


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

[User] Show me the implementation of adserver-graphql/graphql/types/SponsoredProduct.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type SponsoredProduct {
  """
  Unique identifier of the product. Can be SKU, EAN or VTEX Product ID.
  """
  identifier: ProductUniqueIdentifier

  """
  ID of the sponsored product.
  """
  productId: ID @deprecated(reason: "Use `identifier` instead.")

  """
  Merchandising rule applied to the product.
  """
  rule: Rule

  """
  Sponsored campaign related information should be added here.
  """
  advertisement: Advertisement

  """
  Seller ID.
  """
  sellerId: ID
}

type ProductUniqueIdentifier {
  """
  Product ID value. If null, consider anyId as the default.
  """
  field: ProductUniqueIdentifierField
  """
  Product ID value.
  """
  value: ID
}

enum ProductUniqueIdentifierField {
  """
  Any ID, being SKU, EAN or VTEX Product ID. Keep in mind that multiple products can have equivalent SKU or Product ID.
  """
  anyId

  """
  VTEX Product ID, unique to this account.
  """
  product

  """
  SKU ID, unique to each variation of a product such as size, color, etc.
  """
  skuId
}

type Rule {
  """
  Rule ID.
  """
  id: String
}

type Advertisement {
  """
  ID of the ad item associated with the sponsored product.
  """
  adId: ID
  """
  ID of the campaign owner of the ad item.
  """
  campaignId: ID
  """
  Cost of the goal action. E.g: CPC, cost per click.
  """
  actionCost: Float
  """
  Ad Request ID.
  """
  adRequestId: ID
  """
  Ad Response ID.
  """
  adResponseId: ID
}

```


[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 adserver-graphql/graphql/types/Operator.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
"""
Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
"""
enum Operator {
  and
  or
}

```


[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 adserver-graphql/graphql/types/Placement.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
enum Placement {
  top_search
  middle_search
  home_shelfpdp_shelf
  search_shelf
  cart_shelf
  plp_shelf
  autocomplete
  homepage
}

```


[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 adserver-graphql/graphql/types/SelectedFacets.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
"""
Object that represents a selected facet. For example: {key: color, value: blue}
"""
type SelectedFacet {
  """
  Facet key
  """
  key: String
  """
  Facet value
  """
  value: String
}

"""
Object that represents a selected facet. For example: {key: color, value: blue}
"""
input SelectedFacetInput {
  """
  Facet key
  """
  key: String
  """
  Facet value
  """
  value: String
}

```


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

[User] Show me the implementation of adserver-graphql/graphql/types/AdUnit.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
enum AdUnit {
  billboard
  smartphonebanner
  leaderboard
  superleaderboard
  portrait
  skyscraper
  mediumrectangle
  button120x60
  mobilephoneinterstitial
  featurephonesmallbanner
  featurephonemediumbanner
  featurephonelargebanner
}

```


[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 adserver-graphql/graphql/types/SearchParams.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type SearchParams {
  """
  Search term. It can contain any character
  """
  query: String
  """
  List of the selected facets

  The order in which the terms appear is not relevant to the search.

  You can also repeat the same `facetKey` several times for different values.
  """
  selectedFacets: [SelectedFacet]
  """
  Sort the result by a criteria
  """
  sort: String
  """
  Page number
  """
  page: Int
  """
  Number of items per page
  """
  count: Int
  """
  If true, uses isAvailablePerSalesChannel_ parameter on query with segment's sales channel. Will override any given salesChannel arg
  """
  hideUnavailableItems: Boolean
  """
  Indicates how the search-engine will deal with the fullText if there is more than one word. Set `and` if the returned products must have all the words in its metadata or `or` otherwise.
  """
  operator: Operator
  """
  Indicates how the search engine will correct misspelled words by using fuzzy logic.
  It can be a number representing the max number of misspelled letters, or the string `auto` suggesting that the search-engine should set this value by itself.
  """
  fuzzy: String
  """
  As fuzzy and operator, it controls the search state, but it is for general purposes. This field allows the search engines to apply features that are not handled by the other fields.
  The possible values in this field are defined by each search engine.
  """
  searchState: String
  """
  If the search has a redirect enabled, this allows (`true`) or not (`false`) the redirect to be used.
  """
  allowRedirect: String
  """
  Rules for pormoting, demoting, adding or removing products
  """
  dynamicRules: [DynamicRule]
  """
  Indicates the user region. Useful for regionalized accounts.
  """
  regionId: String
  """
  If you want faster searches and do not care about most up to date prices and promotions, use skip value.
  """
  simulationBehavior: SimulationBehavior
}

```


[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 adserver-graphql/graphql/types/SponsoredBanner.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
type SponsoredBanner {
  """
  ID of the sponsored banner.
  """
  adResponseId: ID
  """
  Sponsored campaign related information should be added here.
  """
  advertisement: AdvertisementBanner
}

type AdvertisementBanner {
  """
  Banner Image ID.
  """
  bannerImageId: ID
  """
  URL of the image to be displayed in the ad.
  """
  imageUrl: String
  """
  URL to be redirected to when the ad is clicked.
  """
  targetUrl: String
  """
  Width of the banner in pixels.
  """
  width: Int
  """
  Height of the banner in pixels.
  """
  height: Int
}

```


[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 adserver-graphql/graphql/types/SimulationBehavior.graphql from the adserver-graphql VTEX app.

[Assistant]
Here's the implementation:

```graphql
"""
If you want faster searches and do not care about most up to date prices and promotions, use skip value.
"""
enum SimulationBehavior {
  """
  Ignore simulation calls
  """
  skip
  """
  Calls the simulation only for first party sellers
  """
  only1P
  """
  Calls the simulation for every single seller
  """
  default
}

```


[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 user-identifier-extension-example/docs/README.md from the user-identifier-extension-example VTEX app.

[Assistant]
Here's the implementation:

```markdown
# User identifier extension example

This app is an example implementation of the [Login's user identifier extension](https://github.com/vtex-apps/login#advanced-configuration).

```


[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 user-identifier-extension-example/react/Cpf.tsx from the user-identifier-extension-example VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { ReactNode } from 'react'
import React, { useState, useCallback, useEffect } from 'react'

interface OptionsRenderInput {
  value: string
  onChange: (newValue: string) => void
  placeholder: string
}

type HandleSubmit = () => Promise<string>

interface Props {
  renderInput: (options: OptionsRenderInput) => ReactNode
  identifierPlaceholder: string
  registerSubmitter: (handleSubmit: HandleSubmit) => void
}

const ComponentName = ({ renderInput, registerSubmitter }: Props) => {
  const [cpf, setCpf] = useState('')
  const onChangeInput = useCallback(e => setCpf(e.target.value), [setCpf])

  const onSubmit = useCallback(async () => {
    const email = `${cpf}@email.com`

    return email
  }, [cpf])

  useEffect(() => {
    registerSubmitter(onSubmit)
  }, [registerSubmitter, onSubmit])

  return (
    <>
      <div>This is a custom identifier (CPF) input</div>
      {renderInput({
        value: cpf,
        onChange: onChangeInput,
        placeholder: 'Your CPF here',
      })}
    </>
  )
}

export default ComponentName

```


[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 user-identifier-extension-example/react/package.json from the user-identifier-extension-example VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "react": "^16.4.1"
  },
  "devDependencies": {
    "@types/node": "^16.11.9",
    "@types/react": "^17.0.35",
    "@vtex/tsconfig": "^0.6.0",
    "typescript": "3.9.7",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.132.4/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 user-identifier-extension-example/store/interfaces.json from the user-identifier-extension-example VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "user-identifier.cpf": {
    "component": "Cpf"
  }
}

```


[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 user-identifier-extension-example/store/plugins.json from the user-identifier-extension-example VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "login > user-identifier": "user-identifier.cpf",
  "login-content > user-identifier": "user-identifier.cpf"
}

```


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

[Assistant]
Here's the implementation:

```markdown

# Service Example

A reference app implementing a VTEX IO service with HTTP route handlers.

![Service Example Architecture](https://user-images.githubusercontent.com/18706156/77381360-72489680-6d5c-11ea-9da8-f4f03b6c5f4c.jpg)

We use [**KoaJS**](https://koajs.com/) as the web framework, so you might want to get into that

We also use the [**node-vtex-api**](https://github.com/vtex/node-vtex-api), a VTEX set of utilities for Node services. You can import this package using NPM from `@vtex/api` (already imported on this project)

- Start from `node/index.ts` and follow the comments and imports :)

## Recipes

### Defining routes on _service.json_
```json
{
  "memory": 256,
  "ttl": 10,
  "timeout": 2,
  "minReplicas": 2,
  "maxReplicas": 4,
  "routes": {
    "status": {
      "path": "/_v/status/:code",
      "public": true
    }
  }
}
```

The `service.json` file that sits on the root of the `node` folder holds informations about this service, like the maximum timeout and number of replicas, what might be discontinued on the future, but also **sets its routes**.

Koa uses the [path-to-regexp](https://github.com/pillarjs/path-to-regexp) format for defining routes and, as seen on the example, we use the `:code` notation for declaring a **route param** named code, in this case. A HTTP request for `https://{{workspace}}--{{account}}.myvtex.com/_v/status/500` will match the route we've defined.

For cach _key_ on the `routes` object, there should be a **corresponding entry** on the exported Service object on `node/index.ts`, this will hook your code to a specific route.

### Access Control
You can also provide a `public` option for each route. If `true`, that resource will be reachable for everyone on the internet. If `false`, VTEX credentials will be requested as well.

Another way of controlling access to specific routes is using **ReBACs (Resource-based access)**, that supports more robust configuration. You can read more [on this document](https://docs.google.com/document/d/1ZxNHMFIXfXz3BgTN9xyrHL3V5dYz14wivYgQjRBZ6J8/edit#heading=h.z7pad3qd2qw7) (VTEX only).

#### Query String
For `?accepting=query-string`, you **don't need to declare anything**, as any query provided to the URL will already be available for you to use on the code as `ctx.query`, already parsed as an object, or `ctx.queryString`, taken directly from the URL as a string.

#### Route Params
Route Params will be available for you to use on the code as `ctx.vtex.params`, already parsed as an object.
For a path like `/_v/status/:code`, if you receive the request `/_v/status/200`, `ctx.vtex.params` will return `{ code: '200' }`

#### HTTP methods
When you define a route on the `service.json`, your NodeJS handlers for that route will be triggered  **on every HTTP method** (GET, POST, PUT...), so, if you need to handle them separately you need to implement a "sub-router". Fortunately, the _node-vtex-api_ provides a helper function `method`, exported from `@vtex/api`, to accomplish that behaviour. Instead of passing your handlers directly to the corresponding route on `index.ts`, you pass a `method` call passing **an object with the desired method as key and one handler as its corresponding value**. Check this example:
```typescript
import { method } from '@vtex/api'
...

export default new Service<Clients, State>({
  clients,
  routes: {
    status: method({
      GET: statusGetHandler,
      POST: statusPostHandler,
    }),
  },
})
```

### Throwing errors

When building a HTTP service, we should follow HTTP rules regarding data types, cache, authorization, and status code. Our example app sets a `ctx.status` value that will be used as a HTTP status code return value, but often we also want to give proper information about errors as well.

The **node-vtex-api** already exports a handful of **custom error classes** that can be used for that purpose, like the `NotFoundError`. You just need to throw them inside one of the the route handlers that the appropriate response will be sent to the server.

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

export async function validate(ctx: Context, next: () => Promise<any>) {
  const { code } = ctx.vtex.route.params
  if (isNaN(code) || code < 100 || code > 600) {
    throw new UserInputError('Code must be a number between 100 and 600')
  }
...
```

You can check all the available errors [here](https://github.com/vtex/node-vtex-api/tree/fd6139349de4e68825b1074f1959dd8d0c8f4d5b/src/errors), but some are not useful for just-HTTP services. Check the most useful ones:

|Error Class | HTTP Code |
|--|:--:|
| `UserInputError` | 400 |
| `AuthenticationError` | 401 |
| `ForbiddenError` | 403 |
| `NotFoundError` | 404 |

You can also **create your custom error**, just see how it's done above ;)

### Reading a JSON body

When writing POST or PUT handlers, for example, often you need to have access to the **request body** that comes as a JSON format, which is not provided directly by the handler function.

For this, you have to use the [co-body](https://www.npmjs.com/package/co-body) package that will parse the request into a readable JSON object, used as below:
```typescript
import { json } from 'co-body'
export async function method(ctx: Context, next: () => Promise<any>) {
    const body = await json(ctx.req)
```

### Other example apps

We use Node services across all VTEX, and there are a lot inspiring examples. If you want to dive deeper on learning about this subject, don't miss those internal apps: [builder-hub](https://github.com/vtex/builder-hub) or [store-sitemap](https://github.com/vtex-apps/store-sitemap)

## Testing

`@vtex/test-tools` and `@types/jest` should be installed on `./node` package as `devDependencies`.

Run `vtex test` and [Jest](https://jestjs.io/) will do its thing.

Check the `node/__tests__/simple.test.ts` test case and also [Jest's Documentation](https://jestjs.io/docs/en/getting-started).

## Splunk Dashboard

We have an (for now, VTEX-only, internal) Splunk dashboard to show all metrics related to your app. You can find it [here](https://splunk7.vtex.com/en-US/app/vtex_colossus/node_app_metrics).

After linking this app and making some requests, you can select `vtex.service-example` and see the metrics for your app. **Don't forget to check the box Development, as you are linking your app in a development workspace**.

For convenience, the link for the current version: https://splunk7.vtex.com/en-US/app/vtex_colossus/node_app_metrics?form.time.earliest=-30m%40m&form.time.latest=%40m&form.picked_context=false&form.picked_region=aws-us-east-*&form.picked_service=vtex.service-example

```


[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 multi-tenant-search/node/service.json from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 256,
  "ttl": 10,
  "timeout": 2,
  "minReplicas": 2,
  "maxReplicas": 4,
  "workers": 1,
  "routes": {
    "status": {
      "path": "/_v/status/:code",
      "public": true
    }
  }
}

```


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

[User] Show me the implementation of multi-tenant-search/node/package.json from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "co-body": "^6.0.0",
    "ramda": "^0.25.0"
  },
  "devDependencies": {
    "@types/co-body": "^0.0.3",
    "@types/jest": "^24.0.18",
    "@types/node": "^12.0.0",
    "@types/ramda": "types/npm-ramda#dist",
    "@vtex/api": "6.37.1",
    "@vtex/test-tools": "^1.0.0",
    "@vtex/tsconfig": "^0.5.6",
    "typescript": "3.9.7"
  },
  "scripts": {
    "lint": "tsc --noEmit --pretty"
  },
  "version": "0.2.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 multi-tenant-search/node/index.ts from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ClientsConfig, ServiceContext, RecorderState } from '@vtex/api'
import { LRUCache, method, Service } from '@vtex/api'

import { Clients } from './clients'
import { status } from './middlewares/status'
import { validate } from './middlewares/validate'

const TIMEOUT_MS = 800

// Create a LRU memory cache for the Status client.
// The @vtex/api HttpClient respects Cache-Control headers and uses the provided cache.
const memoryCache = new LRUCache<string, any>({ max: 5000 })

metrics.trackCache('status', memoryCache)

// This is the configuration for clients available in `ctx.clients`.
const clients: ClientsConfig<Clients> = {
  // We pass our custom implementation of the clients bag, containing the Status client.
  implementation: Clients,
  options: {
    // All IO Clients will be initialized with these options, unless otherwise specified.
    default: {
      retries: 2,
      timeout: TIMEOUT_MS,
    },
    // This key will be merged with the default options and add this cache to our Status client.
    status: {
      memoryCache,
    },
  },
}

declare global {
  // We declare a global Context type just to avoid re-writing ServiceContext<Clients, State> in every handler and resolver
  type Context = ServiceContext<Clients, State>

  // The shape of our State object found in `ctx.state`. This is used as state bag to communicate between middlewares.
  interface State extends RecorderState {
    code: number
  }
}

// Export a service that defines route handlers and client options.
export default new Service({
  clients,
  routes: {
    // `status` is the route ID from service.json. It maps to an array of middlewares (or a single handler).
    status: method({
      GET: [validate, 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 multi-tenant-search/node/clients/status.ts from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

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

export default class Status extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super('http://httpstat.us', context, options)
  }

  public async getStatus(status: number): Promise<string> {
    return this.http.get(status.toString(), {
      metric: 'status-get',
    })
  }

  public async getStatusWithHeaders(
    status: number
  ): Promise<IOResponse<string>> {
    return this.http.getRaw(status.toString(), {
      metric: 'status-get-raw',
    })
  }
}

```


[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 multi-tenant-search/node/clients/index.ts from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

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

import Status from './status'

// Extend the default IOClients implementation with our own custom clients.
export class Clients extends IOClients {
  public get status() {
    return this.getOrSet('status', 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 multi-tenant-search/node/middlewares/status.ts from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

```typescript
export async function status(ctx: Context, next: () => Promise<any>) {
  const {
    state: { code },
    clients: { status: statusClient },
  } = ctx

  console.info('Received code:', code)

  const statusResponse = await statusClient.getStatus(code)

  console.info('Status response:', statusResponse)

  const {
    headers,
    data,
    status: responseStatus,
  } = await statusClient.getStatusWithHeaders(code)

  console.info('Status headers', headers)
  console.info('Status data:', data)

  ctx.status = responseStatus
  ctx.body = data
  ctx.set('Cache-Control', headers['cache-control'])

  await next()
}

```


[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 multi-tenant-search/node/middlewares/validate.ts from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

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

export async function validate(ctx: Context, next: () => Promise<any>) {
  const {
    vtex: {
      route: { params },
    },
  } = ctx

  console.info('Received params:', params)

  const { code } = params

  if (!code) {
    throw new UserInputError('Code is required') // Wrapper for a Bad Request (400) HTTP Error. Check others in https://github.com/vtex/node-vtex-api/blob/fd6139349de4e68825b1074f1959dd8d0c8f4d5b/src/errors/index.ts
  }

  const codeNumber = parseInt(code as string, 10)

  ctx.state.code = codeNumber

  await next()
}

```


[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 multi-tenant-search/node/__tests__/simple.test.ts from the multi-tenant-search VTEX app.

[Assistant]
Here's the implementation:

```typescript
// You can import your files here for testing them
//
// More info: https://github.com/sapegin/jest-cheat-sheet

describe('simpleTest', () => {
  it('one test case', async () => {
    expect(0.2 + 0.1).not.toBe(0.3)
  })
})

```


[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 dartel-external-prices-node/docs/README.md from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```markdown
# B2B Seller Price

A reference IO app to allow B2B sellers to define prices based on the user email, by using the external price source through the Pricing Hub service.

## Implementation

This app is ready to use. You can install it on the `master` workspace of the seller account.

If you want to customize the app to use other price parameters, follow the instructions below.

1. Fork this app.

2. In the `manifest.json` file:
    * Change the `vendor` field to the name of the account you are using.
    * Change the `name` field to one of your choosing.
    * Add your service host (e.g. `myhost.com`) in an `outbound-access` policy.

3. In the `node/env.ts` file, add your service endpoint as follows:

    ```
    const ENV = {
      SERVICE_ENDPOINT: 'http://myservice.com',
    }

    export default ENV
    ```

4. Change the ` node/clients/externalPrice.ts` file to parse data received by the external pricing app and return it in a way that Pricing Hub can understand. See more details on the specification of this format in the [Pricing Hub documentation](https://developers.vtex.com/vtex-rest-api/docs/pricing-hub).

> ⛔ Do not change the `"routes"` in `node/service.json` nor the files in `node/typings/`, since they were created to reflect Pricing Hub behavior.

```


[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 dartel-external-prices-node/node/service.json from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 512,
  "ttl": 10,
  "timeout": 2,
  "minReplicas": 2,
  "maxReplicas": 120,
  "workers": 1,
  "cpu": {
    "type": "shared",
    "value": 20
  },
  "routes": {
    "price": {
      "path": "/_v/external-prices/price",
      "public": false,
      "access": "authorized",
      "policies": [
        {
          "effect": "allow",
          "actions": ["post"],
          "principals": ["vrn:vtex.vtex-id:*:*:*:user/vtexappkey-appvtex"]
        }
      ]
    },
    "keep-alive": {
      "path": "/_v/external-prices/keep-alive",
      "public": true,
      "policies": [
        {
          "effect": "allow",
          "actions": ["get"]
        }
      ]
    }
  }
}

```


[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 dartel-external-prices-node/node/package.json from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "co-body": "^6.0.0",
    "ramda": "^0.25.0"
  },
  "devDependencies": {
    "@types/co-body": "^0.0.3",
    "@types/jest": "^24.0.18",
    "@types/node": "^12.0.0",
    "@types/node-fetch": "^2.5.8",
    "@types/ramda": "types/npm-ramda#dist",
    "@vtex/api": "6.45.12",
    "@vtex/test-tools": "^1.0.0",
    "@vtex/tsconfig": "^0.5.6",
    "typescript": "3.9.7",
    "vtex.external-prices-node-unilever": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.external-prices-node-unilever@0.7.0/public/_types/react",
    "vtex.splunk-monitoring": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.splunk-monitoring@1.2.0/public/@types/vtex.splunk-monitoring"
  },
  "scripts": {
    "lint": "tsc --noEmit --pretty"
  },
  "version": "0.7.6"
}

```


[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 dartel-external-prices-node/node/index.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ClientsConfig } from '@vtex/api'
import { LRUCache, method, Service } from '@vtex/api'

import { Clients } from './clients'
import { validate } from './handlers/validate'
import { fetchPrice } from './handlers/fetchPrice'
import { formatResponse } from './handlers/formatResponse'

const TIMEOUT_MS = 800
const memoryCache = new LRUCache<string, never>({ max: 5000 })

const clients: ClientsConfig<Clients> = {
  implementation: Clients,
  options: {
    default: {
      retries: 2,
      timeout: TIMEOUT_MS,
    },
    status: {
      memoryCache,
    },
  },
}

async function keepAlive(ctx: Context) {
  ctx.set('Cache-Control', 'no-cache')
  ctx.status = 200
}

export default new Service({
  clients,
  routes: {
    price: method({
      POST: [validate, fetchPrice, formatResponse],
    }),
    'keep-alive': method({
      GET: keepAlive,
    }),
  },
})

```


[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 dartel-external-prices-node/node/env.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
// App Settings
const ENV = {
  SERVICE_ENDPOINT: 'YOUR_SERVICE_ENDPOINT',
}

export default ENV

```


[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 dartel-external-prices-node/node/clients/externalPrice.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

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

import type { InputItem } from '../typings/externalPrice'
import ENV from '../env'

export interface ExternalPriceClient {
  getPrice: (item: InputItem) => Promise<number | undefined>
}

export default class ExternalPrice
  extends ExternalClient
  implements ExternalPriceClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(ENV.SERVICE_ENDPOINT, context, options)
  }

  public async getPrice(item: InputItem): Promise<number | undefined> {
    try {
      return await this.http.get(item.skuId, {
        metric: 'get-price',
      })
    } catch (e) {
      if (e.response.status === 404) {
        return undefined
      }

      if (e.response.status === 429) {
        throw new TooManyRequestsError()
      }

      throw e
    }
  }
}

```


[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 dartel-external-prices-node/node/clients/profileSystemClient.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { InstanceOptions, IOContext, RequestConfig } from '@vtex/api'
import { JanusClient } from '@vtex/api'
import type { AxiosError } from 'axios'

import { statusToError } from '../utils/statusCodeUtils'
import type { CurrentProfile, Profile } from '../typings/profileSystem'

const FIVE_SECONDS_MS = 5 * 1000

export class ProfileSystemClient extends JanusClient {
  private baseUrl = '/api/profile-system/pvt/profiles'

  constructor(context: IOContext, options?: InstanceOptions) {
    super(context, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdClientAutCookie: context.authToken,
      },
      timeout: FIVE_SECONDS_MS,
    })
  }

  public getProfileInfo = (user: CurrentProfile, customFields?: string) =>
    this.get<Profile>(
      `${this.baseUrl}/${this.getUserIdentification(user)}/personalData`,
      {
        metric: 'profile-system-getProfileInfo',
        params: {
          extraFields: customFields,
        },
      }
    )

  protected get = <T>(url: string, config?: RequestConfig) =>
    this.http.get<T>(url, config).catch<AxiosError>(statusToError)

  private getUserIdentification = (user: CurrentProfile) =>
    user.userId ?? encodeURIComponent(user.email)
}

```


[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 dartel-external-prices-node/node/clients/externalPriceMock.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

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

import type { ExternalPriceClient } from './externalPrice'
import type { InputItem } from '../typings/externalPrice'

export default class ExternalPrice
  extends IOClient
  implements ExternalPriceClient {
  public async getPrice(item: InputItem): Promise<number | undefined> {
    return Number(item.skuId) * 10
  }
}

```


[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 dartel-external-prices-node/node/clients/index.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

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

import ExternalPrice from './externalPriceMock'
import PricingClient from './pricingClient'
import { ProfileSystemClient } from './profileSystemClient'

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

  public get pricing() {
    return this.getOrSet('pricing', PricingClient)
  }

  public get profileSystem() {
    return this.getOrSet('profileSystem', ProfileSystemClient)
  }
}

```


[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 dartel-external-prices-node/node/clients/pricingClient.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

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

import type { Quote } from '../typings/externalPrice'

export default class PricingClient extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(`http://${context.account}.myvtex.com/api/pricing`, context, {
      ...options,
      headers: {
        ...options?.headers,
        Accept: 'application/vnd.vtex.pricing.v3+json',
        'Cache-Control': 'no-cache',
        'Content-Type': 'application/json',
        'X-Vtex-Use-Https': 'true',
        VtexIdclientAutcookie: context.authToken ?? '',
      },
    })
  }

  public async getPrice(skuId: string | number, priceTable: string) {
    try {
      return await this.http.get<Quote>(
        `/prices/${skuId}/computed/${priceTable}`
      )
    } catch (e) {
      if (e.response.status === 404) {
        return undefined
      }

      if (e.response.status === 429) {
        throw new TooManyRequestsError()
      }

      throw e
    }
  }
}

export interface Context {
  categories: Record<string, never>
  brands: Record<string, never>
  markupRange: null
  dateRange: null
}

```


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

[User] Show me the implementation of dartel-external-prices-node/node/typings/profileSystem.d.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Address {
  id?: string
  userId?: string
  receiverName?: string
  complement?: string
  neighborhood?: string
  country?: string
  state?: string
  number?: string
  street?: string
  postalCode?: string
  city?: string
  reference?: string
  addressName?: string
  addressType?: string
  geoCoordinates?: string
}

export interface Profile {
  firstName?: string
  lastName?: string
  profilePicture?: string
  email: string
  document?: string
  userId?: string
  birthDate?: string
  gender?: string
  homePhone?: string
  businessPhone?: string
  isCorporate?: boolean
  isPJ?: string
  corporateName?: string
  corporateDocument?: string
  stateRegistration?: string
  approved?: boolean
  addresses?: Address[]
  tradeName?: string
  payments?: PaymentProfile[]
  customFields?: ProfileCustomField[]
  priceTables: string
}

interface CurrentProfile {
  email: string
  userId?: string
}

```


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

[User] Show me the implementation of dartel-external-prices-node/node/typings/externalPrice.d.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

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

export type Quote = {
  skuId: string
  listPrice: number
  costPrice: number
  sellingPrice: number
  priceValidUntil: string
  tradePolicyId?: string
}

export type InputItem = {
  skuId: string
  quantity: number
  index: number
}

export type ExternalPriceInput = {
  context: {
    email: string
  }
  item: InputItem
}

export type ExternalPriceResponse = {
  message: string
  item: {
    index: number
    skuId: string
    price: number
    costPrice: Maybe<number>
    listPrice: Maybe<number>
    priceValidUntil: string
    priceTables: string
    sellingPrice: Maybe<number>
    tradePolicyId: Maybe<string>
  }
}

```


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

[User] Show me the implementation of dartel-external-prices-node/node/typings/global.d.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { RecorderState, ServiceContext } from '@vtex/api'
import type { Clients } from '../clients'
import type { Quote, ExternalPriceInput } from './externalPrice'

declare global {
  type Context<TState extends State = State> = ServiceContext<Clients, TState>

  interface State extends RecorderState {
    quote?: Quote
    body: ExternalPriceInput
  }

  type Next = () => Promise<void>
}

```


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

[User] Show me the implementation of dartel-external-prices-node/node/utils/statusCodeUtils.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { AxiosError } from 'axios'
import { AuthenticationError, ForbiddenError, UserInputError } from '@vtex/api'

export function isNotSuccessCode(statusCode: number) {
  return statusCode < 200 || statusCode > 299
}

export const statusToError = (e: AxiosError) => {
  if (!e.response) throw e

  const { response } = e as AxiosError

  if (!response?.status) throw e

  const { status } = response

  if (status === 401) throw new AuthenticationError(e)

  if (status === 403) throw new ForbiddenError(e)

  if (status === 400) throw new UserInputError(e)

  throw e
}

```


[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 dartel-external-prices-node/node/__tests__/simple.test.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
// You can import your files here for testing them
//
// More info: https://github.com/sapegin/jest-cheat-sheet

describe('simpleTest', () => {
  it('one test case', async () => {
    expect(0.2 + 0.1).not.toBe(0.3)
  })
})

```


[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 dartel-external-prices-node/node/handlers/formatResponse.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ExternalPriceResponse, Quote } from '../typings/externalPrice'

export async function formatResponse(ctx: Context) {
  const { state, body } = ctx
  const quote = state.quote as Quote

  // Checkout service expect prices coming from Pricing Service to be multiplied by 100
  const response: ExternalPriceResponse = {
    message: 'Price quoted successfully.',
    item: {
      price: quote.sellingPrice * 100,
      priceTables: quote.tradePolicyId ?? '',
      index: body.item.index,
      skuId: quote.skuId,
      listPrice: quote.listPrice * 100,
      costPrice: quote.costPrice * 100,
      sellingPrice: quote.sellingPrice * 100,
      priceValidUntil: quote.priceValidUntil,
      tradePolicyId: quote.tradePolicyId,
    },
  }

  ctx.body = response
  ctx.status = 200
}

```


[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 dartel-external-prices-node/node/handlers/validate.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { json } from 'co-body'
import { UserInputError } from '@vtex/api'

export async function validate(ctx: Context, next: Next) {
  ctx.body = await json(ctx.req)

  const { item } = ctx.body

  if (!item?.skuId) {
    const error = new UserInputError('Item.SkuId is required')

    ctx.vtex.logger.error({
      message: 'ExternalPriceApp_Validate',
      error,
    })

    throw error
  }

  await next()
}

```


[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 dartel-external-prices-node/node/handlers/fetchPrice.ts from the dartel-external-prices-node VTEX app.

[Assistant]
Here's the implementation:

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

import type { Profile } from '../typings/profileSystem'

export async function fetchPrice(ctx: Context, next: Next) {
  const { clients, body } = ctx

  const { profileSystem, pricing } = clients

  let currentProfile: Profile | null = null

  if (body.context.email) {
    try {
      currentProfile = (await profileSystem.getProfileInfo(
        {
          email: body.context.email,
          userId: body.context.email,
        },
        'priceTables,isCorporate'
      )) as Profile
    } catch (e) {
      ctx.vtex.logger.warn({
        message: 'ExternalPriceApp_FetchPrice_NoProfile',
        e,
      })

      throw e
    }
  }

  const priceTableDefault = currentProfile?.isPJ === 'True' ? '2' : '1'

  const price = await pricing.getPrice(
    body.item.skuId,
    currentProfile?.priceTables ?? priceTableDefault
  )

  if (!price) {
    const error = new NotFoundError('Price not found')

    ctx.vtex.logger.error({
      message: 'ExternalPriceApp_FetchPrice_Noprice',
      error,
    })

    throw error
  }

  ctx.state.quote = {
    ...price,
    skuId: body.item.skuId,
  }

  await next()
}

```


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

[Assistant]
Here's the implementation:

```markdown
# Document Field

Document Field is a VTEX IO app that handles formatting and validation of documents, based on a pre-defined
document type. It includes a UI component that renders a input with a listbox, listing all available document
types we currently support.

<img width="314" alt="image" src="https://user-images.githubusercontent.com/10223856/77350379-34774e00-6d1b-11ea-8f0e-7290278ede84.png">

## Usage

To use this app, you first need to add it in your `manifest.json` file, like so

```json
{
  "dependencies": {
    "vtex.document-field": "0.x"
  }
}
```

> If you are developing in TypeScript, you may also want to run `vtex setup` after the step above

Then you can import the document field component and use it in your forms:

```jsx
import * as React from 'react'
import { DocumentField } from 'vtex.document-field'

const Form = () => {
  const [document, setDocument] = React.useState('')
  const [documentType, setDocumentType] = React.useState('cpf')

  const handleDocumentChange = data => {
    setDocument(data.document)
    setDocumentType(data.documentType)

    // you can also use `data.isValid` to show some
    // validation errors
  }

  return (
    <form>
      <DocumentField
        label="Document"
        document={document}
        documentType={documentType}
        onChange={handleDocumentChange}
      />
    </form>
  )
}
```

## Components

### DocumentField

Responsible for rendering the listbox with the text field and formatting and validating the document.

#### Props

The `DocumentField` component also accepts all props of [Styleguide's `Input`](https://styleguide.vtex.com/#/Components/Forms/Input),
except for the `value`, `onChange` and `prefix`, which are used internally by this component.

| Prop name | Type | Required |
| --- | --- | --- |
| [`document`](#documentfield-document) | `string` | `true` |
| [`documentType`](#documentfield-documenttype) | `string` | `true` |
| [`onChange`](#documentfield-onchange) | `func` | `false` |

##### DocumentField document

`document: string`

The document value.

##### DocumentField documentType

`documentType: string`

The document type. E.g.: `cpf`, `ssn`, `dni`.

##### DocumentField onChange

`onChange: (data: { document: string; documentType: string; isValid: boolean }) => void`

Callback to trigger the change of document value. Can be triggered by either typing on the text field
or by changing the document type within the listbox.

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "document-field",
  "version": "0.1.1",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/jest": "^25.1.4",
    "@types/node": "^13.9.3",
    "@types/react": "^16.9.25",
    "@vtex/styleguide": "^9.112.26",
    "@vtex/test-tools": "^3.1.0",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.96.1/public/@types/vtex.render-runtime",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.112.26/public/@types/vtex.styleguide"
  },
  "dependencies": {
    "msk": "^1.0.5",
    "react": "^16.13.1",
    "react-intl": "^4.2.2"
  }
}

```


[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 document-field/react/DocumentField.tsx from the document-field VTEX app.

[Assistant]
Here's the implementation:

```tsx
import msk from 'msk'
import * as React from 'react'
import { Input, InputProps } from 'vtex.styleguide'

import { CPF_MASK, validateCPF } from './utils/validation'

interface DocumentData {
  document: string
  documentType: string
  isValid: boolean
}

interface Props extends Omit<InputProps, 'onChange' | 'value' | 'prefix'> {
  documentType?: string
  document?: string
  onChange?: (data: DocumentData) => void
}

const DocumentField = React.forwardRef<HTMLInputElement, Props>(
  function DocumentField(
    { documentType = 'cpf', document = '', onChange = () => {}, ...props },
    ref
  ) {
    const [focused, setFocused] = React.useState(false)

    const handleDocumentChange: React.ChangeEventHandler<HTMLInputElement> = evt => {
      onChange({
        document: evt.target.value,
        documentType,
        isValid: true,
      })
    }

    const onChangeRef = React.useRef(onChange)

    React.useEffect(() => {
      onChangeRef.current = onChange
    }, [onChange])

    React.useEffect(() => {
      if (focused || documentType !== 'cpf') {
        return
      }

      const value = msk(document, CPF_MASK)

      onChangeRef.current({
        document: value,
        isValid: validateCPF(value),
        documentType,
      })
    }, [focused, documentType, document])

    const handleBlur: React.FocusEventHandler<HTMLInputElement> = evt => {
      setFocused(false)
      props.onBlur?.(evt)
    }

    const handleFocus: React.FocusEventHandler<HTMLInputElement> = evt => {
      setFocused(true)
      props.onFocus?.(evt)
    }

    return (
      <Input
        {...props}
        ref={ref}
        prefix={<span className="ttu">{documentType}</span>}
        value={document}
        onChange={handleDocumentChange}
        onBlur={handleBlur}
        onFocus={handleFocus}
      />
    )
  }
)

export default DocumentField

```


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

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable import/order */

import * as Styleguide from 'vtex.styleguide'

declare module 'vtex.styleguide' {
  import * as React from 'react'

  export type InputProps = {
    label?: string | React.ReactElement
    error?: boolean
    errorMessage?: string
    helpText?: React.ReactNode
    suffix?: React.ReactNode
    prefix?: React.ReactNode
    isLoadingButton?: boolean
    value: string
    onChange: React.ChangeEventHandler<HTMLInputElement>
  } & React.InputHTMLAttributes<HTMLInputElement>

  export const Input: React.FC<InputProps>
}

```


[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 document-field/react/utils/validation.ts from the document-field VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const CPF_LENGTH = 11
export const CPF_MASK = '999.999.999-99'

const unmaskCPF = (value: string) => value.replace(/\D/g, '')

export const validateCPF = (value: string) => {
  const unmaskedValue = unmaskCPF(value)

  if (unmaskedValue.length !== CPF_LENGTH) {
    return false
  }

  if (unmaskedValue.split('').every(digit => digit === unmaskedValue[0])) {
    return false
  }

  let [secondDigit, firstDigit, ...digits] = unmaskedValue
    .split('')
    .map(digit => parseInt(digit, 10))
    .reverse()

  digits = digits.reverse()

  const firstDigitSum = digits.reduce(
    (acc, digit, index) => acc + digit * (10 - index),
    0
  )
  const firstDigitRemainder = ((firstDigitSum * 10) % 11) % 10

  if (firstDigitRemainder !== firstDigit) return false

  const secondDigitSum = digits
    .concat([firstDigit])
    .reduce((acc, digit, index) => acc + digit * (11 - index), 0)
  const secondDigitRemainder = ((secondDigitSum * 10) % 11) % 10

  if (secondDigitRemainder !== secondDigit) return false

  return true
}

```


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

[User] Show me the implementation of document-field/react/__tests__/DocumentField.test.tsx from the document-field VTEX app.

[Assistant]
Here's the implementation:

```tsx
import * as React from 'react'
import { render, fireEvent, wait } from '@vtex/test-tools/react'

import DocumentField from '../DocumentField'

describe('DocumentField', () => {
  it('should correctly mask BRA documents', async () => {
    const Component = () => {
      const [document, setDocument] = React.useState('11111111111')
      return (
        <DocumentField
          label="Document"
          documentType="cpf"
          document={document}
          onChange={(data: { document: string }) => setDocument(data.document)}
        />
      )
    }

    const { getByLabelText } = render(<Component />)

    const input = getByLabelText(/document/i)

    await wait(() => void expect(input).toHaveValue('111.111.111-11'))
  })

  it('should only mask value on field blur', () => {
    const Component: React.FC = () => {
      const [document, setDocument] = React.useState('')
      const [documentType, setDocumentType] = React.useState('cpf')

      const handleDocumentChange = (data: {
        document: string
        documentType: string
      }) => {
        setDocument(data.document)
        setDocumentType(data.documentType)
      }

      return (
        <DocumentField
          label="Document"
          document={document}
          documentType={documentType}
          onChange={handleDocumentChange}
        />
      )
    }

    const { getByLabelText } = render(<Component />)

    const input = getByLabelText(/document/i)

    fireEvent.focus(input)

    fireEvent.change(input, { target: { value: '123456789' } })

    expect(input).toHaveValue('123456789')

    fireEvent.change(input, { target: { value: '12345678901' } })

    expect(input).toHaveValue('12345678901')

    fireEvent.blur(input)

    expect(input).toHaveValue('123.456.789-01')
  })

  it("should not format if document isn't cpf", () => {
    const AnotherDocComponent: React.FC = () => {
      const [document, setDocument] = React.useState('')
      const [documentType, setDocumentType] = React.useState('another-document')

      const handleDocumentChange = (data: {
        document: string
        documentType: string
      }) => {
        setDocument(data.document)
        setDocumentType(data.documentType)
      }

      return (
        <DocumentField
          label="Document"
          document={document}
          documentType={documentType}
          onChange={handleDocumentChange}
        />
      )
    }

    const { getByLabelText } = render(<AnotherDocComponent />)

    const input = getByLabelText(/document/i)

    fireEvent.focus(input)

    fireEvent.change(input, { target: { value: '123456789' } })

    fireEvent.blur(input)

    expect(input).toHaveValue('123456789')
  })

  it('should allow input of any special characters', () => {
    const Component: React.FC = () => {
      const [document, setDocument] = React.useState('')
      const [documentType, setDocumentType] = React.useState('')

      const handleDocumentChange = (data: {
        document: string
        documentType: string
      }) => {
        setDocument(data.document)
        setDocumentType(data.documentType)
      }

      return (
        <DocumentField
          label="Document"
          document={document}
          documentType={documentType}
          onChange={handleDocumentChange}
        />
      )
    }

    const { getByLabelText } = render(<Component />)

    const input = getByLabelText(/document/i)

    fireEvent.change(input, { target: { value: 'abc123.,[]&*()' } })

    expect(input).toHaveValue('abc123.,[]&*()')
  })

  it('should be able to mask a partially masked BRA document', () => {
    const ComponentWithPartialDoc = () => {
      const [doc, setDoc] = React.useState('')
      return (
        <DocumentField
          label="Document"
          documentType="cpf"
          document={doc}
          onChange={(data: { document: string }) => setDoc(data.document)}
        />
      )
    }

    const { getByLabelText } = render(<ComponentWithPartialDoc />)

    const input = getByLabelText(/document/i)

    fireEvent.focus(input)

    fireEvent.change(input, { target: { value: '123.45678901' } })

    fireEvent.blur(input)

    expect(input).toHaveValue('123.456.789-01')
  })
})

```