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

[Assistant]
Here's the implementation:

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

# Modal Layout

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

The Modal Layout app provides blocks to help you create modals in your store.

![image](https://cdn.jsdelivr.net/gh/vtexdocs/dev-portal-content@main/images/vtex-modal-layout-0.png)

## Configuration

1. Add the Modal Layout app to your theme dependencies in the `manifest.json`:

```diff
  "dependencies": {
+   "vtex.modal-layout": "0.x"
  }
```

Now, you can use all blocks exported by the `modal-layout` app. See the full list below:

| Block name            | Description                                                                                |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `modal-trigger`       | ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Defines how the modal content will be triggered through its children blocks.                                                                                |
| `modal-layout`        | ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Defines how the modal content will be rendered through its children blocks. You can declare the `modal-header` and `modal-content` blocks, described below, as children to create a modal with a header and footer. |
| `modal-header`        | Renders a close button and the blocks listed as its children, building a modal header. Note that it does not automatically render a header for your modal. Instead, you should create the modal header as you desire using the children list of this block.                                                                                |
| `modal-content`       | Defines how the modal content will be rendered through its children blocks. Preferably, this block should be used along with the `modal-header` block in order to create a modal with a header and a footer.                                                                                |
| `modal-actions`       | Logical block that only renders its child blocks that, in turn, render call-to-action buttons inside the modal, such as a confirmation button.                                                                                |
| `modal-actions.close` | Button that closes the modal when clicked. It is extremely useful when your modal only has a form or a disclaimer box providing information to the users.                                                                                |

2. Add the `modal-trigger` block in any store template you choose. In the example below, it will be added to the homepage:

```jsonc
{
  "store.home": {
    "children": [
      "modal-trigger#example"
    ]
  },
```

3. Declare the `modal-trigger` block using its prop and configure the children blocks. The first child block of `modal-trigger` must be a block you choose to trigger the modal content. Then, a sibling block called `modal-layout` will be needed to effectively define the modal content through its child block list. For example:

```jsonc
{
  "store.home": {
    "children": ["modal-trigger#example"]
  },
  "modal-trigger#example": {
    "children": ["rich-text#example", "modal-layout#example"]
  },
  "rich-text#example": {
    "props": {
      "text": "Click me"
    }
  },
  "modal-layout#example": {
    "children": ["rich-text#modal-content"]
  },
  "rich-text#modal-content": {
    "props": {
      "text": "Hello"
    }
  }
}
```

In the example above, the [Rich Text](https://developers.vtex.com/docs/apps/vtex.rich-text/) block renders the `Click me` text that will trigger the modal content when clicked. The modal content, in turn, is defined by the `modal-layout` block. Based on the example above, the modal content triggered by the `Click me` Rich Text would be a `Hello` text.

### `modal-trigger` props

| Prop name              | Type     | Description                                                                                | Default value |
| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `trigger`              | `enum`   | Defines whether the modal content should be triggered by user click (`click`), when the page is fully loaded (`load`), or when the page is fully loaded, but the modal will appear just once per session (`load-session`).                                                                                | `click`       |
| `customPixelEventId`   | `string` | Store event ID that triggers the `modal-trigger` block (hence triggering the opening of `modal-layout` blocks on the interface as well).                                                                                | `undefined`   |
| `customPixelEventName` | `string` | Store event name that triggers the `modal-trigger` block (hence triggering the opening of `modal-layout` blocks on the interface as well). Some event examples are `'addToCart'` and `'removeFromCart'`. Note that using this prop will make the associated `modal-layout` open in **every** event with the specified name if no `customPixelEventId` is set. | `undefined`   |

### `modal-layout` props

| Prop name              | Type      | Description                                                                                | Default value |
| ---------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `scroll`               | `enum`    | Defines how users should scroll the modal. Possible values are: `body` (users can scroll the whole modal by normally scrolling the page) and `content` (users can scroll the modal _content_ when hovering over it).                                                                                | `content`     |
| `blockClass`           | `string`  | Unique block ID to be used in [CSS customizations](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization).                                                                                | `undefined`   |
| `disableEscapeKeyDown` | `boolean` | Defines whether the modal should be closed when pressing the `Esc` key (`true`) or not (`false`).                                                                                | `false`       |
| `fullScreen`           | `boolean` | Defines whether the modal should fill the whole screen (`true`) or not (`false`). This prop is responsive, i.e., it adapts to the device breakpoints.                                                                                | `false`       |
| `backdrop`             | `enum`    | Defines whether the modal will have a clickable backdrop (`clickable`) or no backdrop at all (`none`). This prop is responsive, i.e., it adapts to the device breakpoints.                                                                                | `clickable`   |
| `customPixelEventId`   | `string`  | Store event ID that triggers the `modal-layout` block (hence triggering the closing of `modal-layout` blocks on the interface as well).                                                                                | `undefined`   |
| `customPixelEventName` | `string`  | Store event name that triggers the `modal-layout` block (hence triggering the closing of `modal-layout` blocks on the interface as well). Some event examples are `'addToCart'` and `'removeFromCart'`. Note that using this prop will make the associated `modal-layout` close in **every** event with the specified name if no `customPixelEventId` is set. | `undefined`   |

### `modal-header` props

| Prop name         | Type      | Description                                                                                | Default value |
| ----------------- | --------- | ------------------------------------------------------------------------------------------------------- | ------------- |
| `showCloseButton` | `boolean` | Defines whether the close icon button should be rendered in the modal header (`true`) or not (`false`). | `true`        |
| `iconCloseSize`   | `number`  | Size (in pixels) of the close icon button in the modal header.                                          | `32`          |

### `modal-actions.close` props

| Prop name | Type     | Description                                                                                | Default value                                                                                |
| --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `label`   | `string` | Defines the text to be rendered in the close button. The default value of this prop depends on the store's default language, which is set according to the website [binding](https://help.vtex.com/tutorial/what-is-binding--4NcN3NJd0IeYccgWCI8O2W?locale=en). | `Cancel`, `Cancelar`, or `Cancelar` for stores whose default language is, respectively, English, Spanish, or Portuguese. |

## Customization

To apply CSS customizations in this and other blocks, follow the instructions given in the recipe on [Using CSS handles for store customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization).

| CSS handles            |
| ---------------------- |
| `modal`                |
| `backdropContainer`    |
| `backdrop`             |
| `closeButtonContainer` |
| `closeButton`          |
| `container`            |
| `contentContainer`     |
| `headerContainer`      |
| `headerContent`        |
| `paper`                |
| `topRow`               |
| `triggerContainer`     |

<!-- 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 -->
<table>
  <tr>
    <td align="center"><a href="https://github.com/BeatrizMiranda"><img src="https://avatars2.githubusercontent.com/u/28959326?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Beatriz Miranda</b></sub></a><br /><a href="https://github.com/vtex-apps/modal-layout/commits?author=BeatrizMiranda" title="Code">💻</a></td>
    <td align="center"><a href="https://acct.global/"><img src="https://avatars0.githubusercontent.com/u/38354801?v=4?s=100" width="100px;" alt=""/><br /><sub><b>weslybrandao</b></sub></a><br /><a href="https://github.com/vtex-apps/modal-layout/commits?author=weslybrandao" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/renanguerraa1"><img src="https://avatars2.githubusercontent.com/u/69531548?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Renan Guerra</b></sub></a><br /><a href="https://github.com/vtex-apps/modal-layout/commits?author=renanguerraa1" 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 modal-layout/react/ModalActions.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

import { useModalState } from './components/ModalContext'

const CSS_HANDLES = [
  'actionsContainer',
  'actionsContentWrapper',
  'actionsContainerEndOfContent',
] as const

interface Props {
  children: React.ReactNode
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

export default function ModalActions({ children, classes }: Props) {
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const { endOfContent } = useModalState()
  const containerClasses = classnames(handles.actionsContainer, {
    [handles.actionsContainerEndOfContent]: endOfContent,
  })

  return (
    <div className={containerClasses}>
      <div className={handles.actionsContentWrapper}>{children}</div>
    </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 modal-layout/react/styles.css from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```css
.backdropContainer {
  z-index: -1;
  position: fixed;
  right: 0;
  bottom: 0;
  top: 0;
  left: 0;
  touch-action: none;
}

.paperScrollContent {
  max-height: calc(100% - 4rem);
  overflow: auto;
}

/* We have to apply margin: 2rem instead of using ma7 because if the user
* change the value of ma7 the max-height of .paperScrollContent will break
*/
.paperNotFullScreen {
  margin: 2rem;
}

.contentScroll {
  -webkit-overflow-scrolling: 'touch';
}

.fullScreenModal {
  max-height: none;
}

.headerContainer {
  flex-basis: auto;
}

.hiddenContainer {
  /* This can't be overflow-y: hidden because of some problem with safari */
  overflow: hidden;
}

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { useRef, useCallback } from 'react'
import type { ReactNode } from 'react'
import classnames from 'classnames'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'

import styles from './styles.css'
import { useModalDispatch } from './components/ModalContext'
import useIntersection from './modules/useIntersection'

const CSS_HANDLES = ['contentContainer'] as const

interface Props {
  children: ReactNode
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

function ModalContent({ children, classes }: Props) {
  const intersectionRef = useRef<IntersectionObserver | null>(null)
  const sentinelRef = useRef<HTMLDivElement | null>(null)
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const dispatch = useModalDispatch()
  const handleIntersection = useCallback(
    (isIntersecting: boolean) => {
      dispatch({
        type: 'SET_END_OF_CONTENT',
        payload: { endOfContent: isIntersecting },
      })
    },
    [dispatch]
  )

  useIntersection({
    sentinelRef,
    intersectionRef,
    callback: handleIntersection,
  })

  return (
    <div
      className={classnames(
        handles.contentContainer,
        styles.contentScroll,
        'overflow-y-auto pa5 relative'
      )}
    >
      {children}
      <div
        className="absolute bottom-0 right-0"
        style={{ height: 1, width: 1 }}
        ref={sentinelRef}
      />
    </div>
  )
}

export default ModalContent

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useRef, useCallback, useEffect } from 'react'
import type { CssHandlesTypes } from 'vtex.css-handles'
import classnames from 'classnames'

import TrapFocus from './components/TrapFocus'
import ModalManager from './modules/ModalManager'
import type { BackdropMode } from './components/Backdrop'
import Backdrop, {
  CSS_HANDLES as BackdropCssHandles,
} from './components/Backdrop'
import createChainedFunction from './modules/createChainedFunction'
import type { ContainerType } from './components/Portal'
import Portal, { getContainer } from './components/Portal'
import ownerDocument from './modules/ownerDocument'
import useEventCallback from './modules/useEventCallback'

export const CSS_HANDLES = ['modal', ...BackdropCssHandles] as const

interface Props
  extends React.DetailedHTMLProps<
    React.HTMLAttributes<HTMLDivElement>,
    HTMLDivElement
  > {
  open: boolean
  onClose: () => void
  backdrop?: BackdropMode
  container?: ContainerType
  disableEscapeKeyDown?: boolean
  children: React.ReactElement
  onBackdropClick?: (e: React.MouseEvent<HTMLDivElement>) => void
  handles: CssHandlesTypes.CssHandles<typeof CSS_HANDLES>
}

const inlineStyles: Record<string, React.CSSProperties> = {
  container: {
    position: 'fixed',
    right: 0,
    bottom: 0,
    top: 0,
    left: 0,
    zIndex: 1300,
  },
} as const

const manager = new ModalManager()

export default function BaseModal(props: Props) {
  const {
    open,
    onClose,
    backdrop,
    children,
    container,
    onBackdropClick,
    disableEscapeKeyDown = false,
    handles,
    ...rest
  } = props

  const [exited, setExited] = useState(true)
  const modalRef = useRef<HTMLDivElement>(null)
  const isTopModal = useCallback(() => manager.isTopModal(modalRef), [])
  const getDoc = () => ownerDocument(modalRef.current)

  const handleExited = useCallback(() => {
    setExited(true)
  }, [setExited])

  const handleEnter = useCallback(() => {
    setExited(false)
  }, [setExited])

  const handleMounted = () => {
    manager.mount(modalRef)
  }

  const handleOpen = useEventCallback(() => {
    const resolvedContainer = getContainer(container) ?? getDoc().body

    manager.add(modalRef, resolvedContainer as HTMLElement, onClose)

    if (modalRef.current) {
      handleMounted()
    }
  })

  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
    e.stopPropagation()

    if (rest.onClick) {
      rest.onClick(e)
    }
  }

  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
    if (e.key !== 'Escape' || disableEscapeKeyDown) {
      return
    }

    // If its not the top modal this event is not for this modal
    if (!isTopModal()) {
      return
    }

    // If the event is for this modal it will not pass it to anyone else
    e.stopPropagation()
    onClose()

    if (rest.onKeyDown) {
      rest.onKeyDown(e)
    }
  }

  const handleClose = useCallback(() => {
    manager.remove(modalRef)
  }, [])

  useEffect(() => {
    if (open) {
      handleOpen()
    } else if (exited) {
      handleClose()
    }
  }, [exited, handleClose, handleOpen, open])

  // This is needed to prevent the modal from keeping this class if you
  // change the route and don't close the modal
  useEffect(() => {
    return () => {
      handleClose()
    }
  }, [handleClose])

  if (!open && exited) {
    return null
  }

  const childProps: Record<string, any> = {}

  if (children.props.tabIndex === undefined) {
    childProps.tabIndex = '-1'
  }

  childProps.onEnter = createChainedFunction(
    handleEnter,
    children.props.onEnter
  )
  childProps.onExited = createChainedFunction(
    handleExited,
    children.props.onExited
  )

  return (
    <Portal container={container}>
      <div
        {...rest}
        className={classnames(handles.modal, props.className)}
        ref={modalRef}
        role="presentation"
        onClick={handleClick}
        onKeyDown={handleKeyDown}
        style={inlineStyles.container}
        data-testid="base-modal"
      >
        <TrapFocus open={open}>
          {React.cloneElement(children, childProps)}
        </TrapFocus>
        {backdrop !== 'none' && (
          <Backdrop
            open={open}
            onClick={onBackdropClick}
            handles={props.handles}
          />
        )}
      </div>
    </Portal>
  )
}

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useState } from 'react'
import type { ReactNode } from 'react'
import { useIntl } from 'react-intl'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'
import { usePixelEventCallback } from 'vtex.pixel-manager'
import type { PixelEventTypes } from 'vtex.pixel-manager'

import {
  useModalDispatch,
  ModalContextProvider,
} from './components/ModalContext'

const CSS_HANDLES = ['triggerContainer'] as const

type TriggerMode = 'click' | 'load' | 'load-session' | 'event'

interface Props {
  trigger?: TriggerMode
  customPixelEventId?: string
  customPixelEventName?: PixelEventTypes.PixelData['event']
  children: ReactNode
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

function ModalTrigger(props: Props) {
  const {
    children,
    trigger = 'click',
    customPixelEventId,
    customPixelEventName,
    classes,
  } = props

  const intl = useIntl()
  const dispatch = useModalDispatch()
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const [openOnLoad, setOpenOnLoad] = useState(false)

  usePixelEventCallback({
    eventId: customPixelEventId,
    eventName: customPixelEventName,
    handler: () => {
      dispatch({ type: 'OPEN_MODAL' })
    },
  })

  useEffect(() => {
    if (openOnLoad || !dispatch) {
      return
    }

    if (trigger === 'load-session') {
      if (sessionStorage.getItem('hasOpenedModal') === 'true') {
        return
      }

      sessionStorage.setItem('hasOpenedModal', 'true')
    }

    if (trigger !== 'load-session' && trigger !== 'load') {
      return
    }

    dispatch({ type: 'OPEN_MODAL' })
    setOpenOnLoad(true)
  }, [trigger, dispatch, openOnLoad])

  const handleModalOpen = (e: React.MouseEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    if (dispatch) {
      dispatch({ type: 'OPEN_MODAL' })
    }
  }

  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
    if (e.key !== 'Enter') {
      return
    }

    e.stopPropagation()
    if (dispatch) {
      dispatch({ type: 'OPEN_MODAL' })
    }
  }

  if (trigger === 'click') {
    return (
      <div
        tabIndex={0}
        role="button"
        aria-label={intl.formatMessage({
          id: 'store/modal-layout.modal-trigger.aria-label',
          defaultMessage: 'Open modal'
        })}
        onKeyDown={handleKeyDown}
        onClick={handleModalOpen}
        className={`${handles.triggerContainer} bg-transparent pa0 bw0 dib`}
      >
        {children}
      </div>
    )
  }

  return <>{children}</>
}

function EnhancedModalTrigger(props: Props) {
  return (
    <ModalContextProvider>
      <ModalTrigger {...props}>{props.children}</ModalTrigger>
    </ModalContextProvider>
  )
}

export default EnhancedModalTrigger

```


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

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "lint": "tsc --noEmit && eslint --quiet --fix --ext ts,tsx .",
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "classnames": "^2.2.6",
    "react": "^16.8.3",
    "react-cookie": "^4.0.3",
    "react-dom": "^16.8.3",
    "react-intl": "^4.5.5",
    "react-transition-group": "^4.4.1"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/classnames": "^2.2.7",
    "@types/jest": "^25.1.4",
    "@types/node": "^13.9.8",
    "@types/react": "^16.9.31",
    "@types/react-dom": "^16.9.10",
    "@types/react-transition-group": "^4.4.0",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.4.4",
    "apollo-cache-inmemory": "^1.6.5",
    "graphql": "^14.6.0",
    "history": "5",
    "typescript": "3.9.7",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@1.0.0/public/@types/vtex.css-handles",
    "vtex.native-types": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.native-types@0.7.5/public/@types/vtex.native-types",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.6.1/public/@types/vtex.pixel-manager",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.126.6/public/@types/vtex.render-runtime",
    "vtex.responsive-values": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.responsive-values@0.4.0/public/@types/vtex.responsive-values",
    "vtex.store-icons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-icons@0.18.0/public/@types/vtex.store-icons"
  },
  "version": "0.14.2"
}

```


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

[User] Show me the implementation of modal-layout/react/ModalContext.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import {
  useModalDispatch,
  ModalContextProvider,
} from './components/ModalContext'

export default { useModalDispatch, ModalContextProvider }

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { useCallback } from 'react'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'
import { FormattedMessage, defineMessages } from 'react-intl'

import Button from './components/Button'
import { useModalDispatch } from './components/ModalContext'

const CSS_HANDLES = ['closeButton', 'closeButtonLabel'] as const

interface Props {
  label?: string
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

function CloseButton({ label, classes }: Props) {
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const dispatch = useModalDispatch()

  const handleClick = useCallback(() => {
    dispatch({ type: 'CLOSE_MODAL' })
  }, [dispatch])

  const buttonClasses = {
    button: handles.closeButton,
    label: handles.closeButtonLabel,
  }

  return (
    <Button handles={buttonClasses} onClick={handleClick}>
      {label ?? (
        <FormattedMessage id="store/modal-layout.close-button.default-label" />
      )}
    </Button>
  )
}

defineMessages({
  title: {
    id: 'admin/editor.modal-layout.close-button.title',
  },
  labelTitle: {
    id: 'admin/editor.modal-layout.close-button.label.title',
  },
  labelDescription: {
    id: 'admin/editor.modal-layout.close-button.label.description',
  },
})

CloseButton.schema = {
  title: 'admin/editor.modal-layout.close-button.title',
}

export default CloseButton

```


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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { PropsWithChildren } from 'react'
import classnames from 'classnames'
import { IconClose } from 'vtex.store-icons'
import { useCssHandles } from 'vtex.css-handles'
import type { CssHandlesTypes } from 'vtex.css-handles'
import { useResponsiveValue } from 'vtex.responsive-values'
import type { ResponsiveValuesTypes } from 'vtex.responsive-values'

import styles from './styles.css'
import { useModalDispatch } from './components/ModalContext'

const CSS_HANDLES = [
  'headerContainer',
  'closeButton',
  'headerContent',
  'closeButtonContainer',
] as const

interface Props {
  showCloseButton?: ResponsiveValuesTypes.ResponsiveValue<boolean>
  iconCloseSize?: number
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

export default React.memo(function ModalHeader(
  props: PropsWithChildren<Props>
) {
  const {
    children,
    iconCloseSize = 32,
    showCloseButton: showCloseButtonProp = true,
    classes,
  } = props

  const showCloseButton = useResponsiveValue(showCloseButtonProp)
  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const dispatch = useModalDispatch()

  const handleClose = () => {
    if (dispatch) {
      dispatch({
        type: 'CLOSE_MODAL',
      })
    }
  }

  const hasChildren = Boolean(children)
  const headerContainerClasses = classnames(
    styles.headerContainer,
    handles.headerContainer,
    'flex items-start bb b--muted-3 flex-shrink-0 flex-grow-0 z-5',
    {
      'justify-between': hasChildren,
      'justify-end': !hasChildren,
    }
  )

  return (
    <div className={headerContainerClasses}>
      {hasChildren && <div className={handles.headerContent}>{children}</div>}
      {showCloseButton && (
        <div className={handles.closeButtonContainer}>
          <button
            onClick={handleClose}
            className={`${handles.closeButton} ma0 bg-transparent pointer bw0 pa3`}
          >
            <IconClose size={iconCloseSize} type="line" />
          </button>
        </div>
      )}
    </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 modal-layout/react/Modal.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { PropsWithChildren } from 'react'
import classnames from 'classnames'
import type { CssHandlesTypes } from 'vtex.css-handles'
import { useCssHandles } from 'vtex.css-handles'
import type { ResponsiveValuesTypes } from 'vtex.responsive-values'
import { useResponsiveValues } from 'vtex.responsive-values'
import { usePixelEventCallback } from 'vtex.pixel-manager'
import type { PixelEventTypes } from 'vtex.pixel-manager'

import styles from './styles.css'
import BaseModal, { CSS_HANDLES as BaseModalCssHandles } from './BaseModal'
import Fade from './components/Animations/Fade'
import type { BackdropMode } from './components/Backdrop'
import { useModalState, useModalDispatch } from './components/ModalContext'
import { useUrlChange } from './modules/useUrlChange'

export type ScrollMode = 'body' | 'content'

const CSS_HANDLES = [
  'modal',
  'paper',
  'topRow',
  'container',
  'closeButton',
  ...BaseModalCssHandles,
] as const

interface Props {
  scroll?: ScrollMode
  blockClass?: string
  disableEscapeKeyDown?: boolean
  customPixelEventId?: string
  customPixelEventName?: PixelEventTypes.PixelData['event']
  fullScreen?: ResponsiveValuesTypes.ResponsiveValue<boolean>
  backdrop?: ResponsiveValuesTypes.ResponsiveValue<BackdropMode>
  classes?: CssHandlesTypes.CustomClasses<typeof CSS_HANDLES>
}

function Modal(props: PropsWithChildren<Props>) {
  const {
    children,
    classes,
    scroll = 'content',
    customPixelEventId,
    customPixelEventName,
    disableEscapeKeyDown = false,
  } = props

  const { fullScreen = false, backdrop = 'clickable' } = useResponsiveValues({
    backdrop: props.backdrop,
    fullScreen: props.fullScreen,
  })

  const { handles } = useCssHandles(CSS_HANDLES, { classes })
  const { open } = useModalState()
  const dispatch = useModalDispatch()

  usePixelEventCallback({
    eventId: customPixelEventId,
    eventName: customPixelEventName,
    handler: () => {
      dispatch({ type: 'CLOSE_MODAL' })
    },
  })

  const handleClose = () => {
    if (dispatch) {
      dispatch({
        type: 'CLOSE_MODAL',
      })
    }
  }

  // Close modal when url changes
  useUrlChange(
    {
      fn: () => {
        dispatch({
          type: 'CLOSE_MODAL',
        })
      },
      skip: !open,
    },
    [open, dispatch]
  )

  const handleBackdropClick = (e: React.MouseEvent) => {
    // Prevent clicking inside the modal and closing it
    // this way it will close only if you click in the backdrop
    if (e.target !== e.currentTarget) {
      return
    }

    if (backdrop === 'clickable') {
      handleClose()
    }
  }

  const containerClasses = classnames(handles.container, 'outline-0 h-100', {
    'overflow-y-auto overflow-x-hidden tc': scroll === 'body',
    'flex items-center justify-center': scroll === 'content',
  })

  const paperClasses = classnames(handles.paper, 'bg-base relative br2', {
    [styles.paperNotFullScreen]: !fullScreen,
    'dib tl v-mid': scroll === 'body',
    'h-100': fullScreen && scroll === 'content',
    'min-h-100': fullScreen && scroll === 'body',
    [`${styles.fullScreenModal} w-100 mw-100 br0`]: fullScreen,
    [styles.paperScrollContent]: !fullScreen && scroll === 'content',
    [`${styles.paperScrollContent} flex flex-column`]: scroll === 'content',
  })

  return (
    <BaseModal
      handles={handles}
      open={open}
      backdrop={backdrop}
      onClose={handleClose}
      onBackdropClick={handleBackdropClick}
      disableEscapeKeyDown={disableEscapeKeyDown}
    >
      <Fade in={open}>
        {
          /* click-events-have-key-events is disabled because this will be handled by BaseModal */
          /* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
          <div
            tabIndex={-1}
            className={containerClasses}
            onClick={handleBackdropClick}
          >
            <div className={paperClasses}>{children}</div>
          </div>
        }
      </Fade>
    </BaseModal>
  )
}

const ModalRef = React.memo(Modal)

export default ModalRef

```


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

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "CloseButton": {
      "title": "admin/editor.modal-layout-close-button.title",
      "properties": {
        "label": {
          "title": "admin/editor.modal-layout.close-button.label.title",
          "description": "admin/editor.modal-layout.close-button.label.description",
          "$ref": "app:vtex.native-types#/definitions/text"
        }
      }
    }
  }
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "modal-layout": {
    "component": "Modal",
    "composition": "children"
  },
  "modal-trigger": {
    "component": "ModalTrigger",
    "composition": "children"
  },
  "modal-header": {
    "component": "ModalHeader",
    "composition": "children"
  },
  "modal-content": {
    "component": "ModalContent",
    "composition": "children"
  },
  "modal-actions": {
    "component": "ModalActions",
    "composition": "children"
  },
  "modal-actions.close": {
    "component": "CloseButton",
    "content": {
      "$ref": "app:vtex.modal-layout#/definitions/CloseButton"
    }
  }
}

```


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

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const css: Record<string, any>
  export default css
}

```


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

[Assistant]
Here's the implementation:

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

  const value: DocumentNode
  export default value
}

```


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

[User] Show me the implementation of modal-layout/react/components/Backdrop.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { PropsWithChildren } from 'react'
import type { TransitionProps } from 'react-transition-group/Transition'
import type { CssHandlesTypes } from 'vtex.css-handles'

import Fade from './Animations/Fade'
import styles from '../styles.css'

export type BackdropMode = 'display' | 'clickable' | 'none'

export const CSS_HANDLES = ['backdropContainer', 'backdrop'] as const

interface Props {
  open: boolean
  transitionDuration?: TransitionProps['timeout']
  onClick?: (e: React.MouseEvent<HTMLDivElement>) => void
  handles: CssHandlesTypes.CssHandles<typeof CSS_HANDLES>
}

function Backdrop(props: PropsWithChildren<Props>) {
  const { children, open, onClick, transitionDuration, handles } = props
  const nodeRef = React.useRef<HTMLDivElement>(null)

  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
    if (onClick) {
      onClick(e)
    }
  }

  return (
    <Fade in={open} timeout={transitionDuration} ref={nodeRef}>
      <div
        className={`${handles.backdropContainer} ${styles.backdropContainer}`}
        data-testid="modal-backdrop-container"
      >
        <div
          role="presentation"
          onClick={handleClick}
          className={`${handles.backdrop} bg-base--inverted o-50 h-100`}
        >
          {children}
        </div>
      </div>
    </Fade>
  )
}

export default React.memo(Backdrop)

```


[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 modal-layout/react/components/ModalContext.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { createContext, useReducer, useContext } from 'react'
import type { PropsWithChildren } from 'react'

interface State {
  open: boolean
  endOfContent: boolean
}

const DEFAULT_STATE = {
  open: false,
  endOfContent: false,
}

interface OpenAction {
  type: 'OPEN_MODAL'
}

interface CloseAction {
  type: 'CLOSE_MODAL'
}

interface SetEndOfContentAction {
  type: 'SET_END_OF_CONTENT'
  payload: { endOfContent: boolean }
}

type Action = OpenAction | CloseAction | SetEndOfContentAction
export type Dispatch = (action: Action) => void

const ModalStateContext = createContext<State>(DEFAULT_STATE)

// eslint-disable-next-line @typescript-eslint/no-empty-function
export const ModalDispatchContext = createContext<Dispatch>(() => {})

// eslint-disable-next-line @typescript-eslint/default-param-last
function modalContextReducer(state: State = DEFAULT_STATE, action: Action) {
  switch (action.type) {
    case 'OPEN_MODAL':
      return {
        ...state,
        open: true,
      }

    case 'CLOSE_MODAL':
      return {
        ...state,
        open: false,
      }

    case 'SET_END_OF_CONTENT':
      return {
        ...state,
        endOfContent: action.payload.endOfContent,
      }

    default:
      return state
  }
}

interface ContextProviderProps {
  initialState?: State
}

export function ModalContextProvider({
  children,
  initialState = undefined,
}: PropsWithChildren<ContextProviderProps>) {
  const [state, dispatch] = useReducer(
    modalContextReducer,
    initialState ?? DEFAULT_STATE
  )

  return (
    <ModalStateContext.Provider value={state}>
      <ModalDispatchContext.Provider value={dispatch}>
        {children}
      </ModalDispatchContext.Provider>
    </ModalStateContext.Provider>
  )
}

export function useModalDispatch() {
  const context = useContext(ModalDispatchContext)

  return context
}

export function useModalState() {
  const context = useContext(ModalStateContext)

  if (typeof context === 'undefined') {
    throw Error('useModalState must be used within a ModalStateContext')
  }

  return context
}

```


[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 modal-layout/react/components/Portal.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type React from 'react'
import { useState, forwardRef } from 'react'
import ReactDOM from 'react-dom'

import setRef from '../modules/setRef'
import useEnhancedEffect from '../modules/useEnhancedEffect'

export type ContainerType =
  | React.ReactInstance
  | (() => React.ReactInstance | null)
  | null

interface Props {
  children: React.ReactNode
  container?: ContainerType
}

export function getContainer(container?: ContainerType) {
  container = typeof container === 'function' ? container() : container

  if (!container) {
    return null
  }

  // eslint-disable-next-line react/no-find-dom-node
  return ReactDOM.findDOMNode(container) as Element | null
}

const Portal = forwardRef(function Portal(props: Props, ref) {
  const { children, container } = props
  const [mountNode, setMountNode] = useState<Element | null>(null)

  useEnhancedEffect(() => {
    setMountNode(getContainer(container) ?? document.body)
  }, [container])

  useEnhancedEffect(() => {
    if (mountNode) {
      setRef(ref, mountNode)

      return () => {
        setRef(ref, null)
      }
    }

    return undefined
  }, [ref, mountNode])

  return mountNode ? ReactDOM.createPortal(children, mountNode) : mountNode
})

export default Portal

```


[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 modal-layout/react/components/Button.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import classnames from 'classnames'

import useButtonClasses from '../modules/useButtonClasses'

interface AllClasses {
  button: string
  label: string
}

interface Props
  extends React.DetailedHTMLProps<
    React.ButtonHTMLAttributes<HTMLButtonElement>,
    HTMLButtonElement
  > {
  children: React.ReactNode
  handles?: Partial<AllClasses>
}

function Button(props: Props) {
  const { children, handles = {}, className, ...rest } = props
  const buttonClasses = useButtonClasses()

  const rootClasses = classnames(
    className,
    handles.button,
    buttonClasses.container
  )

  const labelClasses = classnames(handles.label, buttonClasses.label)

  return (
    <button className={rootClasses} {...rest}>
      <span className={labelClasses}>{children}</span>
    </button>
  )
}

export default Button

```


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

[User] Show me the implementation of modal-layout/react/components/TrapFocus.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

interface Props {
  children: React.ReactElement
  open: boolean
}

const TrapFocus: React.FC<Props> = (props) => {
  const { children, open } = props
  const childRef = useRef<HTMLElement>()

  useEffect(() => {
    if (open && childRef.current) {
      childRef.current.focus()
    }
  }, [open])

  return <>{React.cloneElement(children, { ref: childRef })}</>
}

export default TrapFocus

```


[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 modal-layout/react/__tests__/CloseButton.test.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

import CloseButton from '../CloseButton'
import { ModalDispatchContext } from '../components/ModalContext'

describe('<CloseButton />', () => {
  it('should render the close button with the label', () => {
    const { queryByText } = render(<CloseButton label="Hello VTEX" />)

    expect(queryByText('Hello VTEX')).toBeTruthy()
  })

  it('should close the modal when clicked', () => {
    const dispatchSpy = jest.fn()

    const { getByText } = render(
      <ModalDispatchContext.Provider value={dispatchSpy}>
        <CloseButton label="close button" />
      </ModalDispatchContext.Provider>
    )

    const closeButtonLabelEl = getByText('close button')

    fireEvent.click(closeButtonLabelEl, {
      bubbles: true,
      cancelable: true,
    })

    expect(dispatchSpy).toBeCalledTimes(1)
    expect(dispatchSpy).toBeCalledWith({ type: 'CLOSE_MODAL' })
  })
})

```


[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 modal-layout/react/__tests__/Backdrop.test.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

// eslint-disable-next-line jest/no-mocks-import
import { findCSSHandles } from '../__mocks__/testUtils'
import Backdrop, { CSS_HANDLES } from '../components/Backdrop'

const handles = {
  backdropContainer: 'backdropContainer',
  backdrop: 'backdrop',
}

describe('<Backdrop />', () => {
  it('should render', () => {
    const { baseElement } = render(<Backdrop open handles={handles} />)

    expect(baseElement).toBeTruthy()
  })

  it('should find all declared handles', () => {
    const { container } = render(<Backdrop open handles={handles} />)

    const foundHandles = findCSSHandles(container, CSS_HANDLES)

    expect(foundHandles).toEqual(CSS_HANDLES)
  })

  it('should have visibility hidden and opacity 0 if open === false', () => {
    const { getByTestId } = render(<Backdrop open={false} handles={handles} />)

    const container = getByTestId('modal-backdrop-container')

    expect(container.style.getPropertyValue('opacity')).toBe('0')
    expect(container.style.getPropertyValue('visibility')).toBe('hidden')
  })

  it('should call onClick when backdrop is clicked', () => {
    const spy = jest.fn()
    const { getByRole } = render(
      <Backdrop open onClick={spy} handles={handles} />
    )

    const backdropElement = getByRole('presentation')

    fireEvent.click(backdropElement, { bubbles: true, cancelable: true })

    expect(spy).toBeCalledTimes(1)
  })

  it('should have a role="presentation"', () => {
    const spy = jest.fn()
    const { queryByRole } = render(
      <Backdrop open onClick={spy} handles={handles} />
    )

    const container = queryByRole('presentation')

    expect(container).toBeTruthy()
  })
})

```


[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 modal-layout/react/__tests__/BaseModal.test.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

import BaseModal from '../BaseModal'
import Fade from '../components/Animations/Fade'

const handles = {
  modal: 'modal',
  backdropContainer: 'backdropContainer',
  backdrop: 'backdrop',
}

describe('<BaseModal />', () => {
  it('should render the modal with the children', () => {
    const onClose = jest.fn()
    const { queryByText, queryByRole } = render(
      <BaseModal open onClose={onClose} backdrop="none" handles={handles}>
        <Fade in>
          <div>Hello VTEX</div>
        </Fade>
      </BaseModal>
    )

    expect(queryByText('Hello VTEX')).toBeTruthy()
    expect(queryByRole('presentation')).toBeTruthy()
  })

  it("shouldn't render anything if open is false", () => {
    const { queryByText, queryByRole } = render(
      <BaseModal open={false} onClose={() => {}} handles={handles}>
        <Fade in>
          <div>Hello VTEX</div>
        </Fade>
      </BaseModal>
    )

    expect(queryByText('Hello VTEX')).toBeNull()
    expect(queryByRole('presentation')).toBeNull()
  })

  it('should call onClose if Esc is pressed', () => {
    const onClose = jest.fn()
    const { getByRole } = render(
      <BaseModal open onClose={onClose} backdrop="none" handles={handles}>
        <Fade in>
          <div>Hello VTEX</div>
        </Fade>
      </BaseModal>
    )

    fireEvent.keyDown(getByRole('presentation'), {
      key: 'Escape',
      code: 27,
    })

    expect(onClose).toBeCalledTimes(1)
  })

  it("shouldn't call onClose if disableEscapeKeyDown", () => {
    const onClose = jest.fn()
    const { getByTestId } = render(
      <BaseModal open onClose={onClose} disableEscapeKeyDown handles={handles}>
        <Fade in>
          <div data-testid="base-modal-child">Hello VTEX</div>
        </Fade>
      </BaseModal>
    )

    fireEvent.keyDown(getByTestId('base-modal-child'), {
      key: 'Escape',
      code: 27,
    })

    expect(onClose).not.toBeCalled()
  })

  it('should have role="presentation"', () => {
    const onClose = jest.fn()
    const { queryByRole } = render(
      <BaseModal open onClose={onClose} backdrop="none" handles={handles}>
        <Fade in>
          <div>Hello VTEX</div>
        </Fade>
      </BaseModal>
    )

    expect(queryByRole('presentation')).toBeTruthy()
  })

  it('should not propagate click events to outside of the modal', () => {
    const onClose = jest.fn()
    const outsideClick = jest.fn()
    const onClick = jest.fn()

    const { getByTestId } = render(
      // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
      <div onClick={outsideClick}>
        <BaseModal open onClick={onClick} onClose={onClose} handles={handles}>
          <Fade in>
            <div>Hello VTEX</div>
          </Fade>
        </BaseModal>
      </div>
    )

    const baseModal = getByTestId('base-modal')

    fireEvent.click(baseModal, {
      bubbles: true,
      cancelable: true,
    })

    expect(onClick).toBeCalledTimes(1)
    expect(outsideClick).not.toBeCalled()
  })
})

```


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

[Assistant]
Here's the implementation:

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

import useEnhancedEffect from './useEnhancedEffect'

// https://github.com/facebook/react/issues/14099#issuecomment-440013892
// eslint-disable-next-line @typescript-eslint/ban-types
export default function useEventCallback(fn: Function) {
  const ref = useRef(fn)

  useEnhancedEffect(() => {
    ref.current = fn
  })

  return useCallback((...args) => ref.current(...args), [])
}

```


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

[Assistant]
Here's the implementation:

```typescript
// This code comes form the vtex.store-link hook
// to add classes of the styleguide button to a
// element. We might have a component to share
// this code between apps in a future
// https://github.com/vtex-apps/store-link/blob/master/react/modules/useButtonClasses.ts

import { useMemo } from 'react'
import classnames from 'classnames'

// for now this are the only necessary variant and sizes
type Size = 'regular'
type Variant = 'secondary'

interface ButtonProps {
  variant: Variant
  size: Size
}

interface AllOptions {
  variant: ButtonProps['variant']
  disabled: boolean
  size: ButtonProps['size']
}

type Options = Partial<AllOptions>

const SECONDARY_DISABLED = ''
const SECONDARY_ENABLED =
  'bg-action-secondary b--action-secondary c-on-action-secondary hover-bg-action-secondary hover-b--action-secondary hover-c-on-action-secondary'

const BASE_CONTAINER_CLASSES = 'bw1 fw5 ba v-mid pa0 lh-solid br2 pointer'
const LABEL_BASE = 'w-100 tc'

const REGULAR = 'min-h-regular t-action'

const LABEL_REGULAR = 'ph6'

function getClassesByVariant(
  variant: ButtonProps['variant'],
  disabled: boolean
) {
  let container

  switch (variant) {
    case 'secondary':
      container = disabled ? SECONDARY_DISABLED : SECONDARY_ENABLED

    // no default
  }

  return { container }
}

function getClassesBySize(size: ButtonProps['size']) {
  let container
  let label

  switch (size) {
    default:
      container = REGULAR
      label = LABEL_REGULAR
  }

  return { container, label }
}

export default function useButtonClasses(options: Options = {}) {
  const { variant = 'secondary', disabled = false, size = 'regular' } = options

  return useMemo(() => {
    const variantClasses = getClassesByVariant(variant, disabled)
    const sizeClasses = getClassesBySize(size)
    const classes = {
      container: classnames(
        BASE_CONTAINER_CLASSES,
        variantClasses.container,
        sizeClasses.container
      ),
      label: classnames(LABEL_BASE, sizeClasses.label),
    }

    return classes
  }, [variant, disabled, size])
}

```


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

[Assistant]
Here's the implementation:

```typescript
import type { RefObject } from 'react'

import ownerDocument from './ownerDocument'
import ownerWindow from './ownerWindow'
import getScrollbarSize from './getScrollbarSize'
import styles from '../styles.css'

export type ModalRef = RefObject<HTMLDivElement | null>
type ProcedureFn = () => void
type OnClose = ProcedureFn

export interface ContainerInfo {
  container: HTMLElement
  modals: ModalRef[]
  restore: ProcedureFn | null
}

function getPaddingRight(node: HTMLElement) {
  return parseInt(window.getComputedStyle(node).paddingRight, 10) || 0
}

function isOverflowing(container: HTMLElement) {
  const doc = ownerDocument(container)

  if (doc.body === container) {
    return ownerWindow(doc).innerWidth > doc.documentElement.clientWidth
  }

  return container.scrollHeight > container.clientHeight
}

interface RestoreStyle {
  value: string
  el: HTMLElement
  key: string | 'className'
}

type FindIndexOfCallback = (item: ContainerInfo) => boolean
function findIndexOf(
  containerInfo: ContainerInfo[],
  callback: FindIndexOfCallback
) {
  let idx = -1

  containerInfo.some((item, index) => {
    if (callback(item)) {
      idx = index

      return true
    }

    return false
  })

  return idx
}

function handleContainer(containerInfo: ContainerInfo) {
  const { container } = containerInfo
  const restoreStyle: RestoreStyle[] = []

  if (isOverflowing(container)) {
    const scrollbarSize = getScrollbarSize()

    restoreStyle.push({
      value: container.style.paddingRight,
      key: 'padding-right',
      el: container,
    })

    container.style.paddingRight = `${
      getPaddingRight(container) + scrollbarSize
    }px`
  }

  // https://css-tricks.com/snippets/css/force-vertical-scrollbar/
  const parent = container.parentElement
  const scrollContainer =
    parent?.nodeName === 'HTML' &&
    window.getComputedStyle(parent).overflowY === 'scroll'
      ? parent
      : container

  restoreStyle.push({
    value: styles.hiddenContainer,
    key: 'className',
    el: scrollContainer,
  })

  scrollContainer.classList.add(styles.hiddenContainer)

  const restore = () => {
    restoreStyle.forEach(({ value, el, key }) => {
      if (key === 'className') {
        el.classList.remove(styles.hiddenContainer)
      } else if (value) {
        el.style.setProperty(key, value)
      } else {
        el.style.removeProperty(key)
      }
    })
  }

  return restore
}

/**
 * Class used to manage the open modals and to close
 * them when the route change with the 'CLOSE_MODAL'
 * action
 */
export default class ModalManager {
  private modals: ModalRef[]
  private containers: ContainerInfo[]
  private closeMethods: OnClose[]

  constructor() {
    this.modals = []
    this.closeMethods = []
    this.containers = []
  }

  public add(modal: ModalRef, container: HTMLElement, onClose: OnClose) {
    let modalIndex = this.modals.indexOf(modal)

    if (modalIndex !== -1) {
      return modalIndex
    }

    modalIndex = this.modals.length
    this.modals.push(modal)
    this.closeMethods.push(onClose)
    const containerIndex = findIndexOf(
      this.containers,
      (item) => item.container === container
    )

    if (containerIndex !== -1) {
      this.containers[containerIndex].modals.push(modal)

      return modalIndex
    }

    this.containers.push({
      modals: [modal],
      container,
      restore: null,
    })

    return modalIndex
  }

  public mount(modal: ModalRef) {
    const containerIndex = findIndexOf(
      this.containers,
      (item) => item.modals.indexOf(modal) !== -1
    )

    const containerInfo = this.containers[containerIndex]

    if (!containerInfo.restore) {
      containerInfo.restore = handleContainer(containerInfo)
    }
  }

  public remove(modal: ModalRef) {
    const modalIndex = this.modals.indexOf(modal)

    if (modalIndex === -1) {
      return
    }

    const containerIndex = findIndexOf(
      this.containers,
      (item) => item.modals.indexOf(modal) !== -1
    )

    const containerInfo = this.containers[containerIndex]

    this.modals.splice(modalIndex, 1)
    this.closeMethods.splice(modalIndex, 1)
    containerInfo.modals.splice(containerInfo.modals.indexOf(modal), 1)

    if (containerInfo.modals.length === 0) {
      if (containerInfo.restore) {
        containerInfo.restore()
      }

      this.containers.splice(containerIndex, 1)
    }

    return modalIndex
  }

  public removeTopModal() {
    if (this.modals.length === 0) {
      return -1
    }

    return this.remove(this.modals[this.modals.length - 1])
  }

  public isTopModal(modal: ModalRef) {
    return (
      this.modals.length > 0 && this.modals[this.modals.length - 1] === modal
    )
  }
}

```


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

[Assistant]
Here's the implementation:

```typescript
// mock function from ramda

type PickFnType = <T, K extends string>(
  names: readonly K[],
  obj: T
) => Pick<T, Exclude<keyof T, Exclude<keyof T, K>>>

const pick: PickFnType = (names, obj) => {
  const result: any = {}

  names.forEach((name) => {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    result[name] = obj[name]
  })

  return result
}

export default pick

```


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

[Assistant]
Here's the implementation:

```typescript
import ownerDocument from './ownerDocument'

type NodeType = HTMLElement | Document | null | undefined
export default function ownerWindow(node: NodeType) {
  const doc = ownerDocument(node)

  return doc.defaultView ?? window
}

```


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

[User] Show me the implementation of modal-layout/react/modules/useIntersection.ts from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

interface Params {
  intersectionRef: React.MutableRefObject<IntersectionObserver | null>
  sentinelRef: React.RefObject<HTMLDivElement | null>
  callback: (isIntersecting: boolean) => void
}

export default function useIntersection(params: Params) {
  const { callback, intersectionRef, sentinelRef } = params
  const handleIntersection: IntersectionObserverCallback = useCallback(
    (entries) => {
      if (entries[0]) {
        callback(entries[0].isIntersecting)
      }
    },
    [callback]
  )

  useEffect(() => {
    // If we are in IE11 this might break if we don't check
    if (IntersectionObserver) {
      intersectionRef.current = new IntersectionObserver(handleIntersection)
      if (sentinelRef.current) {
        intersectionRef.current.observe(sentinelRef.current)
      }
    }

    return () => {
      if (intersectionRef.current) {
        intersectionRef.current.disconnect()
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [handleIntersection])
}

```


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

[Assistant]
Here's the implementation:

```typescript
type NodeType = HTMLElement | Document | null | undefined
export default function ownerDocument(node: NodeType) {
  return node?.ownerDocument ?? window.document
}

```


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

[Assistant]
Here's the implementation:

```typescript
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ChainedFunction = (...args: any[]) => void
export type MaybeChainedFunction = ChainedFunction | undefined | null

// eslint-disable-next-line @typescript-eslint/no-empty-function
export const noop = () => {}

export default function createChainedFunction(
  ...funcs: MaybeChainedFunction[]
) {
  return funcs.reduce((acc: ChainedFunction, func) => {
    if (!func || typeof func !== 'function') {
      return acc
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return function chainedFunction(...args: any) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore 'this' has implicit type any and there is no way to type this here
      acc.apply(this, args)
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      func.apply(this, args)
    }
  }, 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 modal-layout/react/modules/useForkRef.ts from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

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

import setRef from './setRef'

export function useForkRef<T>(
  refA: React.Ref<T>,
  refB: React.Ref<T>
): React.Ref<T> {
  return useMemo(() => {
    if (!refA && !refB) {
      return null
    }

    return (refValue) => {
      setRef(refA, refValue)
      setRef(refB, refValue)
    }
  }, [refA, refB])
}

```


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

[Assistant]
Here's the implementation:

```typescript
export default function setRef<T>(
  ref: React.Ref<T> | ((instance: T | null) => void) | null | undefined,
  value: T | null
) {
  if (typeof ref === 'function') {
    ref(value)
  } else if (ref) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    ;(ref as any).current = value
  }
}

```


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

[User] Show me the implementation of modal-layout/react/modules/getScrollbarSize.ts from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
export default function getScrollbarSize() {
  const scrollDiv = document.createElement('div')

  scrollDiv.style.width = '99px'
  scrollDiv.style.height = '99px'
  scrollDiv.style.position = 'absolute'
  scrollDiv.style.top = '-9999px'
  scrollDiv.style.overflow = 'scroll'

  document.body.appendChild(scrollDiv)
  const scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth

  document.body.removeChild(scrollDiv)

  return scrollbarSize
}

```


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

[Assistant]
Here's the implementation:

```typescript
import { useLayoutEffect, useEffect } from 'react'
import { canUseDOM } from 'vtex.render-runtime'

const useEnhancedEffect = canUseDOM ? useLayoutEffect : useEffect

export default useEnhancedEffect

```


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

[Assistant]
Here's the implementation:

```typescript
import { useCallback, useEffect } from 'react'
import { useRuntime } from 'vtex.render-runtime'
import type { Listener } from 'history'

type Params = {
  fn: Listener
  skip: boolean
}

export const useUrlChange = ({ fn, skip }: Params, deps: unknown[]) => {
  const { history } = useRuntime()

  // Lint is not getting it
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const memoizedCallback = useCallback(fn, deps)

  useEffect(() => {
    if (skip) return

    // cancel method is returned to be executed whenever our deps change
    return history?.listen(memoizedCallback)
  }, [skip, memoizedCallback, history])
}

```


[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 modal-layout/react/components/Animations/Fade.tsx from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Transition } from 'react-transition-group'
import type {
  ExitHandler,
  EnterHandler,
  TransitionProps,
  TransitionStatus,
} from 'react-transition-group/Transition'
import { ENTERED, ENTERING } from 'react-transition-group/Transition'

import { getTransitionProps, createTransition } from './utils'
import { duration } from './transitions'

interface Props {
  in: boolean
  children: React.ReactElement
  timeout?: TransitionProps['timeout']
  onEnter?: EnterHandler<undefined>
  onExit?: ExitHandler<undefined>
}

function getOpacity(state: TransitionStatus) {
  switch (state) {
    case ENTERING:
      return 1

    case ENTERED:
      return 1

    default:
      return 0
  }
}

const defaultTimeout = {
  enter: duration.enteringScreen,
  exit: duration.leavingScreen,
}

const Fade = React.forwardRef(function Fade(props: Props, ref: React.Ref<any>) {
  const {
    onExit,
    onEnter,
    children,
    in: inProp,
    timeout = defaultTimeout,
    ...other
  } = props

  const handleEnter: EnterHandler<undefined> = (
    node: HTMLElement,
    isAppearing: boolean
  ) => {
    const transitionProps = getTransitionProps({ timeout }, { mode: 'enter' })

    // suport for older versions of android browser and safari
    // https://caniuse.com/#feat=css-transitions
    node.style.webkitTransition = createTransition('opacity', transitionProps)
    node.style.transition = createTransition('opacity', transitionProps)

    if (onEnter) {
      onEnter(node, isAppearing)
    }
  }

  const handleExit: ExitHandler<undefined> = (node: HTMLElement) => {
    const transitionProps = getTransitionProps({ timeout }, { mode: 'exit' })

    node.style.webkitTransition = createTransition('opacity', transitionProps)
    node.style.transition = createTransition('opacity', transitionProps)

    if (onExit) {
      onExit(node)
    }
  }

  return (
    <Transition
      appear
      in={inProp}
      timeout={timeout}
      onExit={handleExit}
      onEnter={handleEnter}
      {...other}
    >
      {(state: TransitionStatus) => {
        return React.cloneElement(children, {
          ref,
          style: {
            opacity: getOpacity(state),
            visibility: state === 'exited' && !inProp ? 'hidden' : undefined,
            ...children.props.style,
          },
        })
      }}
    </Transition>
  )
})

export default Fade

```


[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 modal-layout/react/components/Animations/transitions.ts from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const duration = {
  enteringScreen: 250,
  leavingScreen: 218,
  standard: 300,
}

export const easing = {
  easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
  easeOut: 'cubic-bezier(0.0, 0, 0.2, 1)',
  easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
  sharp: 'cubic-bezier(0.4, 0, 0.6, 1)',
}

```


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

[User] Show me the implementation of modal-layout/react/components/Animations/utils.ts from the modal-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type {
  TransitionActions,
  TransitionProps as _TransitionProps,
} from 'react-transition-group/Transition'

import {
  easing as easingFunctions,
  duration as transitionDuration,
} from './transitions'

export type TransitionHandlerKeys = 'onEnter' | 'onExit'

export type TransitionKeys = 'in' | 'timeout' | TransitionHandlerKeys

export type TransitionProps = TransitionActions &
  Partial<Pick<_TransitionProps, TransitionKeys>>

interface TransitionPropsOptions {
  mode: 'enter' | 'exit' | 'appear'
}

interface TransitionCreationOptions {
  duration: number | string
  easing: string
  delay: number | string
}

export function getTransitionProps(
  props: TransitionProps,
  options?: TransitionPropsOptions
) {
  const { timeout } = props

  let duration: number | string | undefined = 0

  if (typeof timeout === 'number') {
    duration = timeout
  } else if (typeof timeout === 'object' && options && timeout[options.mode]) {
    duration = timeout[options.mode]
  }

  return {
    duration,
  }
}

export const formatMs = (milliseconds: number) =>
  `${Math.round(milliseconds)}ms`

export function createTransition(
  props: string | string[] = ['all'],
  options: Partial<TransitionCreationOptions> = {}
) {
  const {
    delay = 0,
    easing = easingFunctions.easeInOut,
    duration = transitionDuration.standard,
  } = options

  return (Array.isArray(props) ? props : [props])
    .map(
      (animatedProp) =>
        `${animatedProp} ${
          typeof duration === 'string' ? duration : formatMs(duration)
        } ${easing} ${typeof delay === 'string' ? delay : formatMs(delay)}`
    )
    .join(',')
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "admin/test": "teste",
  "store/test": "teste"
}
```


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

[Assistant]
Here's the implementation:

```json
{
  "admin/test": "test",
  "store/test": "test"
}

```


[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 challenge-tp-condition/messages/es.json from the challenge-tp-condition VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/test": "teste",
  "store/test": "teste"
}
```


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

[Assistant]
Here's the implementation:

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

# Challenge Trade Policy Condition

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

Used in B2B environments, the Challenge block is a non-rendered block responsible for checking if a user is allowed to access the store's content.

:information_source: This check is made according to the Condition Rule specified in the Trade Policy configuration, one of the steps needed to [**configure a B2B environment in VTEX IO**](https://vtex.io/docs/recipes/store/configuring-a-b2b-environment).

## Configuration

1. Import the app to your theme's dependencies in `manifest.json`, for example:

```json
  "dependencies": {
    // ...
    "vtex.challenge-tp-condition": "0.x"
  }
```

2. Add the  `challenge.trade-policy-condition` block as a `parent` block to the templates of the pages you want to protect, such as:

```diff
 "store.home": {
   "blocks": [
     "shelf#home",
     "flex-layout.row#deals",
     "info-card#home",
     "rich-text#question",
     "rich-text#link",
     "newsletter"
   ],
+   "parent": {
+     "challenge": "challenge.trade-policy-condition"
+   }
 },

```

3. Declare the `challenge.trade-policy-condition`, using its props to define to where the store's users should be redirected according to each scenario. For example:

```json
"challenge.trade-policy-condition": {
  "props": {
    "redirectPath": "/login"
  }
},
```

| Prop name          | Type |    Description   | Default value |
| ------------------------ | ------------- | --------------------- | ----------- |
| `redirectPath`             | `string` | Path to which the not logged in user will be redirected      |  `/login`          | Path to which the not logged in user will be redirected                     |
| `forbiddenRedirectPath`    | `string`    | Path to which the logged in user will be redirected if not allowed access according to the Condition Rule         |   `/login`      |
| `defaultContentVisibility` |   `enum`  |  Whether the store's content should be visible (`visible`) or hidden (`hidden`) while the Challenge block is verifying the user's access permission | `visible` |

:warning: Using `hidden` as the `defaultContentVisibility` value result in the entire page's content being rendered on the client side (in a scenario in which the check concludes that the user has permission to access the store). The page will not be Server Side Rendered (SSR) due to the fact that this verification process is user-based, making it impossible to cache.

## Customization

No CSS Handles are available for the app customization.

<!-- 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 challenge-tp-condition/react/ChallengeTradePolicyCondition.tsx from the challenge-tp-condition VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC, useEffect, Fragment, useState } from 'react'
import {
  useRuntime,
  SessionUnauthorized,
  Session,
  SessionForbidden,
  canUseDOM,
} from 'vtex.render-runtime'

import { getSession } from './modules/session'

type ContentVisibility = 'visible' | 'hidden'

const useRedirect = (condition: boolean, path: string) => {
  const { navigate } = useRuntime()

  useEffect(() => {
    if (!condition) {
      return
    }

    const url = canUseDOM
      ? window.location.pathname +
      (window.location.hash || window.location.search)
      : // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (global as any).__pathname__

    navigate({
      to: `${path}?returnUrl=${encodeURIComponent(url)}`,
    })
  }, [condition, navigate, path])
}

type SessionResponse = Session | SessionUnauthorized | SessionForbidden

const useSessionResponse = () => {
  const [session, setSession] = useState<SessionResponse>()
  const sessionPromise = getSession()

  useEffect(() => {
    if (!sessionPromise) {
      return
    }

    sessionPromise.then(sessionResponse => {
      const response = sessionResponse.response as SessionResponse

      setSession(response)
    })
  }, [sessionPromise])

  return session
}

const isSessionUnauthorized = (
  session: SessionResponse | undefined
): session is SessionUnauthorized =>
  (session as SessionUnauthorized)?.type?.toLowerCase() === 'unauthorized'

const isSessionForbidden = (
  session: SessionResponse | undefined
): session is SessionForbidden =>
  (session as SessionForbidden)?.type?.toLowerCase() === 'forbidden'

interface Props {
  redirectPath: string
  forbiddenRedirectPath: string
  defaultContentVisibility: ContentVisibility
}

const isProfileAllowed = (sessionResponse: SessionResponse | undefined) => {
  if (sessionResponse == null) {
    return null
  }

  const hasAccessToTradePolicy = (sessionResponse as Session).namespaces?.store
    ?.channel
  const isLoggedIn = (sessionResponse as Session).namespaces?.profile?.email

  if (hasAccessToTradePolicy) {
    return 'authorized'
  }
  if (isLoggedIn) {
    return 'forbidden'
  }
  return 'unauthorized'
}

const ChallengeTradePolicyCondition: FC<Props> = ({
  redirectPath = '/login',
  forbiddenRedirectPath = redirectPath,
  defaultContentVisibility = 'visible',
  children,
}) => {
  const sessionResponse = useSessionResponse()
  const isUnauthorized = isSessionUnauthorized(sessionResponse)
  const isForbidden = isSessionForbidden(sessionResponse)
  const profileCondition = isProfileAllowed(sessionResponse)

  useRedirect(
    isUnauthorized === true || profileCondition === 'unauthorized',
    redirectPath
  )
  useRedirect(
    isForbidden === true || profileCondition === 'forbidden',
    forbiddenRedirectPath
  )

  const defaultHidden =
    defaultContentVisibility === 'hidden' && sessionResponse == null

  if (
    defaultHidden ||
    isUnauthorized === true ||
    isForbidden === true ||
    profileCondition === 'unauthorized' ||
    profileCondition === 'forbidden'
  ) {
    return null
  }

  return <Fragment>{children}</Fragment>
}

export default React.memo(ChallengeTradePolicyCondition)

```


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

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "lint": "tsc --noEmit && eslint --quiet --fix --ext ts,tsx .",
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "apollo-client": "^2.6.3",
    "graphql": "^14.5.8",
    "ramda": "^0.26.1",
    "react": "^16.8.6",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.8.6",
    "react-intl": "^2.9.0"
  },
  "devDependencies": {
    "@types/graphql": "^14.5.0",
    "@types/jest": "^24.0.21",
    "@types/node": "^12.12.3",
    "@types/ramda": "^0.26.33",
    "@types/react": "^16.8.22",
    "@types/react-intl": "^2.3.18",
    "@vtex/test-tools": "^0.3.2",
    "@vtex/tsconfig": "^0.2.0",
    "eslint": "^6.8.0",
    "eslint-config-vtex-react": "^6.1.0",
    "prettier": "^1.19.1",
    "prop-types": "^15.7.2",
    "typescript": "3.9.7",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.91.1/public/@types/vtex.render-runtime",
    "vtex.store": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.87.1/public/@types/vtex.store",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.115.0/public/@types/vtex.store-graphql"
  },
  "version": "0.6.1"
}

```


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

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

[Assistant]
Here's the implementation:

```json
{
  "challenge.trade-policy-condition": {
    "component": "ChallengeTradePolicyCondition"
  }
}

```


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

[Assistant]
Here's the implementation:

```typescript
/* Typings for `render-runtime` */
declare module 'vtex.render-runtime' {
  import { Component, ComponentType, ReactElement, ReactType } from 'react'

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

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

  interface ExtensionPointProps {
    id: string
    [key: string]: any
  }

  interface ChildBlock<BlockProps> {
    props: BlockProps
  }

  export const ExtensionPoint: ComponentType<ExtensionPointProps>
  export const useChildBlock: <BlockProps>({
    id,
  }: {
    id: string
  }) => ChildBlock<BlockProps> | null
  export const Helmet: ReactElement
  export const Link: ReactType
  export const NoSSR: ReactElement
  export const RenderContextConsumer: any
  export const TreePathContextConsumer: any
  export const useTreePath: any
  export const useRuntime: any
  export const canUseDOM: boolean
  export const withRuntimeContext: <TOriginalProps extends {}>(
    Component: ComponentType<TOriginalProps & RenderContextProps>
  ) => ComponentType<TOriginalProps>

  export const withSession: <TOriginalProps extends {}>(
    Component: ComponentType<TOriginalProps & RenderContextProps>
  ) => ComponentType<TOriginalProps>

  interface KeyValue {
    value: string
  }

  interface Session {
    id: string
    namespaces: {
      store: {
        channel: string
      }
      profile: {
        isAuthenticated: KeyValue
        email: string
      }
    }
  }

  interface SessionUnauthorized {
    type: 'Unauthorized'
    message: string
  }

  interface SessionForbidden {
    type: 'Forbidden'
    message: string
  }

  export interface RenderSession {
    sessionPromise: Promise<SessionPromise>
  }

  export interface SessionPromise {
    response: Session | SessionUnauthorized | SessionForbidden
  }
}

```


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

[Assistant]
Here's the implementation:

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

  const value: DocumentNode
  export default value
}

```


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

[User] Show me the implementation of challenge-tp-condition/react/__tests__/index.test.tsx from the challenge-tp-condition VTEX app.

[Assistant]
Here's the implementation:

```tsx
describe('Challenge Trade Policy Condition', () => {
  it('should work', () => {
    expect(1).toBe(1)
  })
})

```


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

[User] Show me the implementation of challenge-tp-condition/react/modules/session.ts from the challenge-tp-condition VTEX app.

[Assistant]
Here's the implementation:

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

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

```


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

[User] Show me the implementation of binding-countries/docs/README.md from the binding-countries VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Binding Countries

When this app is installed and configured, render-server will do a redirect to the binding corresponding to the viewer country.

## Configuration

Example:

```json
{
  "bindings": [
    {
      "canonicalBaseAddress": "www.store.com/ar",
      "targetCountries": ["AR"]
    },
    {
      "canonicalBaseAddress": "www.store.com/br",
      "targetCountries": ["BR", "*"]
    },
    {
      "canonicalBaseAddress": "www.store.com/co",
      "targetCountries": ["CO", "CH", "PY", "UY"]
    },
    {
      "canonicalBaseAddress": "www.store.com",
      "targetCountries": null
    }
  ]
}
```

If the request comes from www.store.com it will be redirected to some binding depending on viewer's country (`AR` => `/ar`, `BR` => `/br`, etc.). If there is no specific binding for viewer's country, it will be redirect to the one registered with `wildcard` (`*`), in this case (`CX` => `/br`)
```


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

[User] Show me the implementation of checkout-payment/messages/sl.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Izbrali ste",
  "store/checkout-payment.installmentsButton": "Izberite možnost plačila",
  "store/checkout-payment.creditCardExtraDataMessage": "Zaradi vaše varnosti izpolnite naslednje podatke:",
  "store/checkout-payment.documentLabel": "Dokument imetnika kartice",
  "store/checkout-payment.requiredField": "To polje je obvezno.",
  "store/checkout-payment.invalidDigits": "Neveljavne številke",
  "store/checkout-payment.creditCardLabel": "Kreditna kartica",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Oglejte si možnosti obrokov",
  "store/checkout-payment.installmentsOptionsTitle": "Možnosti obrokov",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {without interest} true {z obrestmi {interestRate}% mesečno}}",
  "store/checkout-payment.installmentsTitle": "Obroki",
  "store/checkout-payment.installmentOptionLabel": "Izberite možnost plačila z obroki",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Spremeni obroke",
  "store/checkout-payment.interestFree": "Brez-obresti",
  "store/checkout-payment.newCreditCardLabel": "Nova kreditna kartica",
  "store/checkout-payment.incompleteCardLabel": "Nepopolna kartica",
  "store/checkout-payment.choosePaymentMethodLabel": "Izberite vaš plačilni način",
  "store/checkout-payment.paymentSummaryCardMessage": "Kreditna kartica, ki se konča s {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Ustvarjeno po nakupu",
  "store/checkout-payment.boletoNotice": "Predračun dostave je treba potrditi z nakupom. To lahko traja do 1 delovni dan.",
  "store/checkout-payment.reviewPurchaseLabel": "Preglejte nakup",
  "store/checkout-payment.billingAddressLabel": "Naslov za bremenitev",
  "store/checkout-payment.newAddressLabel": "+ Nov naslov",
  "store/checkout-payment.cardFormTitle": "Vsebnik za obrazec kreditne kartice",
  "store/checkout-payment.freePurchase": "Vaš nakup je brezplačen",
  "store/checkout-payment.informBillingAddress": "Prosimo, sporočite svoj naslov za plačilo"
}

```


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

[User] Show me the implementation of checkout-payment/messages/nl.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "U koos",
  "store/checkout-payment.installmentsButton": "Kies een betalingsoptie",
  "store/checkout-payment.creditCardExtraDataMessage": "Voor uw veiligheid, vul de volgende informatie in:",
  "store/checkout-payment.documentLabel": "Kaarthouder document",
  "store/checkout-payment.requiredField": "Dit veld is verplicht.",
  "store/checkout-payment.invalidDigits": "Ongeldige cijfers",
  "store/checkout-payment.creditCardLabel": "Kredietkaart ",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Bekijk termijnopties",
  "store/checkout-payment.installmentsOptionsTitle": "Termijnopties",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {without interest} true {met een rente van {interestRate}% per maand}}",
  "store/checkout-payment.installmentsTitle": "Termijnen",
  "store/checkout-payment.installmentOptionLabel": "Kies een termijnoptie",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Termijnen wijzigen",
  "store/checkout-payment.interestFree": "Renteloos",
  "store/checkout-payment.newCreditCardLabel": "Nieuwe kredietkaart",
  "store/checkout-payment.incompleteCardLabel": "Onvolledige kaart",
  "store/checkout-payment.choosePaymentMethodLabel": "Kies een betalingsmethode",
  "store/checkout-payment.paymentSummaryCardMessage": "Kredietkaart eindigend op {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Gegenereerd na aankoop",
  "store/checkout-payment.boletoNotice": "De geschatte levering is onder voorbehoud van bevestiging van betaling. Dit kan tot 1 werkdag duren.",
  "store/checkout-payment.reviewPurchaseLabel": "Aankoop beoordelen",
  "store/checkout-payment.billingAddressLabel": "Factuuradres",
  "store/checkout-payment.newAddressLabel": "+ Nieuw adres",
  "store/checkout-payment.cardFormTitle": "Container voor kredietkaartformulier",
  "store/checkout-payment.freePurchase": "Uw aankoop is gratis",
  "store/checkout-payment.informBillingAddress": "Geef uw factuuradres door"
}

```


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

[User] Show me the implementation of checkout-payment/messages/fi.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Valitsit",
  "store/checkout-payment.installmentsButton": "Valitse maksutapa",
  "store/checkout-payment.creditCardExtraDataMessage": "Turvallisuutesi takaamiseksi täytä seuraavat tiedot:",
  "store/checkout-payment.documentLabel": "Kortinhaltijan asiakirja",
  "store/checkout-payment.requiredField": "Tämä on pakollinen kenttä.",
  "store/checkout-payment.invalidDigits": "Virheelliset numerot",
  "store/checkout-payment.creditCardLabel": "Luottokortti",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Näytä maksuerävaihtoehdot",
  "store/checkout-payment.installmentsOptionsTitle": "Maksuerävaihtoehdot",
  "store/checkout-payment.installmentWithoutValue": "{count} x {hasInterestRate, select, false {without interest} true {with interest of {interestRate}% monthly}}",
  "store/checkout-payment.installmentsTitle": "Maksuerät",
  "store/checkout-payment.installmentOptionLabel": "Valitse maksuerävaihtoehto",
  "store/checkout-payment.installmentValue": "{installments} x {value}",
  "store/checkout-payment.changeInstallments": "Muuta maksueriä",
  "store/checkout-payment.interestFree": "Koroton",
  "store/checkout-payment.newCreditCardLabel": "Uusi luottokortti",
  "store/checkout-payment.incompleteCardLabel": "Epätäydellinen kortti",
  "store/checkout-payment.choosePaymentMethodLabel": "Valitse maksutapa",
  "store/checkout-payment.paymentSummaryCardMessage": "Luottokortti, jonka viimeiset numerot ovat {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Luodaan oston jälkeen",
  "store/checkout-payment.boletoNotice": "Toimitusarvio edellyttää, että maksu vahvistetaan. Tässä voi mennä jopa 1 arkipäivä.",
  "store/checkout-payment.reviewPurchaseLabel": "Tarkastele ostosta",
  "store/checkout-payment.billingAddressLabel": "Laskutusosoite",
  "store/checkout-payment.newAddressLabel": "+ Uusi osoite",
  "store/checkout-payment.cardFormTitle": "Luottokorttilomakkeen säilö",
  "store/checkout-payment.freePurchase": "Ostoksesi on ilmainen",
  "store/checkout-payment.informBillingAddress": "Anna laskutusosoitteesi"
}

```