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

[Assistant]
Here's the implementation:

```markdown
📢 Use this project, [contribute](https://github.com/vtex-apps/condition-layout) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).
>⚠
>
> ***Condition Layout app v1 has been deprecated in favor of Condition Layout app v2**. Although support for the former version is still granted, we strongly recommend you to access the [Migration Guide](https://github.com/vtex-apps/condition-layout/tree/master/docs/MIGRATION-GUIDE.md) and update your store theme with the app's newest version in order to keep up with the components' evolution. If you’re still using the former version, you can find its documentation [here](https://github.com/vtex-apps/condition-layout/tree/master/docs/v1-DOC.md).

# Condition Layout

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

The Condition Layout app renders a component in your store when predefined conditions are met.

![Screen-Recording-certo](https://cdn.jsdelivr.net/gh/vtexdocs/dev-portal-content@main/images/vtex-condition-layout-0.gif)

## Configuration

### Step 1 - Adding the Condition Layout app to your theme dependencies

In the `manifest.json` file of your theme, add the Condition Layout app as a dependency:

```diff
  "dependencies": {
+   "vtex.condition-layout": "2.x"
  }
```

You can now use all blocks exported by the `condition-layout` app. See the full list below:

| Block name                       | Description                                                                                |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `condition-layout.product`       | Defines the condition logic in the product context and the children blocks that will be rendered when the predefined conditions are met.                     |
| `condition-layout.binding`       | Defines the condition logic in the current binding and the children blocks that will be rendered when the predefined conditions are met.                     |
| `condition-layout.category`      | Defines the condition logic on the current category or department page and the children blocks that will be rendered when the predefined conditions are met. |
| `condition-layout.telemarketing` | Defines the condition logic in the user role (telemarketing) and the children blocks that will be rendered when the predefined conditions are met.           |

### Step 2 - Adding the `condition-layout.product` block to your theme templates

In the product theme template, add the `condition-layout.product` block as a child. For example:

```
{
  "store.product": {
    "children": ["condition-layout.product"]
  },
```

Or the `condition-layout.binding` block. For example:

```json
{
  "store.product": {
    "children": ["condition-layout.binding"]
  }
}
```

Or the `condition-layout.category` block. For example:

```json
{
  "store.search#my-category-page": {
    "children": ["condition-layout.category"]
  }
}
```

>⚠ Never use `condition-layout` directly. Always use it with a context variant, such as `condition-layout.product`.

### Step 3 - Defining the desired conditions

Now it is time to configure the `condition-layout.product` block!

**Use the block props to define your layout condition**. You can also declare blocks of your choice as children of `condition-layout.product`. These children blocks will be rendered if the condition is met.

For example:

```diff
{
  "store.product": {
    "children": ["condition-layout.product#cond1"]
  },
  "condition-layout.product#cond1": {
+   "props": {
+     "conditions": [
+       {
+         "subject": "productId",
+         "arguments": {
+           "id": "12"
+         }
+       }
+     ]
+     "Then": "flex-layout.row#custom-pdp-layout-12",
+     "Else": "flex-layout.row#default"
+   }
+ }
```

Or for `condition-layout.binding`:

```diff
{
  "store.product": {
    "children": ["condition-layout.binding#cond42"]
  },
  "condition-layout.binding#cond42": {
+   "props": {
+     "conditions": [
+       {
+         "subject": "bindingId",
+         "arguments": {
+           "id": "13fb71d0-binding-code-here-87h9c28h9013"
+         }
+       }
+     ]
+     "Then": "flex-layout.row#just-for-this-binding",
+     "Else": "flex-layout.row#for-other-bindings"
+   }
+ }
```

Or for `condition-layout.category`:

 ```diff
 {
   "store.product": {
     "children": ["condition-layout.category#cond42"]
   },
   "condition-layout.category#cond42": {
 +   "props": {
 +     "conditions": [
 +       {
 +         "subject": "department",
 +         "arguments": {
 +           "ids": ["1", "42"]
 +         }
 +       }
 +       {
 +         "subject": "category",
 +         "arguments": {
 +           "ids": ["301", "304"]
 +         }
 +       }
 +     ]
 +     "matchType": "any",
 +     "Then": "flex-layout.row#just-for-this-category-or-department",
 +     "Else": "flex-layout.row#for-other-category-or-department"
 +   }
 + }
 ```

Or for `condition-layout.telemarketing`:

```diff
{
  "store.product": {
    "children": ["condition-layout.telemarketing#show-block"]
  },
  "condition-layout.telemarketing#show-block": {
+   "props": {
+     "conditions": [
+       {
+         "subject": "impersonable",
+         "arguments": {
+           "value": true
+         }
+       }
+     ]
+     "Then": "flex-layout.row#just-for-telemarketers",
+     "Else": "flex-layout.row#for-other-user-roles"
+   }
+ }
```

>ℹ In the example above, whenever users interact with a product whose ID is equal to 12, the `flex-layout.row#custom-pdp-layout-12` block is rendered. If users interact with a product whose ID is not equal to 12, the rendered block is `flex-layout.row#default`.

| Prop name | Type | Description | Default value |
| - | - | - | - |
| `conditions` | `object` | List of desired conditions. | `undefined`   |
| `matchType`  | `enum` | Layout rendering criteria. Possible values are: `all` (all conditions must be met to render the layout), `any` (at least one of the conditions must be met to render the layout), or `none` (no conditions must be met to render the layout). | `all` |
| `Then` | `block`  | Name of the block to be rendered if the conditions are met. If no value is defined, the blocks declared as children of `condition-layout.product` will be rendered instead. | `undefined`   |
| `Else` | `block`  | Name of the block to be rendered if the conditions are not met. | `undefined`   |

- **`conditions` object:**

| Prop name   | Type | Description | Default value |
| - | - | - | - |
| `subject` | `string` | Defines, based on the product context where the block is declared, which information is needed from the UI to validate the value chosen in the `object` prop. See below the possible values for this prop. | `undefined` |
| `arguments` | `object`  | Defines the condition parameters. Note that the value of this prop varies depending on the value set for the `subject` prop. See below the table with the possible values for the `subject` prop and their expected arguments. | `undefined` |
| `toBe` | `boolean` | Determines whether the data fetched in the `subject` prop must meet the predefined conditions to render the new layout (`true`) or not (`false`). | `true` |

Possible values for `subject` prop of the `condition-layout.product` block:

| Subject | Description | Arguments |
| - | - | - |
| `productId` | Product IDs currently displayed on the UI. | `{ id: string }` |
| `categoryId` | Category IDs currently displayed on the UI. | `{ id: string }` |
| `brandId` | Brand IDs currently displayed on the UI. | `{ id: string }` |
| `selectedItemId` | ID of the item currently selected by the user. | `{ id: string }` |
| `productClusters` | List of product clusters currently displayed on the UI. | `{ id: string }` |
| `categoryTree` | List of categories currently displayed on the UI. **Note:** Only available on the Product Detail Page. | `{ id: string }` |
| `specificationProperties`  | List of product specifications currently displayed on the UI. | `{ name: string, value: string }`. Note: `value` is an optional prop. If omitted, only the specification name (`name`) will be checked. |
| `areAllVariationsSelected` | Determines whether all product variations currently available on the UI were selected by the user (`true`) or not (`false`). | No arguments are expected. |
| `isProductAvailable` | Determines whether the product is available (`true`) or not (`false`).                                                       | No arguments are expected. |
| `hasMoreSellersThan` | Determines whether the number of sellers for a product is greater than the argument passed. | `{ quantity: number }` |
| `hasBestPrice` | Whether the product is being given a discount on its list price.  | `{ value: boolean }` or no arguments. |
| `sellerId` | Whether any of the sellers of the product are included in the list of IDs passed.  | `{ ids: string[] }` |

Possible values for the `subject` prop of the `condition-layout.binding` block:

| Subject     | Description                      | Arguments        |
| ----------- | -------------------------------- | ---------------- |
| `bindingId` | ID of the desired store binding. | `{ id: string }` |

Possible values for the `subject` prop of the `condition-layout.category` block:

| Subject      | Description                                   | Arguments           |
| ------------ | --------------------------------------------- | ------------------- |
| `category`   | Category IDs currently displayed on the UI.   | `{ ids: string[] }` |
| `department` | Department IDs currently displayed on the UI. | `{ ids: string[] }` |

Possible values for the `subject` prop of the `condition-layout.telemarketing` block:

| Subject        | Description                         | Arguments            |
| -------------- | ----------------------------------- | -------------------- |
| `impersonable` | Value of the impersonation setting. | `{ value: boolean }` |

## App behavior

The `condition-layout.product` block mainly uses the `matchType` and `conditions` props to respectively set the criteria and the conditions that blocks must meet to be rendered.

The `conditions` prop does not rely on any automatic grammar to define the desired conditions. Instead, it relies on its two props, namely `subject` and `arguments`, which together define which condition must be met by using an underlying data validation method (with specific arguments) based on the UI behavior.

Lastly, the `matchType` prop decides the necessary number of valid conditions for the layout rendering.

## Customization

The Condition Layout merely establishes a logic to render other blocks. Therefore, the app does not have its own CSS handles for customization.

Instead, you should use the handles of the child blocks.

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

## Contributors ✨

Thanks goes out to these wonderful people:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tr>
    <td align="center"><a href="https://github.com/LucasCastroAcctGlobal"><img src="https://avatars0.githubusercontent.com/u/55210107?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LucasCastroAcctGlobal</b></sub></a><br /><a href="https://github.com/vtex-apps/condition-layout/commits?author=LucasCastroAcctGlobal" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/vini-lima-acct"><img src="https://avatars.githubusercontent.com/u/78028684?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vini-lima-acct</b></sub></a><br /><a href="https://github.com/vtex-apps/condition-layout/commits?author=vini-lima-acct" title="Code">💻</a></td>
  </tr>
</table>

<!-- markdownlint-restore -->
<!-- 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 condition-layout/react/ConditionLayoutTelemarketing.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo } from 'react'
import type { ComponentType } from 'react'
import { useFullSession } from 'vtex.session-client'

import ConditionLayout from './ConditionLayout'
import type { MatchType, Condition, Handlers, NoUndefinedField } from './types'

type Props = {
  conditions: Array<Condition<ContextValues, HandlerArguments>>
  matchType?: MatchType
  Else?: ComponentType
  Then?: ComponentType
}

type ContextValues = {
  impersonable: boolean
}

type HandlerArguments = {
  impersonable: { value: boolean }
}

const HANDLERS: Handlers<ContextValues, HandlerArguments> = {
  impersonable({ values, args }) {
    return values.impersonable === args?.value
  },
}

const ConditionLayoutTelemarketing: StorefrontFunctionComponent<Props> = ({
  Else,
  Then,
  matchType,
  conditions,
  children,
}) => {
  const { data } = useFullSession()

  const impersonable = Boolean(
    data?.session?.namespaces?.impersonate?.canImpersonate?.value
  )

  const values = useMemo<ContextValues>(() => {
    const bag = {
      impersonable,
    }

    // We use `NoUndefinedField` to remove optionality + undefined values from the type
    return bag as NoUndefinedField<typeof bag>
  }, [impersonable])

  return (
    <ConditionLayout
      Else={Else}
      Then={Then}
      matchType={matchType}
      conditions={conditions}
      values={values}
      handlers={HANDLERS}
    >
      {children}
    </ConditionLayout>
  )
}

export default ConditionLayoutTelemarketing

```


[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 condition-layout/react/ConditionLayout.test.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react'
import { render } from '@vtex/test-tools/react'

import ConditionLayout from './ConditionLayout'
import type { Condition } from './types'

test('Renders a condition that resolves to true', () => {
  const { queryByText } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '37' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
    >
      Hooray!
    </ConditionLayout>
  )

  expect(queryByText(/Hooray!/)).toBeInTheDocument()
})

test('Renders a condition that resolves to false with toBe: false', () => {
  const { queryByText } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '100' },
          toBe: false,
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
    >
      Hooray!
    </ConditionLayout>
  )

  expect(queryByText(/Hooray!/)).toBeInTheDocument()
})

test('Renders the Then slot if a condition resolves to true', () => {
  const ThenSlot = () => <>Hooray!</>

  const { queryByText } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '37' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
      Then={ThenSlot}
    />
  )

  expect(queryByText(/Hooray!/)).toBeInTheDocument()
})

test('Prevents children from being rendered if Then is set', () => {
  const ThenSlot = () => <>Hooray!</>

  const { queryByText } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '37' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
      Then={ThenSlot}
    >
      Potato!!
    </ConditionLayout>
  )

  expect(queryByText(/Hooray!/)).toBeInTheDocument()
  expect(queryByText(/Potato/)).not.toBeInTheDocument()
})

test('Renders nothing if no condition matches', () => {
  const { container } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '39' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
    >
      Hooray!
    </ConditionLayout>
  )

  expect(container).toBeEmptyDOMElement()
})

test('Renders the else Slot if no condition matches', () => {
  const ElseSlot = () => <>Oh no!</>

  const { queryByText } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '39' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
      Else={ElseSlot}
    >
      Hooray!
    </ConditionLayout>
  )

  expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
  expect(queryByText(/Oh no!/)).toBeInTheDocument()
})

test("Doesn't render the else block if some condition match", () => {
  const ElseSlot = () => <>Oh no!</>

  const { queryByText } = render(
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '37' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === '37',
      }}
      values={{}}
      Else={ElseSlot}
    >
      Hooray!
    </ConditionLayout>
  )

  expect(queryByText(/Hooray!/)).toBeInTheDocument()
  expect(queryByText(/Oh no!/)).not.toBeInTheDocument()
})

test('Switches from rendering a matched condition to the else component', () => {
  const ElseSlot = () => <>Oh no!</>

  let id = '37'

  const layout = (
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '37' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === id,
      }}
      values={{}}
      Else={ElseSlot}
    >
      Hooray!
    </ConditionLayout>
  )

  const { queryByText, rerender } = render(layout)

  expect(queryByText(/Hooray!/)).toBeInTheDocument()
  expect(queryByText(/Oh no!/)).not.toBeInTheDocument()

  // wrong id
  id = '38'

  rerender(layout)

  expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
  expect(queryByText(/Oh no!/)).toBeInTheDocument()
})

test('Switches from rendering the else component to a matched condition component', () => {
  const ElseSlot = () => <>Oh no!</>

  // wrong id
  let id = '38'

  const layout = (
    <ConditionLayout
      conditions={[
        {
          subject: 'selectedItemId',
          arguments: { id: '37' },
        },
      ]}
      handlers={{
        selectedItemId: ({ args }: any) => args.id === id,
      }}
      values={{}}
      Else={ElseSlot}
    >
      Hooray!
    </ConditionLayout>
  )

  const { queryByText, rerender } = render(layout)

  expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
  expect(queryByText(/Oh no!/)).toBeInTheDocument()

  // correct id
  id = '37'

  rerender(layout)
  expect(queryByText(/Hooray!/)).toBeInTheDocument()
  expect(queryByText(/Oh no!/)).not.toBeInTheDocument()
})

describe('multiple conditions', () => {
  describe('matchType: all', () => {
    it('returns true for a composed condition', () => {
      const handlers = {
        potatoId({ values, args }: unknown) {
          return values.potatoId === args.potatoId
        },
        kiwiId({ values, args }: unknown) {
          return values.kiwiId === args.kiwiId
        },
      }

      const conditions: Condition[] = [
        {
          subject: 'potatoId',
          arguments: {
            potatoId: 'correct',
          },
        },
        {
          subject: 'kiwiId',
          arguments: {
            kiwiId: 'correct',
          },
        },
      ]

      const values = {
        potatoId: 'correct',
        kiwiId: 'correct',
      }

      const { queryByText } = render(
        <ConditionLayout
          matchType="all"
          conditions={conditions}
          handlers={handlers}
          values={values}
        >
          Hooray!
        </ConditionLayout>
      )

      expect(queryByText(/Hooray!/)).toBeInTheDocument()
    })

    it('returns false for a composed condition', () => {
      const handlers = {
        potatoId({ values, args }: unknown) {
          return values.potatoId === args.potatoId
        },
        kiwiId({ values, args }: unknown) {
          return values.kiwiId === args.kiwiId
        },
      }

      const conditions: Condition[] = [
        {
          subject: 'potatoId',
          arguments: {
            potatoId: 'correct',
          },
        },
        {
          subject: 'kiwiId',
          arguments: {
            kiwiId: 'wrong',
          },
        },
      ]

      const values = {
        potatoId: 'correct',
        kiwiId: 'correct',
      }

      const { queryByText } = render(
        <ConditionLayout
          matchType="all"
          conditions={conditions}
          handlers={handlers}
          values={values}
        >
          Hooray!
        </ConditionLayout>
      )

      expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
    })
  })

  describe('matchType: any', () => {
    // simple 'any' conditions are the same as 'all' conditions

    it('returns true for a composed condition', () => {
      const handlers = {
        potatoId({ values, args }: unknown) {
          return values.potatoId === args.potatoId
        },
        kiwiId({ values, args }: unknown) {
          return values.kiwiId === args.kiwiId
        },
      }

      const conditions: Condition[] = [
        {
          subject: 'potatoId',
          arguments: {
            potatoId: 'wrong',
          },
        },
        {
          subject: 'kiwiId',
          arguments: {
            kiwiId: 'correct',
          },
        },
      ]

      const values = {
        potatoId: 'correct',
        kiwiId: 'correct',
      }

      const { queryByText } = render(
        <ConditionLayout
          matchType="any"
          conditions={conditions}
          handlers={handlers}
          values={values}
        >
          Hooray!
        </ConditionLayout>
      )

      expect(queryByText(/Hooray!/)).toBeInTheDocument()
    })

    it('returns false for a composed condition', () => {
      const handlers = {
        potatoId({ values, args }: unknown) {
          return values.potatoId === args.potatoId
        },
        kiwiId({ values, args }: unknown) {
          return values.kiwiId === args.kiwiId
        },
      }

      const conditions: Condition[] = [
        {
          subject: 'potatoId',
          arguments: {
            potatoId: 'wrong',
          },
        },
        {
          subject: 'kiwiId',
          arguments: {
            kiwiId: 'wrong',
          },
        },
      ]

      const values = {
        potatoId: 'correct',
        kiwiId: 'correct',
      }

      const { queryByText } = render(
        <ConditionLayout
          matchType="any"
          conditions={conditions}
          handlers={handlers}
          values={values}
        >
          Hooray!
        </ConditionLayout>
      )

      expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
    })
  })

  describe('matchType: none', () => {
    it('returns true for a composed condition', () => {
      const handlers = {
        potatoId({ values, args }: unknown) {
          return values.potatoId === args.potatoId
        },
        kiwiId({ values, args }: unknown) {
          return values.kiwiId === args.kiwiId
        },
      }

      const conditions: Condition[] = [
        {
          subject: 'potatoId',
          arguments: {
            potatoId: 'wrong',
          },
        },
        {
          subject: 'kiwiId',
          arguments: {
            kiwiId: 'wrong',
          },
        },
      ]

      const values = {
        potatoId: 'correct',
        kiwiId: 'correct',
      }

      const { queryByText } = render(
        <ConditionLayout
          matchType="none"
          conditions={conditions}
          handlers={handlers}
          values={values}
        >
          Hooray!
        </ConditionLayout>
      )

      expect(queryByText(/Hooray!/)).toBeInTheDocument()
    })

    it('returns false for a composed condition', () => {
      const handlers = {
        potatoId({ values, args }: unknown) {
          return values.potatoId === args.potatoId
        },
        kiwiId({ values, args }: unknown) {
          return values.kiwiId === args.kiwiId
        },
      }

      const conditions: Condition[] = [
        {
          subject: 'potatoId',
          arguments: {
            potatoId: 'wrong',
          },
        },
        {
          subject: 'kiwiId',
          arguments: {
            kiwiId: 'correct',
          },
        },
      ]

      const values = {
        potatoId: 'correct',
        kiwiId: 'correct',
      }

      const { queryByText } = render(
        <ConditionLayout
          matchType="none"
          conditions={conditions}
          handlers={handlers}
          values={values}
        >
          Hooray!
        </ConditionLayout>
      )

      expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
    })
  })
})

```


[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 condition-layout/react/ConditionLayoutProduct.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo } from 'react'
import { useProduct } from 'vtex.product-context'
import type { Product, Item } from 'vtex.product-context/react/ProductTypes'

import ConditionLayout from './ConditionLayout'
import type { NoUndefinedField, MatchType, Condition, Handlers } from './types'

type Props = {
  conditions: Array<Condition<ContextValues, HandlerArguments>>
  matchType?: MatchType
  Else?: React.ComponentType
  Then?: React.ComponentType
}

type ContextValues = {
  productId: Product['productId']
  categoryId: Product['categoryId']
  brandId: Product['brandId']
  productClusters: Product['productClusters']
  categoryTree: Product['categoryTree']
  selectedItemId: Item['itemId']
  specificationProperties: Product['properties']
  areAllVariationsSelected: boolean
  sellers: Item['sellers']
}

type HandlerArguments = {
  productId: { id: string }
  categoryId: { id: string }
  brandId: { id: string }
  productClusters: { id: string }
  categoryTree: { id: string }
  selectedItemId: { id: string }
  specificationProperties: { name: string; value?: string }
  areAllVariationsSelected: undefined
  isProductAvailable: undefined
  hasMoreSellersThan: { quantity: number }
  hasBestPrice: { value: boolean } | undefined
  sellerId: { ids: string[] }
}

export const HANDLERS: Handlers<ContextValues, HandlerArguments> = {
  productId({ values, args }) {
    return String(values.productId) === String(args?.id)
  },
  categoryId({ values, args }) {
    return String(values.categoryId) === String(args?.id)
  },
  brandId({ values, args }) {
    return String(values.brandId) === String(args?.id)
  },
  selectedItemId({ values, args }) {
    return String(values.selectedItemId) === String(args?.id)
  },
  areAllVariationsSelected({ values }) {
    return values.areAllVariationsSelected
  },
  productClusters({ values, args }) {
    return Boolean(
      values.productClusters?.find(({ id }) => String(id) === String(args?.id))
    )
  },
  categoryTree({ values, args }) {
    return Boolean(
      values?.categoryTree?.find(({ id }) => String(id) === String(args?.id))
    )
  },
  specificationProperties({ values, args }) {
    const specification = values.specificationProperties?.find(
      ({ name }) => name === args?.name
    )

    if (specification == null) return false
    if (args?.value == null) return Boolean(specification)

    return specification.values.includes(String(args?.value))
  },
  isProductAvailable({ values }) {
    const { sellers } = values

    const isAvailable = sellers?.some(
      (seller) => seller.commertialOffer.AvailableQuantity > 0
    )

    return Boolean(isAvailable)
  },
  hasMoreSellersThan({ values, args }) {
    const { sellers } = values

    const productAvailable = sellers?.filter(
      (seller) => seller.commertialOffer.AvailableQuantity > 0
    )

    const isMoreThan = productAvailable?.length > args?.quantity

    return isMoreThan
  },
  hasBestPrice({ values, args }) {
    const {
      commertialOffer: { ListPrice, Price },
    } =
      values.sellers?.find(({ sellerDefault }) => sellerDefault) ??
      // Falls back to first seller, if no default is found.
      values.sellers[0]

    const expected = args?.value ?? true
    const hasDiscount = ListPrice !== Price

    return hasDiscount === expected
  },
  sellerId({ values, args }) {
    const { sellers } = values

    const availableSellers = sellers?.filter(
      (seller) => seller.commertialOffer.AvailableQuantity > 0
    )

    const matchSellers = availableSellers?.some((availableSeller) =>
      args?.ids?.includes(availableSeller.sellerId)
    )

    return matchSellers
  },
}

const ConditionLayoutProduct: StorefrontFunctionComponent<Props> = ({
  Else,
  Then,
  matchType,
  conditions,
  children,
}) => {
  const {
    product,
    selectedItem,
    skuSelector: { areAllVariationsSelected = false } = {},
  } = useProduct() ?? {}

  const {
    productId,
    categoryId,
    brandId,
    productClusters,
    categoryTree,
    properties: specificationProperties,
  } = product ?? {}

  const { itemId: selectedItemId, sellers } = selectedItem ?? {}

  // We use a useMemo to modify the condition layout "values"
  // only when some of the context props change.
  const values = useMemo<ContextValues>(() => {
    const bag = {
      productId,
      categoryId,
      brandId,
      productClusters,
      categoryTree,
      selectedItemId,
      specificationProperties,
      areAllVariationsSelected,
      sellers,
    }

    // We use `NoUndefinedField` to remove optionality + undefined values from the type
    return bag as NoUndefinedField<typeof bag>
  }, [
    brandId,
    categoryId,
    categoryTree,
    productClusters,
    productId,
    selectedItemId,
    specificationProperties,
    areAllVariationsSelected,
    sellers,
  ])

  // Sometimes it takes a while for useProduct() to return the correct results
  if (values.selectedItemId == null || values.productId == null) {
    return null
  }

  return (
    <ConditionLayout
      Else={Else}
      Then={Then}
      matchType={matchType}
      conditions={conditions}
      values={values}
      handlers={HANDLERS}
    >
      {children}
    </ConditionLayout>
  )
}

ConditionLayoutProduct.schema = {
  title: 'admin/editor.condition-layout.wrapper.product',
}

export default ConditionLayoutProduct

```


[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 condition-layout/react/ConditionLayoutCategory.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo } from 'react'
import type { ComponentType } from 'react'
import { useRuntime } from 'vtex.render-runtime'

import ConditionLayout from './ConditionLayout'
import type { NoUndefinedField, MatchType, Condition, Handlers } from './types'

interface Props {
  conditions: Array<Condition<ContextValues, HandlerArguments>>
  matchType?: MatchType
  Else?: ComponentType
  Then?: ComponentType
}

interface ContextValues {
  [key: string]: string
  id: string
  type: 'category' | 'department'
}

interface HandlerArguments {
  category: { ids: string[] }
  department: { ids: string[] }
}

const handlersMap: Handlers<ContextValues, HandlerArguments> = {
  category({ values, args }) {
    if (values.type !== 'category') {
      return false
    }

    return args.ids.includes(values.id)
  },
  department({ values, args }) {
    if (values.type !== 'department') {
      return false
    }

    return args.ids.includes(values.id)
  },
}

const ConditionLayoutCategory: StorefrontFunctionComponent<Props> = ({
  Else,
  Then,
  matchType,
  conditions,
  children,
}) => {
  const {
    route: {
      pageContext: { id, type },
    },
  } = useRuntime()

  const values = useMemo<ContextValues>(() => {
    const bag = {
      id,
      type,
    }

    // We use `NoUndefinedField` to remove optionality + undefined values from the type
    return bag as NoUndefinedField<typeof bag>
  }, [id, type])

  return (
    <ConditionLayout
      Else={Else}
      Then={Then}
      matchType={matchType}
      conditions={conditions}
      values={values}
      handlers={handlersMap}
    >
      {children}
    </ConditionLayout>
  )
}

export default ConditionLayoutCategory

```


[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 condition-layout/react/types.ts from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
export type NoUndefinedField<T> = {
  [P in keyof T]-?: Exclude<T[P], undefined>
}

export type MatchType = 'any' | 'all' | 'none'

type SameProps<T> = Record<keyof T, unknown>

export type Condition<Subjects = unknown, Args = unknown> = {
  toBe?: boolean
} & (Args extends SameProps<Subjects>
  ? {
      [K in keyof Subjects]: Args[K] extends undefined
        ? { subject: K }
        : { subject: K; arguments: Args[K] }
    }[keyof Subjects]
  : { subject: string; arguments?: unknown })

export type Handler<Values, Args> = (o: {
  values: Values
  args: Args
}) => boolean

export type Handlers<Values, Args> = {
  [K in keyof Args]: Handler<Values, Args[K]>
}

```


[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 condition-layout/react/ConditionLayoutProduct.test.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react'
import { render } from '@vtex/test-tools/react'
import { useProduct } from 'vtex.product-context'
import type { ProductContextState } from 'vtex.product-context/react/ProductContextProvider'

import ConditionLayoutProduct from './ConditionLayoutProduct'

const mockedUseProduct = useProduct as jest.Mock<ProductContextState>

function getMockedProduct({
  skuId = '37',
  productId = 'prod-id',
  categoryId = 'cat-id',
  brandId = 'brand-id',
  clusterId = 'cluster1',
  catTreeId = 'cat1',
  propName = 'prop1',
  propValue = 'value1',
  areAllVariationsSelected = false,
} = {}): ProductContextState {
  return ({
    product: {
      productId,
      categoryId,
      brandId,
      productClusters: [{ id: clusterId, name: 'cluster 1' }],
      categoryTree: [{ id: catTreeId, name: 'cat 1', href: '' }],
      properties: [{ name: propName, values: propValue }],
    },
    selectedItem: { itemId: skuId },
    skuSelector: { areAllVariationsSelected },
  } as any) as ProductContextState
}

test('renders nothing if no product context is available', () => {
  mockedUseProduct.mockImplementation(() => undefined as any)

  const { container } = render(
    <ConditionLayoutProduct
      conditions={[{ subject: 'selectedItemId', arguments: { id: '37' } }]}
    >
      Hooray!
    </ConditionLayoutProduct>
  )

  expect(container).toBeEmptyDOMElement()
})

describe('subject: selectedItemId', () => {
  it('Renders a condition that resolves to true', () => {
    mockedUseProduct.mockImplementation(() => getMockedProduct({ skuId: '37' }))

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'selectedItemId', arguments: { id: '37' } }]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })

  it('Renders the Then slot of a condition that resolves to true', () => {
    const thenSlot = () => <>Hooray!</>

    mockedUseProduct.mockImplementation(() => getMockedProduct({ skuId: '37' }))

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'selectedItemId', arguments: { id: '37' } }]}
        Then={thenSlot}
      />
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })

  it('Renders the Else slot of a condition that resolves to false', () => {
    mockedUseProduct.mockImplementation(() => getMockedProduct({ skuId: '37' }))

    const ElseComponent = () => <>Nope</>

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'selectedItemId', arguments: { id: '39' } }]}
        Else={ElseComponent}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
    expect(queryByText(/Nope/)).toBeInTheDocument()
  })
})

describe('subject: productId', () => {
  it('Renders a condition that resolves to true', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ productId: 'prod-2' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'productId', arguments: { id: 'prod-2' } }]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })
})

describe('subject: categoryId', () => {
  it('Renders a condition that resolves to true', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ categoryId: 'cat-2' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'categoryId', arguments: { id: 'cat-2' } }]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })
})

describe('subject: brandId', () => {
  it('Renders a condition that resolves to true', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ brandId: 'brand-2' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'brandId', arguments: { id: 'brand-2' } }]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })
})

describe('subject: productClusters', () => {
  it('Renders a condition that resolves to true', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ clusterId: 'cluster-1' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[
          { subject: 'productClusters', arguments: { id: 'cluster-1' } },
        ]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })
})

describe('subject: category tree', () => {
  it('Renders a condition that resolves to true', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ catTreeId: 'cat-1' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[{ subject: 'categoryTree', arguments: { id: 'cat-1' } }]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })
})

describe('subject: specification properties', () => {
  it('renders a true condition with just the name', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ propName: 'prop-1' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[
          { subject: 'specificationProperties', arguments: { name: 'prop-1' } },
        ]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })

  it("doesn't render when specification doesn't exist", () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ propName: 'prop-1' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[
          {
            subject: 'specificationProperties',
            arguments: { name: 'non-existing' },
          },
        ]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
  })

  it('renders a true condition with name and value', () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ propName: 'prop-2', propValue: 'potato' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[
          {
            subject: 'specificationProperties',
            arguments: { name: 'prop-2', value: 'potato' },
          },
        ]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })

  it("doens't render when value doesn't exist", () => {
    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ propName: 'prop-2', propValue: 'potato' })
    )

    const { queryByText } = render(
      <ConditionLayoutProduct
        conditions={[
          {
            subject: 'specificationProperties',
            arguments: { name: 'prop-2', value: 'ice-cream' },
          },
        ]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    expect(queryByText(/Hooray!/)).not.toBeInTheDocument()
  })
})

describe('subject: areAllVariationsSelected', () => {
  it('renders a true condition with name and value', () => {
    const ui = (
      <ConditionLayoutProduct
        conditions={[{ subject: 'areAllVariationsSelected' }]}
      >
        Hooray!
      </ConditionLayoutProduct>
    )

    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ areAllVariationsSelected: false })
    )

    const { queryByText, rerender } = render(ui)

    expect(queryByText(/Hooray!/)).not.toBeInTheDocument()

    mockedUseProduct.mockImplementation(() =>
      getMockedProduct({ areAllVariationsSelected: true })
    )

    rerender(ui)

    expect(queryByText(/Hooray!/)).toBeInTheDocument()
  })
})

```


[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 condition-layout/react/ConditionLayout.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

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

import { validateConditions } from './modules/conditions'
import type { MatchType, Condition } from './types'

type Props = {
  matchType?: MatchType
  conditions: Condition[]
  values: Record<string, unknown>
  handlers: Record<string, unknown>
  Else?: React.ComponentType
  Then?: React.ComponentType
}

const ConditionLayout: FC<Props> = ({
  Else,
  Then,
  conditions,
  children,
  values,
  handlers,
  matchType,
}) => {
  const result = validateConditions({ matchType, conditions, values, handlers })

  if (result) {
    if (Then) {
      return <Then />
    }

    return <>{children}</>
  }

  if (Else) {
    return <Else />
  }

  return null
}

export default ConditionLayout

```


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

[Assistant]
Here's the implementation:

```json
{
  "version": "2.8.2",
  "scripts": {
    "test": "vtex-test-tools test --collect-coverage",
    "lint": "tsc --noEmit && eslint --ext ts,tsx ."
  },
  "dependencies": {
    "@vtex/css-handles": "^1.1.3",
    "classnames": "^2.2.6",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-intl": "^5.8.3"
  },
  "devDependencies": {
    "@apollo/react-testing": "^4.0.0",
    "@types/classnames": "^2.2.10",
    "@types/jest": "^26.0.14",
    "@types/node": "^14.11.2",
    "@types/prop-types": "^15.7.3",
    "@types/ramda": "^0.27.19",
    "@types/react": "^16.9.49",
    "@vtex/test-tools": "^3.3.2",
    "apollo-client": "^2.6.10",
    "typescript": "3.9.7",
    "vtex.product-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-context@0.9.2/public/@types/vtex.product-context",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.122.2/public/@types/vtex.render-runtime",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.132.1/public/@types/vtex.styleguide"
  }
}

```


[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 condition-layout/react/ConditionLayoutBinding.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo } from 'react'
import { useRuntime } from 'vtex.render-runtime'
import type { ComponentType } from 'react'

import ConditionLayout from './ConditionLayout'
import type { NoUndefinedField, MatchType, Condition, Handlers } from './types'

type Props = {
  conditions: Array<Condition<ContextValues, HandlerArguments>>
  matchType?: MatchType
  Else?: ComponentType
  Then?: ComponentType
}

type ContextValues = {
  bindingId: string
}

type HandlerArguments = {
  bindingId: { id: string }
}

const HANDLERS: Handlers<ContextValues, HandlerArguments> = {
  bindingId({ values, args }) {
    return String(values.bindingId) === String(args?.id)
  },
}

const ConditionLayoutBinding: StorefrontFunctionComponent<Props> = ({
  Else,
  Then,
  matchType,
  conditions,
  children,
}) => {
  const {
    binding: { id: bindingId },
  } = useRuntime()

  const values = useMemo<ContextValues>(() => {
    const bag = {
      bindingId,
    }

    // We use `NoUndefinedField` to remove optionality + undefined values from the type
    return bag as NoUndefinedField<typeof bag>
  }, [bindingId])

  return (
    <ConditionLayout
      Else={Else}
      Then={Then}
      matchType={matchType}
      conditions={conditions}
      values={values}
      handlers={HANDLERS}
    >
      {children}
    </ConditionLayout>
  )
}

export default ConditionLayoutBinding

```


[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 condition-layout/react/Noop.tsx from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
const Noop = () => {
  if (process.env.NODE_ENV === 'development') {
    throw new Error(
      'Do not use the "condition-layout" block directly. Please use the appropriate variation for your context.'
    )
  }

  return null
}

export default Noop

```


[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 condition-layout/store/contentSchemas.json from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "ConditionLayoutProduct": {
      "title": "admin/editor.condition-layout.wrapper.product"
    },
    "ConditionProduct": {
      "title": "admin/editor.condition-layout.condition",
      "type": "object",
      "properties": {
        "enabled": {
          "title": "admin/editor.condition-layout.enabled.title",
          "description": "admin/editor.condition-layout.enabled.description",
          "default": true,
          "type": "boolean"
        }
      },
      "dependencies": {
        "enabled": {
          "oneOf": [
            {
              "properties": {
                "enabled": {
                  "enum": [true]
                },
                "match": {
                  "default": "all",
                  "enum": ["any", "none", "all"],
                  "title": "admin/editor.condition-layout.match",
                  "type": "string"
                },
                "conditions": {
                  "title": "admin/editor.condition-layout.conditions",
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "subject": {
                        "default": "",
                        "type": "string",
                        "title": "admin/editor.condition-layout.subject",
                        "enum": [
                          "productId",
                          "categoryId",
                          "brandId",
                          "productClusters",
                          "categoryTree",
                          "specificationProperties",
                          "selectedItemId"
                        ],
                        "enumNames": [
                          "admin/editor.condition-layout.product.subject.productId",
                          "admin/editor.condition-layout.product.subject.categoryId",
                          "admin/editor.condition-layout.product.subject.brandId",
                          "admin/editor.condition-layout.product.subject.productClusters",
                          "admin/editor.condition-layout.product.subject.categoryTree",
                          "admin/editor.condition-layout.product.subject.specificationProperties",
                          "admin/editor.condition-layout.product.subject.selectedItemId"
                        ]
                      },
                      "verb": {
                        "type": "string",
                        "title": "admin/editor.condition-layout.verb"
                      },
                      "object": {
                        "type": "string",
                        "title": "admin/editor.condition-layout.object"
                      }
                    },
                    "dependencies": {
                      "subject": {
                        "oneOf": [
                          {
                            "properties": {
                              "subject": {
                                "enum": [
                                  "productClusters",
                                  "categoryTree",
                                  "specificationProperties"
                                ]
                              },
                              "verb": {
                                "default": "contains",
                                "enum": ["contains", "does-not-contain"],
                                "enumNames": [
                                  "admin/editor.condition-layout.verb.contains",
                                  "admin/editor.condition-layout.verb.does-not-contain"
                                ]
                              }
                            }
                          },
                          {
                            "properties": {
                              "subject": {
                                "enum": [
                                  "productId",
                                  "categoryId",
                                  "brandId",
                                  "selectedItemId"
                                ]
                              },
                              "verb": {
                                "default": "is",
                                "enum": ["is", "is-not"],
                                "enumNames": [
                                  "admin/editor.condition-layout.verb.is",
                                  "admin/editor.condition-layout.verb.is-not"
                                ]
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          ]
        }
      }
    },
    "ConditionElse": {
      "title": "admin/editor.condition-layout.else",
      "type": "object",
      "properties": {
        "enabled": {
          "default": true,
          "title": "admin/editor.condition-layout.enabled.title",
          "type": "boolean"
        }
      }
    }
  }
}

```


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

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

[Assistant]
Here's the implementation:

```json
{
  "condition-layout": {
    "component": "Noop"
  },
  "condition-layout.product": {
    "component": "ConditionLayoutProduct",
    "composition": "children",
    "content": {
      "$ref": "app:vtex.condition-layout#/definitions/ConditionLayoutProduct"
    }
  },
  "condition-layout.binding": {
    "component": "ConditionLayoutBinding",
    "composition": "children"
  },
  "condition-layout.category": {
    "component": "ConditionLayoutCategory",
    "composition": "children"
  },
  "condition-layout.telemarketing": {
    "component": "ConditionLayoutTelemarketing",
    "composition": "children"
  }
}

```


[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 condition-layout/react/typings/storefront.d.ts from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable @typescript-eslint/ban-types */
import { FunctionComponent } from 'react'

declare global {
  interface StorefrontFunctionComponent<P = {}> extends FunctionComponent<P> {
    getSchema?(props: P): object
    schema?: object
  }

  interface StorefrontComponent<P = {}, S = {}> extends Component<P, S> {
    getSchema?(props: P): object
    schema: object
  }
}

```


[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 condition-layout/react/modules/conditions.ts from the condition-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Condition, MatchType } from '../types'

export function validateConditions({
  matchType = 'all',
  conditions,
  values,
  handlers,
}: {
  matchType?: MatchType
  conditions: Condition[]
  values: Record<string, unknown>
  handlers: Record<string, unknown>
}) {
  const matches = conditions.reduce((acc: boolean | null, condition) => {
    const { subject, arguments: args, toBe = true } = condition
    const handler = handlers[subject]

    // istanbul ignore next
    if (typeof handler !== 'function') {
      if (process.env.NODE_ENV !== 'production') {
        console.error(
          `Invalid subject "${subject}". Must be one of "${Object.keys(
            handlers
          ).join(', ')}".`
        )
      }

      return acc
    }

    const conditionMatch = handler({ values, args }) === toBe

    if (matchType === 'any') {
      return (acc ?? false) || conditionMatch
    }

    if (matchType === 'none') {
      return (acc ?? true) && !conditionMatch
    }

    // matchType === all
    return (acc ?? true) && conditionMatch
  }, null)

  return matches
}

```


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

[Assistant]
Here's the implementation:

```markdown
# Facebook pixel

VTEX Facebook Pixel first-party app allows you to connect your store to the Facebook ad services. You will be able to create ads and manage campaigns in real time through a Facebook "Ads Manager" account.

## Intalling Facebook pixel app

1. Open the [VTEX App Store](https://apps.vtex.com/vtex-facebook-pixel/p) and install this app on your store, or run the following command on the VTEX IO CLI:

```
vtex install vtex.facebook-pixel@2.x
```

2. Now, open the app settings on your [store's Admin](https://your-store-name.myvtex.com/admin/apps).
3. Click on facebook pixel app, and fill in the Facebook Pixel 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 facebook-pixel/react/index.tsx from the facebook-pixel VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { ProductOrder, PixelMessage, Product } from './typings/events'
import { canUseDOM } from 'vtex.render-runtime'

function handleMessages(e: PixelMessage) {
  switch (e.data.eventName) {
    case 'vtex:pageView': {
      fbq('track', 'PageView')
      break
    }
    case 'vtex:orderPlaced': {
      const { currency, transactionTotal, transactionProducts, orderGroup } = e.data

      fbq('track', 'Purchase', {
        value: transactionTotal,
        currency,
        content_type: 'product',
        eventID: orderGroup,
        contents: transactionProducts.map(
          (product: ProductOrder) => ({
            id: product.sku,
            quantity: product.quantity,
            item_price: product.sellingPrice
          })
        )
      });
      break
    }
    case 'vtex:productView': {
      const { product: { productName, items }, currency } = e.data

      fbq('track', 'ViewContent', {
        content_ids: items.map(({ itemId }) => itemId),
        content_name: productName,
        content_type: 'product',
        currency,
        value: getProductPrice(e.data.product),
      })
      break
    }
    case 'vtex:addToCart': {
      const { items, currency } = e.data

      fbq('track', 'AddToCart', {
        value: items.reduce((acc, item) => acc + item.price, 0) / 100,
        content_ids: items.map(sku => sku.skuId),
        contents: items.map(sku => ({
          id: sku.skuId,
          quantity: sku.quantity,
          item_price: sku.price / 100,
        })),
        content_type: 'product',
        currency: currency,
      })
      break
    }
    default:
      break
  }
}

function getProductPrice(product: Product) {
  let price
  try {
    price = product.items[0].sellers[0].commertialOffer.Price
  } catch {
    price = undefined
  }
  return price
}

if (canUseDOM) {
  window.addEventListener('message', handleMessages)
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.facebook-pixel",
  "version": "2.2.3",
  "dependencies": {
    "ramda": "^0.25.0"
  },
  "scripts": {
    "lint": "tsc --noEmit --pretty && tslint -c tslint.json './**/*.ts'"
  },
  "devDependencies": {
    "@types/node": "^10.12.18",
    "@types/prop-types": "^15.5.6",
    "@types/ramda": "types/npm-ramda#dist",
    "@types/react": "^16.4.14",
    "tslint": "^5.11.0",
    "tslint-config-vtex": "^2.0.0",
    "tslint-eslint-rules": "^5.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 facebook-pixel/store/interfaces.json from the facebook-pixel VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "pixel.facebookPixel": {
    "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 facebook-pixel/react/typings/events.d.ts from the facebook-pixel VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface PixelMessage extends MessageEvent {
  data: ProductViewData | ProductClickData | OrderPlacedData | PageViewData | ProductImpressionData | AddToCartData | RemoveToCartData | CategoryViewData | DepartmentViewData
}

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

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

export interface CategoryViewData extends EventData {
  event: 'categoryView'
  eventName: 'vtex:categoryView'
  products: Product[]
}

export interface DepartmentViewData extends EventData {
  event: 'departmentView'
  eventName: 'vtex:departmentView'
  products: Product[]
}

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

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

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

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

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

export interface ProductImpressionData extends EventData {
  event: 'productImpression'
  eventName: 'vtex:productImpression'
  product: Product
  position: number
  list: string
}

export interface Order {
  currency: string
  accountName: string
  orderGroup: string
  salesChannel: string
  coupon: string
  visitorType: string
  visitorContactInfo: string[]
  transactionId: string
  transactionDate: string
  transactionAffiliation: string
  transactionTotal: number,
  transactionShipping: number,
  transactionTax: number,
  transactionCurrency: string,
  transactionPaymentType: PaymentType[],
  transactionShippingMethod: ShippingMethod[]
  transactionProducts: ProductOrder[]
  transactionPayment: {
    id: string
  }
}

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

interface ShippingMethod {
  itemId: string
  selectedSla: string
}

interface ProductOrder {
  id: string,
  name: string,
  sku: string,
  skuRefId: string,
  skuName: string,
  brand: string,
  brandId: string,
  seller: string,
  sellerId: string,
  category: string,
  categoryId: string,
  categoryTree: string[]
  categoryIdTree: string[]
  originalPrice: number
  price: number
  sellingPrice: number
  tax: number
  quantity: number
  components: any[]
  measurementUnit: string
  unitMultiplier: number
}

export interface Product {
  brand: string
  categoryId?: string // inconsistency
  categories: string[]
  productId: string
  productName: string
  selectedSku?: string // inconsistency
  items: Item[]
  sku: Item
  [key: string]: any
}

interface Item {
  itemId: string
  name: string
  seller?: Seller
  [key: string]: any
}

interface Seller {
  commertialOffer: CommertialOffer
  AvailableQuantity: number
  [key: string]: any
}

interface CommertialOffer {
  Price: number
  [key: string]: any
}

interface AddToCartProduct {
  brand: string
  name: string
  price: number
  quantity: number
  skuId: string
  variant: 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 facebook-pixel/react/typings/vtex.render-runtime.d.ts from the facebook-pixel VTEX app.

[Assistant]
Here's the implementation:

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

```


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

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

[Assistant]
Here's the implementation:

```typescript
declare function fbq(s: string, t: string, o?: any): void

interface Event extends Event {
  data: any
}

interface Window extends Window {
  __SETTINGS__: {
    pixelId: 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 sponsored-products/docs/README.md from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

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

# Sponsored Products

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

VTEX Sponsored Products is responsible for implementing the necessary frontend apps to properly render the sponsored products.

:warning: Keep in mind that this app alone **will not** request the sponsored products; it will only add the "Sponsored" badge and add the Analytics wrapper.

![Media Placeholder](https://github.com/vtex-apps/sponsored-products/assets/15937541/576a2021-0d90-47b7-a6fc-bb60f231cca2)

## Configuration

### Step 1: Adding the Sponsored Products app to your theme's dependency

In your theme's `manifest.json`, add the Sponsored Products app as a dependency:

```json
  "dependencies": {
    "vtex.sponsored-products": "0.x"
  }
```

Now, you are able to use all the blocks exported by the `sponsored-products` app. Check out the full list below:

#### `sponsored-products` blocks

| Block name        | Description                                                                                |
| ----------------- | -------------------------------------------------------------------------------------------------------------- |
| `sponsored-badge` | Renders the "Sponsored" badge in your Product Summary. You can customize its CSS however fits best your store. |
| `ads-analytics`   | Necessary for observing impression and click metrics to assess the performance of the campaigns                |

### Step 2: Using the Sponsored Products blocks

#### The sponsored badge

This is fairly straightforward: simply call it as a child block on you Product Summary shelf. For example:

```diff
"product-summary.shelf": {
    "children": [
        "stack-layout#prodsum",
        "product-summary-space",
+       "sponsored-badge",
        "product-summary-name",
        "flex-layout.col#productRating",
        "product-summary-space",
        "product-list-price#summary",
        "flex-layout.row#selling-price-savings",
        "product-installments#summary",
        "add-to-cart-button"
    ]
},
```

They can also be added anywhere where a product is in context. For instance, in a product carrousel.

#### The Ads Analytics wrapper

For this one, you'll need to use the Ads Analytics directly as children of your Gallery block. For instance:

```diff
"gallery": {
    "props": {
        "layouts": [
            {
                "name": "grid",
                "component": "GridSummary",
                "itemsPerRow": {
                    "(min-width:1300px)": 4,
                    "desktop": 3,
                    "tablet": 3,
                    "phone": 2
                }
            },
            {
                "name": "list",
                "component": "ListSummary",
                "itemsPerRow": 1
            }
        ],
+       "ListSummary": "ads-analytics#listLayout",
+       "GridSummary": "ads-analytics"
    }
},

+ "ads-analytics": {
+   "props": {
+       "ProductSummary": "product-summary.shelf"
+   }
+ },

+ "ads-analytics#listLayout": {
+   "props": {
+   "ProductSummary": "product-summary.shelf#listLayout"
+   }
+ },

```

## Blocks

### `sponsored-badge`

No props are necessary, this component is able to access the current product via context automatically.

### `ads-analytics`

| Prop name        | Type     | Description                                 | Default value |
| ---------------- | -------- | ------------------------------------------- | ------------- |
| `ProductSummary` | `string` | The component used for the Product Summary. | `undefined`   |

## Customization

In order to apply CSS customizations in this and other blocks, follow the instructions given in the recipe on [Using CSS Handles for store customization](https://vtex.io/docs/recipes/style/using-css-handles-for-store-customization).

| CSS Handles             |
| ----------------------- |
| `badgeContainer`        |
| `badgeText`             |
| `adsAnalyticsContainer` |

<!-- 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 sponsored-products/react/babel.config.js from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```javascript
module.exports = {
  presets: [
    '@babel/preset-env',
    ['@babel/preset-react', { runtime: 'automatic' }],
    '@babel/preset-typescript',
  ],
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "sponsored-products",
  "version": "0.1.0",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "jest": {
    "testEnvironment": "jsdom"
  },
  "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",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@1.0.0/public/@types/vtex.css-handles"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@babel/core": "^7.23.0",
    "@babel/preset-env": "^7.22.20",
    "@babel/preset-react": "^7.22.15",
    "@babel/preset-typescript": "^7.23.0",
    "@faker-js/faker": "^8.1.0",
    "@types/node": "^13.9.8",
    "@types/react": "^16.9.31",
    "@types/rosie": "^0.0.43",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.4.4",
    "apollo-cache-inmemory": "^1.6.5",
    "babel-jest": "^29.7.0",
    "graphql": "^14.6.0",
    "jest": "^26.0.0",
    "jest-environment-jsdom": "^26.0.0",
    "rosie": "^2.1.0",
    "ts-jest": "^29.1.1",
    "typescript": "3.9.7",
    "vtex.product-summary-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-summary-context@0.10.0/public/@types/vtex.product-summary-context"
  },
  "resolutions": {
    "@types/jest": "26.0.15"
  }
}

```


[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 sponsored-products/react/SponsoredBadge.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { SponsoredBadge } from './components/SponsoredBadge'

export default SponsoredBadge

```


[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 sponsored-products/react/AdsAnalytics.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { AdsAnalytics } from './components/AdsAnalytics'

export default AdsAnalytics

```


[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 sponsored-products/store/interfaces.json from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "sponsored-badge": {
    "component": "SponsoredBadge"
  },
  "ads-analytics": {
    "component": "AdsAnalytics"
  }
}

```


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

[Assistant]
Here's the implementation:

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

  const Schema: DocumentNode

  export default Schema
}

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

  const schema: DocumentNode

  export default schema
}

```


[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 sponsored-products/react/typings/css.d.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  type Styles = {
    [selector: string]: string
  }

  const styles: Styles

  export default styles
}

```


[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 sponsored-products/react/utils/isSponsored.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

const isSponsored = (product: Product) => !!product?.advertisement?.adId

export default isSponsored

```


[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 sponsored-products/react/utils/index.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import isSponsored from './isSponsored'

export { isSponsored }

```


[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 sponsored-products/react/utils/__tests__/isSponsored.test.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

import ProductFactory from '../../__testUtils__/factories/product'
import isSponsored from '../isSponsored'

describe('#isSponsored', () => {
  describe('when the product is sponsored', () => {
    const product = ProductFactory.build() as Product

    it('should return true', () => {
      expect(isSponsored(product)).toBe(true)
    })
  })

  describe('when the product is not sponsored', () => {
    const product = ProductFactory.build({}, { isSponsored: false }) as Product

    it('should return true', () => {
      expect(isSponsored(product)).toBe(false)
    })
  })
})

```


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

[User] Show me the implementation of sponsored-products/react/components/SponsoredBadge/SponsoredBadge.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { FormattedMessage } from 'react-intl'
import { useCssHandles } from 'vtex.css-handles'
import { ProductSummaryContext } from 'vtex.product-summary-context'

import { isSponsored } from '../../utils'

const { useProductSummary } = ProductSummaryContext
const CSS_HANDLES = ['badgeContainer', 'badgeText'] as const

export const SponsoredBadge = () => {
  const { product } = useProductSummary()
  const { handles } = useCssHandles(CSS_HANDLES)

  if (!isSponsored(product)) return null

  return (
    <div className={handles.badgeContainer}>
      <span className={handles.badgeText}>
        <FormattedMessage id="store/sponsoredBadge.title" />
      </span>
    </div>
  )
}

```


[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 sponsored-products/react/components/AdsAnalytics/AdsAnalytics.types.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { ProductSummaryTypes } from 'vtex.product-summary-context'

type ProductSummaryProps = {
  product: ProductSummaryTypes.Product
  position: number
  [x: string]: unknown
}

export type AdsAnalyticsProps = {
  ProductSummary: React.FC<ProductSummaryProps>
} & ProductSummaryProps

export type DataProperties = {
  'data-van-prod-id': string
  'data-van-prod-name': string
  'data-van-position': number
  'data-van-aid': string
  'data-van-cid': string
  'data-van-req-id': string
  'data-van-res-id': string
  'data-van-cpc': number
}

```


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

[User] Show me the implementation of sponsored-products/react/components/AdsAnalytics/AdsAnalytics.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useCssHandles } from 'vtex.css-handles'

import { isSponsored } from '../../utils'
import { AdsAnalyticsProps } from './AdsAnalytics.types'
import { getDataProperties } from './utils'

const CSS_HANDLES = ['adsAnalyticsContainer'] as const

export const AdsAnalytics = ({
  ProductSummary,
  ...productSummaryProps
}: AdsAnalyticsProps) => {
  const { handles } = useCssHandles(CSS_HANDLES)
  const { product, position } = productSummaryProps

  if (!isSponsored(product)) return <ProductSummary {...productSummaryProps} />

  const dataProperties = getDataProperties({ product, position })

  return (
    <div
      {...dataProperties}
      className={handles.adsAnalyticsContainer}
      data-testid="ads-analytics"
    >
      <ProductSummary {...productSummaryProps} />
    </div>
  )
}

```


[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 sponsored-products/react/components/SponsoredBadge/__tests__/SponsoredBadge.test.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import '@testing-library/jest-dom'
import { render, screen } from '@vtex/test-tools/react'
import React from 'react'
import { ProductSummaryContext } from 'vtex.product-summary-context'
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

import ProductFactory from '../../../__testUtils__/factories/product'
import { SponsoredBadge } from '../SponsoredBadge'

const setupTests = ({ isSponsored = true } = {}) => {
  const product = ProductFactory.build({}, { isSponsored }) as Product

  return render(
    <ProductSummaryContext.ProductSummaryProvider product={product}>
      <SponsoredBadge />
    </ProductSummaryContext.ProductSummaryProvider>
  )
}

describe('<SponsoredBadge />', () => {
  describe('when the product is sponsored', () => {
    beforeEach(() => setupTests())

    it('should render the badge', () => {
      expect(screen.getByText(/Sponsored/i)).toBeInTheDocument()
    })
  })

  describe('when the product is not sponsored', () => {
    beforeEach(() => setupTests({ isSponsored: false }))

    it('should not render the badge', () => {
      expect(screen.queryByText(/Sponsored/i)).not.toBeInTheDocument()
    })
  })
})

```


[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 sponsored-products/react/components/AdsAnalytics/utils/index.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import getDataProperties from './getDataProperties'

export { getDataProperties }

```


[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 sponsored-products/react/components/AdsAnalytics/utils/getDataProperties.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

import { isSponsored } from '../../../utils'
import { DataProperties } from '../AdsAnalytics.types'

type GetDataPropertiesArgs = {
  product: Product
  position: number
}

const getDataProperties = ({
  product,
  position,
}: GetDataPropertiesArgs): Nullable<DataProperties> => {
  if (!isSponsored(product)) return

  const {
    productId,
    productName,
    advertisement: { adId, campaignId, adRequestId, adResponseId, actionCost },
  } = product

  return {
    'data-van-prod-id': productId,
    'data-van-prod-name': productName,
    'data-van-position': position,
    'data-van-aid': adId,
    'data-van-cid': campaignId,
    'data-van-req-id': adRequestId,
    'data-van-res-id': adResponseId,
    'data-van-cpc': actionCost,
  }
}

export default getDataProperties

```


[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 sponsored-products/react/components/AdsAnalytics/__tests__/AdsAnalytics.test.tsx from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```tsx
import '@testing-library/jest-dom'
import { render } from '@vtex/test-tools/react'
import React from 'react'
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

import ProductFactory from '../../../__testUtils__/factories/product'
import { AdsAnalytics } from '../AdsAnalytics'

const testId = 'product-summary'
const MockProductSummary = () => <div data-testid={testId}>ProductSummary</div>

const position = 1

const setupTest = (product: Product) => {
  return render(
    <AdsAnalytics
      ProductSummary={MockProductSummary}
      product={product}
      position={position}
    />
  )
}

describe('<AdsAnalytics />', () => {
  describe('when a product is sponsored', () => {
    const product = ProductFactory.build() as Product

    it('should render the ProductSummary component passed as prop', () => {
      const { getByTestId } = setupTest(product)

      expect(getByTestId(testId)).toBeInTheDocument()
    })

    it('should add a wrapper with the correct data properties', () => {
      const { getByTestId } = setupTest(product)
      const wrapper = getByTestId('ads-analytics')
      const {
        productId,
        productName,
        advertisement: {
          campaignId,
          adId,
          adRequestId,
          adResponseId,
          actionCost,
        },
      } = product

      expect(wrapper.getAttribute('data-van-prod-id')).toBe(productId)
      expect(wrapper.getAttribute('data-van-prod-name')).toBe(productName)
      expect(wrapper.getAttribute('data-van-position')).toBe('1')
      expect(wrapper.getAttribute('data-van-cid')).toBe(campaignId)
      expect(wrapper.getAttribute('data-van-aid')).toBe(adId)
      expect(wrapper.getAttribute('data-van-req-id')).toBe(adRequestId)
      expect(wrapper.getAttribute('data-van-res-id')).toBe(adResponseId)
      expect(wrapper.getAttribute('data-van-cpc')).toBe(actionCost.toString())
    })
  })

  describe('when a product is not sponsored', () => {
    const product = ProductFactory.build({}, { isSponsored: false }) as Product

    it('should render the ProductSummary component passed as prop', () => {
      const { getByTestId } = setupTest(product)

      expect(getByTestId(testId)).toBeInTheDocument()
    })

    it('should not add a wrapper with the data properties', () => {
      const { queryByTestId } = setupTest(product)

      expect(queryByTestId('ads-analytics')).not.toBeInTheDocument()
    })
  })
})

```


[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 sponsored-products/react/components/AdsAnalytics/utils/__tests__/getDataProperties.test.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

import ProductFactory from '../../../../__testUtils__/factories/product'
import getDataProperties from '../getDataProperties'

const position = 1

describe('#getDataProperties', () => {
  describe('when product is  sponsored', () => {
    const product = ProductFactory.build() as Product

    it('returns the correct data properties to be added to the HTML', () => {
      const dataProperties = getDataProperties({ product, position })

      expect(dataProperties).toMatchObject({
        'data-van-prod-id': product.productId,
        'data-van-prod-name': product.productName,
        'data-van-position': position,
        'data-van-aid': product.advertisement.adId,
        'data-van-cid': product.advertisement.campaignId,
        'data-van-req-id': product.advertisement.adRequestId,
        'data-van-res-id': product.advertisement.adResponseId,
        'data-van-cpc': product.advertisement.actionCost,
      })
    })
  })

  describe('when product is not sponsored', () => {
    const product = ProductFactory.build({}, { isSponsored: false }) as Product

    it('returns undefined', () => {
      const dataProperties = getDataProperties({ product, position })

      expect(dataProperties).toBeUndefined()
    })
  })
})

```


[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 sponsored-products/react/__testUtils__/factories/product.ts from the sponsored-products VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { faker } from '@faker-js/faker'
import { Factory } from 'rosie'
import { Product } from 'vtex.product-summary-context/react/ProductSummaryTypes'

const ProductFactory = Factory.define<Partial<Product>>('product')
  .option('isSponsored', true)
  .attr('productId', faker.string.uuid)
  .attr('productName', faker.commerce.productName())
  .attr('advertisement', ['isSponsored'], (isSponsored: boolean) => {
    if (!isSponsored) return

    return {
      adId: faker.string.uuid(),
      campaignId: faker.string.uuid(),
      adRequestId: faker.string.uuid(),
      adResponseId: faker.string.uuid(),
      actionCost: faker.number.float({ min: 0, max: 5, precision: 0.01 }),
    }
  })

export default ProductFactory

```


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

[Assistant]
Here's the implementation:

```markdown
# Criteo
Get the holiday data you need to drive more sales. See the season’s peaks, top categories, and biggest mobile moments across the globe in our report and interactive map.
For more information please visit, [Criteo](https://www.criteo.com/) website.

## How to install

Open the VTEX APP Store and install the app on your store.

or

Run the following command:

```sh
vtex install vtex.criteo@0.x
```

Next, open the app settings on your admin and fill the form with your Criteo details.
```


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

[User] Show me the implementation of criteo/react/index.tsx from the criteo VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { canUseDOM } from 'vtex.render-runtime'
import { PixelMessage } from './typings/events'
import { fetchEmail, getSiteType } from './helpers'

async function dispatchEvent(event: CriteoQ) {
  const { criteo_q = [], criteo_id: account } = window
  const setAccount: CriteoAccountEvent = { event: 'setAccount', account }
  const setEmail: CriteoEmailEvent = {
    event: 'setEmail',
    email: [await fetchEmail()],
  }
  const setSiteType: CriteoSiteTypeEvent = {
    event: 'setSiteType',
    type: getSiteType(),
  }
  criteo_q.push(setAccount, setEmail, setSiteType, event)
}

function handleMessages(event: PixelMessage) {
  const { criteo_q = [], criteo_id: account } = window
  if (!account) return

  switch (event.data.eventName) {
    case 'vtex:pageInfo': {
      if (event.data.eventType === 'homeView') {
        const setHomeView: CriteoViewHomeEvent = {
          event: 'viewHome',
          tms: 'gtm-vtex',
        }
        dispatchEvent(setHomeView)
      }
      break
    }
    case 'vtex:departmentView':
    case 'vtex:internalSiteSearchView':
    case 'vtex:categoryView': {
      const {
        data: { products },
      } = event
      const item: string[] = products
        .slice(0, 3)
        .map<string>(({ productId }) => productId)
      const setViewList: CriteoViewListEvent = {
        event: 'viewList',
        tms: 'gtm-vtex',
        item,
      }
      dispatchEvent(setViewList)
      break
    }
    case 'vtex:productView': {
      const {
        data: {
          product: { productId },
        },
      } = event
      const setViewItem: CriteoViewItemEvent = {
        event: 'viewItem',
        tms: 'gtm-vtex',
        item: productId,
      }
      dispatchEvent(setViewItem)
      break
    }
    case 'vtex:orderPlaced': {
      const {
        data: { transactionId, transactionProducts },
      } = event

      const item: CriteoTrackTransactionItem[] = transactionProducts.map<
        CriteoTrackTransactionItem
      >(({ id, sellingPrice, quantity }) => ({
        id,
        price: sellingPrice,
        quantity,
      }))

      const setTrackTransaction: CriteoTrackTransactionEvent = {
        event: 'trackTransaction',
        id: transactionId,
        tms: 'gtm-vtex',
        item,
      }

      dispatchEvent(setTrackTransaction)
      break
    }
    default:
      break
  }
}

if (canUseDOM) {
  window.addEventListener('message', handleMessages)
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "author": "vtex",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "devDependencies": {
    "@types/graphql": "^14.2.0",
    "@types/jest": "^24.0.12",
    "@types/node": "^12.0.0",
    "@types/ramda": "^0.25.42",
    "@types/react": "^16.8.16",
    "@types/react-intl": "^2.3.17",
    "@vtex/test-tools": "^0.3.2",
    "apollo-cache-inmemory": "^1.5.1",
    "apollo-client": "^2.5.1",
    "eslint": "^6.4.0",
    "eslint-config-vtex": "^11.0.0",
    "eslint-config-vtex-react": "^5.0.1",
    "prettier": "^1.17.1",
    "typescript": "3.5.2",
    "vtex.pixel-interfaces": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.pixel-interfaces@1.1.0/public/_types/react",
    "vtex.render-runtime": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.render-runtime@8.67.0/public/@types/vtex.render-runtime"
  },
  "version": "0.0.5"
}

```


[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 criteo/store/interfaces.json from the criteo VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "pixel.criteo": {
    "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 criteo/react/typings/events.d.ts from the criteo VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface PixelMessage extends MessageEvent {
  data:
    | PageInfo
    | ProductViewData
    | ProductClickData
    | OrderPlacedData
    | PageViewData
    | ProductImpressionData
    | AddToCartData
    | RemoveToCartData
    | CategoryViewData
    | DepartmentViewData
    | InternalSiteSearchViewData
}

export interface InternalSiteSearchViewData extends EventData {
  event: 'internalSiteSearchView'
  eventName: 'vtex:internalSiteSearchView'
  products: Product[]
}

export interface CategoryViewData extends EventData {
  event: 'categoryView'
  eventName: 'vtex:categoryView'
  products: Product[]
}

export interface DepartmentViewData extends EventData {
  event: 'departmentView'
  eventName: 'vtex:departmentView'
  products: Product[]
}

export interface PageInfo extends EventData {
  event: 'pageInfo'
  eventName: 'vtex:pageInfo'
  eventType: string
}

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

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

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

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

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

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

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

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

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

export interface Order {
  currency: string
  accountName: string
  orderGroup: string
  salesChannel: string
  coupon: string
  visitorType: string
  visitorContactInfo: string[]
  visitorAddressState: string
  visitorAddressCountry: string
  visitorAddressPostalCode: string
  transactionId: string
  transactionDate: string
  transactionAffiliation: string
  transactionTotal: number
  transactionShipping: number
  transactionSubtotal: number
  transactionDiscounts: number
  transactionTax: number
  transactionCurrency: string
  transactionPaymentType: PaymentType[]
  transactionShippingMethod: ShippingMethod[]
  transactionProducts: ProductOrder[]
  transactionPayment: {
    id: string
  }
}

export interface Impression {
  product: Product
  position: number
}

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

interface ShippingMethod {
  itemId: string
  selectedSla: string
}

interface ProductOrder {
  id: string
  name: string
  sku: string
  skuRefId: string
  skuName: string
  productRefId: string
  ean: string
  slug: string
  brand: string
  brandId: string
  seller: string
  sellerId: string
  category: string
  categoryId: string
  categoryTree: string[]
  categoryIdTree: string[]
  priceTags: PriceTag[]
  originalPrice: number
  price: number
  sellingPrice: number
  tax: number
  quantity: number
  components: any[]
  measurementUnit: string
  unitMultiplier: number
}

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

interface Product {
  brand: string
  categoryId?: string // inconsistency
  categories: string[]
  productId: string
  productName: string
  selectedSku?: string // inconsistency
  items: Item[]
  sku: Item
  [key: string]: any
}

interface Item {
  itemId: string
  name: string
  seller?: Seller
  [key: string]: any
}

interface Seller {
  commertialOffer: CommertialOffer
  [key: string]: any
}

interface CommertialOffer {
  Price: number
  [key: string]: any
}

```