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

[Assistant]
Here's the implementation:

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

# Tab 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 Tab Layout app provides you the needed structure to create different layouts within the store's main one from the use of *tabs*.

|![tab-layout](https://user-images.githubusercontent.com/52087100/66661201-fc70c880-ec1c-11e9-8387-3fea98f59e3c.png)|
|----|
|Example of a storefront with tabs (`Perfumes até 40%off`, `Presentes`, and `Best Sellers`) displaying different content for users.|

## Configuration

1. Add the Tab Layout app to your theme's dependencies in the `manifest.json` file:

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

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

| Block name   | Description                |
| :----------: | :------------------------: |
| `tab-layout` |  ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Parent block that merely defines the logic (via its children blocks) for the layout structure, declaring the desired list of tabs and its content. |
| `tab-list`   |  ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Defines the list of tabs to be rendered. It only accepts the `tab-list.item` block as a child. |
| `tab-list.item` | ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Defines the rendering for a given tab. Notice that it does not define the tab content, which is handled by the `tab-content.item` block.  |
| `tab-list.item.children` | Flexible alternative to `tab-list.item`. Defines the rendering for a given tab and also accepts any array of blocks as its children. |
| `tab-content` |  ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Defines the list of content to be rendered in each tab. It only accepts the `tab-content.item` block as a child. |
| `tab-content.item` |  ![https://img.shields.io/badge/-Mandatory-red](https://img.shields.io/badge/-Mandatory-red) Defines the content for a given tab. |

2. In the desired page template (e.g., `store.home`), add the `tab-layout` block:

```json
{
  "store.home": {
    "blocks": [
      "tab-layout#home"
    ]
  },
```

3. Declare the `tab-list` and the `tab-content` blocks as `tab-layout`'s children. Do not forget to use the `tab-layout`'s props, for example:

```diff
{
  "store.home": {
    "blocks": [
      "tab-layout#home"
    ]
  },
  "tab-layout#home": {
    "children": [
      "tab-list#home",
      "tab-content#home"
    ],
    "props": {
      "blockClass": "home",
      "defaultActiveTabId": "home1"
    }
  }
}
```

4. Add and then declare the desired `tab-list.item` blocks as `tab-list`'s children:

```diff
{
  "store.home": {
    "blocks": [
      "tab-layout#home"
    ]
  },
  "tab-layout#home": {
    "children": [
      "tab-list#home",
      "tab-content#home"
    ],
    "props": {
      "blockClass": "home",
      "defaultActiveTabId": "home1"
    }
  },
  "tab-list#home": {
    "children": [
      "tab-list.item#home1",
      "tab-list.item#home2"
    ]
  },
  "tab-list.item#home1": {
    "props": {
      "tabId": "home1",
      "label": "Home 1",
      "defaultActiveTab": true
    }
  },
  "tab-list.item#home2": {
    "props": {
      "tabId": "home2",
      "label": "Home 2"
    }
  }
}
```

5. Add and then declare the desired `tab-content.item` blocks as `tab-content`'s children:

```diff
{
  "store.home": {
    "blocks": [
      "tab-layout#home"
    ]
  },
  "tab-layout#home": {
    "children": [
      "tab-list#home",
      "tab-content#home"
    ],
    "props": {
      "blockClass": "home",
      "defaultActiveTabId": "home1"
    }
  },
  "tab-list#home": {
    "children": [
      "tab-list.item#home1",
      "tab-list.item#home2"
    ]
  },
  "tab-list.item#home1": {
    "props": {
      "tabId": "home1",
      "label": "Home 1",
      "defaultActiveTab": true
    }
  },
  "tab-list.item#home2": {
    "props": {
      "tabId": "home2",
      "label": "Home 2"
    }
  },
  "tab-content#home": {
    "children": [
      "tab-content.item#home1",
      "tab-content.item#home2"
    ]
  },
  "tab-content.item#home1": {
    "children": [
      "carousel#home"
    ],
    "props": {
      "tabId": "home1"
    }
  },
  "tab-content.item#home2": {
    "children": [
      "shelf#home",
      "info-card#home",
      "rich-text#question",
      "rich-text#link",
      "newsletter"
    ],
    "props": {
      "tabId": "home2"
    }
  }
}
```

> ⚠ Make sure to declare the `tab-content.item`'s children blocks in order to properly render the tab content.

### `tab-layout` props

| Prop name      | Type         | Description                                        | Default value   |
| ------------ | ---------- | ------------------------------------------------ | ------------- |
| `defaultActiveTabId` | `string` | ID of the desired tab to be rendered as the default one. If no value is provided, the first tab declared in the theme will be used as default. | `undefined` |
| `blockClass` | `string` | Block ID of your choosing to be used in [CSS customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization).  | `undefined` |

### `tab-list` props

| Prop name      | Type         | Description                                        | Default value   |
| ------------ | ---------- | ------------------------------------------------ | ------------- |
| `blockClass`   | `string`     | Block ID of your choosing to be used in [CSS customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization). | `undefined` |

### `tab-list.item` props

| Prop name      | Type         | Description                                        | Default value   |
| ------------ | ---------- | ------------------------------------------------ | ------------- |
| `blockClass` | `string` | Block ID of your choosing to be used in [CSS customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization). | `undefined` |
| `tabId` | `string` | Tab ID of your choosing. It will be used to match the tab to its content (defined by the `tab-content.item` block).  | `undefined` |
| `label` | `string` | Defines the tab's text label. | `undefined` |
| `defaultActiveTab` | `boolean` | Defines the item as the default active tab. | `false` |

### `tab-list.item.children` props

| Prop name      | Type         | Description                                        | Default value   |
| ------------ | ---------- | ------------------------------------------------ | ------------- |
| `blockClass` | `string` | Block ID of your choosing to be used in [CSS customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization). | `undefined` |
| `tabId` | `string` | Tab ID of your choosing. It will be used to match the tab to a given content (defined by the `tab-content.item` block). | `undefined` |

### `tab-content` props

| Prop name      | Type         | Description                                        | Default value   |
| ------------ | ---------- | ------------------------------------------------ | ------------- |
| `blockClass`   | `string`     | Block ID of your choosing to be used in [CSS customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization).  | `undefined`  |

### `tab-content.item` props

| Prop name      | Type         | Description                                        | Default value   |
| ------------ | ---------- | ------------------------------------------------ | ------------- |
| `blockClass` | `string` | Block ID of your choosing to be used in [CSS customization](https://developers.vtex.com/docs/guides/vtex-io-documentation-using-css-handles-for-store-customization). | `undefined` |
| `tabId` | `string` | Tab ID of your choosing. It will be used to match the content to a given tab (defined by the `tab-list.item` / `tab-list.item.children`  blocks). | `undefined` |

> ⚠ Be mindful of the `tabID` specified in both `tab-list.item` and `tab-content.item` blocks, as this parameter couples a tab and its corresponding content.

## Customization

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

| CSS Handle |
| ---------- |
| `container`  |
| `contentContainer`  |
| `contentItem`  |
| `listContainer`  |
| `listItem`  |
| `listItemActive`  |
| `listItemChildren` |
| `listItemChildrenActive` |

<!-- 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/JNussens"><img src="https://avatars0.githubusercontent.com/u/7662734?v=4" width="100px;" alt=""/><br /><sub><b>Jean Nussenzveig</b></sub></a><br /><a href="https://github.com/vtex-apps/tab-layout/commits?author=JNussens" title="Code">💻</a></td>
    <td align="center"><a href="https://github.com/lucasayb"><img src="https://avatars2.githubusercontent.com/u/17356081?v=4" width="100px;" alt=""/><br /><sub><b>Lucas Yamamoto</b></sub></a><br /><a href="https://github.com/vtex-apps/tab-layout/commits?author=lucasayb" title="Code">💻</a></td>
    <td align="center"><a href="https://acct.global/"><img src="https://avatars0.githubusercontent.com/u/38354801?v=4" width="100px;" alt=""/><br /><sub><b>weslybrandao</b></sub></a><br /><a href="https://github.com/vtex-apps/tab-layout/commits?author=weslybrandao" title="Code">💻</a></td>
  </tr>
</table>

<!-- 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 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 tab-layout/react/TabContent.tsx from the tab-layout VTEX app.

[Assistant]
Here's the implementation:

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

const CSS_HANDLES = ['contentContainer'] as const

const TabContent: StorefrontFunctionComponent = props => {
  const { children } = props
  const handles = useCssHandles(CSS_HANDLES)

  return (
    <div className={`${handles.contentContainer} w-100`}>
      {React.Children.map(children, (child, index) => React.cloneElement(child as any, { position: index }))}
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.tabContent.title',
  },
  description: {
    defaultMessage: '',
    id: 'admin/editor.tabContent.description',
  },
})

TabContent.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default TabContent
```


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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages } from 'react-intl'

import { useCssHandles } from 'vtex.css-handles'

import { useTabState, useTabDispatch } from './components/TabLayoutContext'
import { useDeprecatedDefaultActiveTab } from './modules/useDeprecatedDefaultActiveTab'

const CSS_HANDLES = ['listItemChildren', 'listItemChildrenActive'] as const

interface Props {
  tabId: string
  defaultActiveTab: boolean //deprecated
  position: number
}

const TabListItemChildren: StorefrontFunctionComponent<Props> = props => {
  const { tabId, defaultActiveTab, position, children } = props
  const handles = useCssHandles(CSS_HANDLES)
  const { activeTab } = useTabState()
  const dispatch = useTabDispatch()

  useDeprecatedDefaultActiveTab(defaultActiveTab, tabId)

  const isActive = activeTab === tabId || (!activeTab && position === 0)

  const handleClick = () =>
    dispatch({
      type: 'changeActiveTab',
      payload: { newActiveTab: tabId },
    })

  return (
    <div
      role="button"
      onClick={handleClick}
      className={`${handles.listItemChildren} ${
        isActive ? handles.listItemChildrenActive : ''
      } ph2 pv2 ma2`}
    >
      {children}
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.tabListItem.title',
  },
  description: {
    defaultMessage: '',
    id: 'admin/editor.tabListItem.description',
  },
})

TabListItemChildren.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default TabListItemChildren

```


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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages } from 'react-intl'

import { Button } from 'vtex.styleguide'
import { IOMessage } from 'vtex.native-types'
import { useCssHandles } from 'vtex.css-handles'

import { useTabState, useTabDispatch } from './components/TabLayoutContext'
import { useDeprecatedDefaultActiveTab } from './modules/useDeprecatedDefaultActiveTab'

const CSS_HANDLES = ['listItem', 'listItemActive'] as const

interface Props {
  tabId: string
  label: string
  /**
   * @deprecated This prop should not be used
   */
  defaultActiveTab: boolean
  position: number
}

function TabListItem(props: Props) {
  const { tabId, label, defaultActiveTab, position } = props
  const handles = useCssHandles(CSS_HANDLES)
  const { activeTab } = useTabState()
  const dispatch = useTabDispatch()

  useDeprecatedDefaultActiveTab(defaultActiveTab, tabId)

  const isActive = activeTab === tabId || (!activeTab && position === 0)

  const handleClick = () =>
    dispatch({
      type: 'changeActiveTab',
      payload: { newActiveTab: tabId },
    })

  if (!label || label === '') {
    return null
  }

  return (
    <div
      className={`${handles.listItem} ${
        isActive ? handles.listItemActive : ''
      } ph2 pv2 ma2`}
    >
      <Button
        variation={isActive ? 'primary' : 'tertiary'}
        onClick={handleClick}
      >
        <IOMessage id={label} />
      </Button>
    </div>
  )
}

const messages = defineMessages({
  title: {
    id: 'admin/editor.tabListItem.title',
  },
  description: {
    id: 'admin/editor.tabListItem.description',
  },
})

TabListItem.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default TabListItem

```


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

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "ramda": "^0.26.1",
    "react": "^16.8.6",
    "react-intl": "^2.9.0"
  },
  "devDependencies": {
    "@types/graphql": "^14.2.0",
    "@types/jest": "^24.0.11",
    "@types/node": "^11.13.2",
    "@types/ramda": "^0.26.8",
    "@types/react": "^16.8.13",
    "@types/react-intl": "^2.3.17",
    "eslint": "5.15.1",
    "eslint-config-vtex": "10.1.0",
    "eslint-config-vtex-react": "4.1.0",
    "vtex.render-runtime": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.render-runtime@8.65.0/public/_types/react",
    "vtex.styleguide": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.styleguide@9.79.4/public/_types/react"
  },
  "version": "0.4.6"
}

```


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

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

[Assistant]
Here's the implementation:

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

const CSS_HANDLES = ['listContainer'] as const

const TabList: StorefrontFunctionComponent = props => {
  const { children } = props
  const handles = useCssHandles(CSS_HANDLES)

  return (
    <div className={`${handles.listContainer} flex w-100 flex-wrap justify-center`}>
      {React.Children.map(children, (child, index) => React.cloneElement(child as any, { position: index }))}
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.tabList.title',
  },
  description: {
    defaultMessage: '',
    id: 'admin/editor.tabList.description',
  },
})

TabList.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default TabList
```


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

[Assistant]
Here's the implementation:

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

import {
  TabLayoutContextProvider
} from './components/TabLayoutContext'

const CSS_HANDLES = ['container'] as const

interface Props {
  defaultActiveTabId?: string
}

const TabLayout: StorefrontFunctionComponent<Props> = props => {
  const { children, defaultActiveTabId = '' } = props
  const handles = useCssHandles(CSS_HANDLES)

  return (
    <TabLayoutContextProvider activeTab={defaultActiveTabId}>
      <div className={handles.container}>
        {children}
      </div>
    </TabLayoutContextProvider>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.tabLayout.title',
  },
  description: {
    defaultMessage: '',
    id: 'admin/editor.tabLayout.description',
  },
})

TabLayout.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default TabLayout
```


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

[Assistant]
Here's the implementation:

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

import {
  useTabState
} from './components/TabLayoutContext'

const CSS_HANDLES = ['contentItem'] as const

interface Props {
  tabId: string
  position: number
}

const TabContentItem: StorefrontFunctionComponent<Props> = props => {
  const { tabId, children, position } = props
  const handles = useCssHandles(CSS_HANDLES)
  const { activeTab } = useTabState()

  const shouldShow = activeTab === tabId || (!activeTab && position === 0)

  if (!shouldShow) return null

  return (
    <div className={`${handles.contentItem} w-100`}>
      {children}
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.tabContentItem.title',
  },
  description: {
    defaultMessage: '',
    id: 'admin/editor.tabContentItem.description',
  },
})

TabContentItem.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default TabContentItem
```


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

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "TabListItem": {
      "type": "object",
      "properties": {
        "label": {
          "title": "admin/editor.tabListItem.label",
          "$ref": "app:vtex.native-types#/definitions/text",
          "default": ""
        }
      }
    }
  }
}
```


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

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

[Assistant]
Here's the implementation:

```json
{
  "tab-layout": {
    "component": "TabLayout",
    "composition": "children",
    "allowed": "*"
  },
  "tab-list": {
    "component": "TabList",
    "composition": "children",
    "allowed": ["tab-list.item"]
  },
  "tab-list.item": {
    "component": "TabListItem",
    "content": {
      "$ref": "app:vtex.tab-layout#/definitions/TabListItem"
    }
  },
  "tab-list.item.children": {
    "component": "TabListItemChildren",
    "composition": "children"
  },
  "tab-content": {
    "component": "TabContent",
    "composition": "children",
    "allowed": "*"
  },
  "tab-content.item": {
    "component": "TabContentItem",
    "composition": "children",
    "allowed": "*"
  }
}
```


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

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.css-handles' {
  type CssHandlesInput = readonly string[]
  type ValueOf<T extends readonly any[]> = T[number]
  type CssHandles<T extends CssHandlesInput> = Record<ValueOf<T>, string>
  interface CssHandlesOptions {
    migrationFrom?: string | string[]
  }

  export const useCssHandles: <T extends CssHandlesInput>(
    handles: T,
    options: CssHandlesOptions = {}
  ) => CssHandles<T>
  export const applyModifiers: (
    handles: string,
    modifier: string | string[]
  ) => string
}

```


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

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

[Assistant]
Here's the implementation:

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

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

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

  interface StorefrontElement extends ReactElement {
    schema?: object
    getSchema?(props: P): object
  }
}
```


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

[User] Show me the implementation of tab-layout/react/typings/css.d.ts from the tab-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
    const css: 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 tab-layout/react/typings/vtex.styleguide.d.ts from the tab-layout VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.styleguide' {
    export const 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 tab-layout/react/components/TabLayoutContext.tsx from the tab-layout VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FunctionComponent, useContext, useReducer } from 'react'

interface TabLayoutContextProps {
  activeTab: string
}

interface ChangeActiveTabAction {
  type: 'changeActiveTab'
  payload: {
    newActiveTab: string
  }
}

type Dispatch = (action: ChangeActiveTabAction) => void

const initialState = {
  activeTab: ""
}

const TabLayoutStateContext = React.createContext<TabLayoutContextProps>(initialState)
const TabLayoutDispatchContext = React.createContext<Dispatch | undefined>(undefined)

function reducer(state: TabLayoutContextProps, action: ChangeActiveTabAction): TabLayoutContextProps {
  switch (action.type) {
    case 'changeActiveTab':
      if (action.payload.newActiveTab === state.activeTab) {
        return state
      }
      return {
        ...state,
        activeTab: action.payload.newActiveTab
      }
    default:
      return state
  }
}

const TabLayoutContextProvider: FunctionComponent<
  TabLayoutContextProps
> = ({ children, activeTab }) => {
  const [state, dispatch] = useReducer(reducer, {
    activeTab,
  })
  return (
    <TabLayoutStateContext.Provider value={state}>
      <TabLayoutDispatchContext.Provider value={dispatch}>
        {children}
      </TabLayoutDispatchContext.Provider>
    </TabLayoutStateContext.Provider>
  )
}

function useTabState() {
  const context = useContext(TabLayoutStateContext)
  if (context === undefined) {
    throw new Error(
      'useTabState must be used within a TabLayoutStateContextProvider'
    )
  }
  return context
}

function useTabDispatch() {
  const context = useContext(TabLayoutDispatchContext)

  if (context === undefined) {
    throw new Error(
      'useTabDispatch must be used within a TabLayoutDispatchContextProvider'
    )
  }
  return context
}

export { TabLayoutContextProvider, useTabDispatch, useTabState }
```


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

[Assistant]
Here's the implementation:

```typescript
import { useEffect } from 'react'
import { useTabState, useTabDispatch } from '../components/TabLayoutContext'

export const useDeprecatedDefaultActiveTab = (defaultActiveTab: boolean, tabId: string) => {
  const { activeTab } = useTabState()
  const dispatch = useTabDispatch()

  useEffect(() => {
    // defaultActiveTab has been deprecated, keep this for compatibility
    if (defaultActiveTab && activeTab === '') {
      dispatch({
        type: 'changeActiveTab',
        payload: { newActiveTab: tabId },
      })
    }
  }, [])
}
```


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

[Assistant]
Here's the implementation:

```markdown
# Shopback

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

or

Run the following command:

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

Next, open the app settings on your admin and fill the form with your Shopback Id.
```


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

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

[Assistant]
Here's the implementation:

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

function handleMessages(event: PixelMessage) {
  const {
    data,
    data: { eventName },
  } = event
  if (eventName === 'vtex:orderPlaced') {
    const { transactionSubtotal: valor, transactionId: order_id } = data
    window._cv_data = {
      order_id,
      valor,
    }
    let script = document.createElement('script')
    script.type = 'text/javascript'
    script.async = true
    script.src = '//app.shoptarget.com.br/js/tracking.js'
    let firstScript = document.getElementsByTagName('script')[0]
    if (firstScript && firstScript.parentNode) {
      firstScript.parentNode.insertBefore(script, firstScript)
    }
  }
}

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

```


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

[User] Show me the implementation of shopback/react/package.json from the shopback VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "devDependencies": {
    "@types/graphql": "^14.2.0",
    "@types/jest": "^24.0.11",
    "@types/node": "^11.13.0",
    "@types/ramda": "^0.26.5",
    "@vtex/test-tools": "^1.1.0",
    "eslint": "^5.15.1",
    "eslint-config-vtex": "^10.1.0",
    "eslint-config-vtex-react": "^4.1.0",
    "prettier": "^1.18.2",
    "tslint-eslint-rules": "^5.4.0",
    "typescript": "3.5.2",
    "vtex.pixel-interfaces": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.pixel-interfaces@1.1.0/public/_types/react",
    "vtex.render-runtime": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.render-runtime@8.58.0/public/_types/react"
  }
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "pixel.shopback": {
    "component": "index"
  }
}

```


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

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

[Assistant]
Here's the implementation:

```typescript
export interface PixelMessage extends MessageEvent {
  data: OrderPlacedData
}

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

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

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

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

interface ShippingMethod {
  itemId: string
  selectedSla: string
}

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

```


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

[Assistant]
Here's the implementation:

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

```


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

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

[Assistant]
Here's the implementation:

```typescript
interface Window extends Window {
  _st_account: string
  _cv_data: CVData
}

interface CVData {
  order_id: string
  valor: string
}

```


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

[User] Show me the implementation of paginated-table/messages/it-IT.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "Mostra righe",
  "admin/table.of": "di",
  "admin/table.item-label": "{total, plural, one {elemento} other {elementi}}"
}

```


[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 paginated-table/messages/th-TH.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "แสดงแถว",
  "admin/table.of": "ของ",
  "admin/table.item-label": "{total, plural, one {รายการ} other {รายการ}}"
}

```


[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 paginated-table/messages/ko-KR.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "행 표시",
  "admin/table.of": "/",
  "admin/table.item-label": "{total, plural, one {항목} other {항목}}"
}
```


[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 paginated-table/messages/ja-JP.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "表示行数",
  "admin/table.of": "/",
  "admin/table.item-label": "{total, plural, one {項目} other {項目}}"
}
```


[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 paginated-table/messages/bg-BG.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
    "admin/table.show-rows": "Показване на редове",
    "admin/table.of": "от",
    "admin/table.item-label": "{total, plural, one {артикул} other {артикули}}"
}
```


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

[Assistant]
Here's the implementation:

```json
{
    "admin/table.show-rows": "Mostrar linhas",
    "admin/table.of": "de",
    "admin/table.item-label": "{total, plural, one {unidade} other {unidades}}"
}
```


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

[Assistant]
Here's the implementation:

```json
{
    "admin/table.show-rows": "Show rows",
    "admin/table.of": "of",
    "admin/table.item-label": "{total, plural, one {item} other {items}}"
}
```


[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 paginated-table/messages/ro-RO.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "Arată rânduri",
  "admin/table.of": "din",
  "admin/table.item-label": "{total, plural, one {articol} few {articole} other {articole}}"
}

```


[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 paginated-table/messages/de-DE.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
    "admin/table.show-rows": "Zeilen anzeigen",
    "admin/table.of": "von",
    "admin/table.item-label": "{total, plural, one {Artikel} other {Artikel}}"
}
```


[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 paginated-table/messages/fr-FR.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "Afficher les lignes",
  "admin/table.of": "de",
  "admin/table.item-label": "{total, plural, one {article} other {articles}}"
}

```


[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 paginated-table/messages/nl-NL.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "Toon rijen",
  "admin/table.of": "van",
  "admin/table.item-label": "{total, plural, one {item} other {items}}"
}

```


[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 paginated-table/messages/es.json from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/table.show-rows": "Mostrar filas",
  "admin/table.of": "de",
  "admin/table.item-label": "{total, plural, one {ítem} other {ítems}}"
}
```


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

[Assistant]
Here's the implementation:

```markdown
> :warning: **Unmantained**: This repository is currently unmaintaned and is considered obsolete. It's based on VTEX Styleguide, which is no longer being worked on. Please consider migrating to [ADMIN UI's table and hooks](https://admin-ui.vercel.app/components/table), some of these functionalities are already provided by it and it's flexible enough to allow for the others. Feel free to re-use code from the hooks implemented here in your project if it makes sense to you
>
> If you'd like to keep updating this repository you are able to contribute and make new releases as long as you are in the `tech` team on vtex-apps. It is no longer adviseble to evolve functionalities based on styleguide's table though.

# Paginated Table

## Description

The Paginated Table is a wrapper to the VTEX Styleguide Table that abstracts some of the logic that normally one should write to handle pagination with GraphQL

## Table of Contents

- [Paginated Table](#paginated-table)
  - [Description](#description)
  - [Table of Contents](#table-of-contents)
  - [Usage](#usage)
    - [PaginatedTable](#paginatedtable)
    - [PersistedPaginatedTable](#persistedpaginatedtable)
  - [Troubleshooting](#troubleshooting)
  - [Contributing](#contributing)

## Usage

This app uses our styleguide as the Table engine. To know more about the VTEX Styleguide [click here.](https://styleguide.vtex.com/)

To use this app, you need to import it in your dependencies in `manifest.json`.

```json
  dependencies: {
    "vtex.paginated-table": "0.x"
  }
```

Then, import the `PaginatedTable` component into your app as

```jsx
import { PaginatedTable } from 'vtex.paginated-table'
```

If you prefer to use the `PersistedPaginatedTable`, you can do it as follows

```jsx
import { PersistedPaginatedTable } from 'vtex.paginated-table'
```

If you want to use the table V2 and its hooks you can import just the hooks you will be using.

```jsx
import { ExtendedTable, useDynamicMeasures, useInverseTableSort } from 'vtex.paginated-table'
```

## Table V2

### ExtendedTable

This table works like styleguide's table V2 with some extra optional params to add the following features:

- Sorting with default ordering = 'DSC'
- Dynamic row heights
- Detecting on rowHover
- Expandable rows (rows that can be expanded vertically to show more info)

#### To use hovering:

Add parameter `hovering`

```jsx
const hovering = {
  // called when hovering a row
  onMouseEnter = (id: string) => void
  // called when mouse leaves table (so it's no longer hovering any row)
  onMouseLeave = () => void
}
```

#### To use dynamic rowHeights:

Add parameter `measuringRef` to table and use `useDynamicMeasures` to get the parameter `measures` and ref

```jsx
const { ref, measures } = useDynamicMeasures({
    lenght: items.length || 0,
  })

  <ExtendedTable
    measures={measures}
    measuringRef={ref}
    {...}
  />
```

#### To use sorting with default sort order:

Use either hook `useInverseTableSort` or `usePersistedTableSort` with defaultSortOrder parameter to get `sorting` and feed it to the table

```jsx
const { sortOrder, sortedBy: sortBy, sorting } = usePersistedTableSort({
    defaultSortOrder: 'DSC',
  })

  <ExtendedTable
    sorting={sorting}
  />
```

### To use row expansion functionality

You must add `rowExpansion` prop which contains a map indicating what rows are expanded. You can use the `useExpandableRows` hook as the value for `rowExpansion`.

Additionally, to the data of each item on the table you must add the props:

```jsx
{
  // indicates if this row will be expandable, set it to always true if you want all rows
  // to be expandable
  isExpandable?: boolean
  // what will be rendered inside the expanded area for this row
  extendedRowRenderer?: React.ReactNode,
}
```

Inside any cell rendered for a column you will get the addtional info `isExpanded` in case you want to change the style based on that. (be aware you will only get this data if this column is defined with `isExtended` the prop that makes the cell get the full rowData)

```jsx
  const items = rawData.map((item: any) => ({
    name: item.fullName
    // REQUIRED parameters:
    id: item.ID,
    isExpandable: true,
    extendedRowRenderer: <ExtraInfoComponent item={item} />,
  }))

  // the items array MUST have id for each item, this is used to control what rows are expanded
  const rowExpansion = useExpandableRows({
    items,
  })

  <ExtendedTable
    onRowClick={({
      rowData: { id },
    }: {
      rowData: {
        id: any
      }
    }) => {
      rowExpansion.toggleExpandRow(id)
    }}
    rowExpansion={rowExpansion}
  />
```

## Table V1

### PaginatedTable

Along the usual [Styleguide Table's props](https://styleguide.vtex.com/#/Components/Display/Table), this table has the following props:

| Prop name             | Type       | Description                                                                                | Default value |
| --------------------- | ---------- | ----------------------------------------------------------------------------------------------------- | ------------- |
| `fetchMore`           | `Function` | A React Apollo `fetchMore` function to fetch data for the next/last page                              | Required      |
| `total`               | `Number`   | The total number of items in your data                                                                | Required      |
| `updateQuery`         | `Function` | A React Apollo `updateQuery` function that runs the `fetchMore` function in order to update your data | Required      |
| `updatePaginationKey` | `String`   | A key to force a table update when it changes                                                         | `''`          |
| `onSortChange`        | `Function` | A callback to be called whenever there is a Sort change in the Table                                  | `() => {}`    |

**OBS:**

- Detailed specifications for `fetchMore` and `updateQuery` can be seen in [this Apollo link](https://www.apollographql.com/docs/react/data/pagination/)
- The callback provided to `onSortChange` should have the following signature `(newSortedBy: string, newSortOrder: 'ASC' | 'DESC') => void`

### PersistedPaginatedTable

The `PersistedPaginatedTable` uses the page's query string to persist the table pagination state. It is meant to be used whenever the page has interactive elements that make the user to leave the page that contains the table without resetting the table state or to share a specific table state between users (e.g. by providing a link to the page that contains the table).

Along the usual [Styleguide Table's props](https://styleguide.vtex.com/#/Components/Display/Table), this table has the following props:

| Prop name                | Type                       | Description                                              | Default value |
| ------------------------ | -------------------------- | -------------------------------------------------------- | ------------- |
| `total`                  | `Number`                   | The total number of items in your data                   | Required      |
| `updatePaginationKey`    | `String`                   | A key to force a table update when it changes            | `''`          |
| `defaultElementsPerPage` | `Number`                   | The default number of elements per table page            | `15`          |
| `defaultSortOrder`       | One of [`'ASC'`, `'DESC'`] | The default sort order for the page                      | `'ASC'`       |
| `defaultSortedBy`        | `String`                   | The default column by which the table is to be sorted by | `''`          |

```


[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 paginated-table/react/PaginatedTable.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useEffect } from 'react'
import { Table } from 'vtex.styleguide'
import { GraphqlQueryControls } from 'react-apollo'
import { JSONSchema6Type } from 'json-schema'
import { defineMessages, useIntl } from 'react-intl'

const INITIAL_ELEMENTS_PER_PAGE = 15

type Props<TItem, TQueryVariables, TSchema extends JSONSchema6Type> = {
  fetchMore: GraphqlQueryControls<TQueryVariables>['fetchMore']
  total: number
  updateQuery: any
  updatePaginationKey?: string
  onSortChange?: (sortedBy: string, sortOrder: string) => void
} & TableProps<TItem, TSchema>

type TableProps<TItem, TSchema extends JSONSchema6Type> = {
  items: TItem[]
  schema: TSchema
  loading?: boolean
  emptyStateLabel?: React.ReactNode
  emptyStateChildren?: React.ReactNode
  onRowClick?: OnRowClickHandler<TItem>
  totalizers?: any
  filters?: any
  toolbar?: {
    inputSearch?: {
      value: IntlMessage
      placeholder: React.ReactNode
      onChange: React.ChangeEventHandler<HTMLInputElement>
      onClear: React.ChangeEventHandler<HTMLInputElement>
      onSubmit: React.MouseEventHandler<HTMLSpanElement>
    }
    density?: {
      buttonLabel: IntlMessage
      lowOptionLabel: IntlMessage
      mediumOptionLabel: IntlMessage
      highOptionLabel: IntlMessage
    }
    fields?: {
      label: IntlMessage
      showAllLabel: IntlMessage
      hideAllLabel: IntlMessage
    }
    download?: {
      label: IntlMessage
      handleCallback: () => void
    }
    upload?: {
      label: IntlMessage
      handleCallback: () => void
    }
    extraActions?: {
      label: IntlMessage
      actions: {
        label: IntlMessage
        handleCallback: () => void
      }[]
    }
    newLine?: {
      label: IntlMessage
      handleCallback: () => void
    }
  }
  lineActions?: {
    label: () => IntlMessage
    isDangerous?: boolean
    onClick: Function
  }[]
  bulkActions?: {
    texts: {
      secondaryActionsLabel: string
      rowsSelected: Function
      selectAll: string
      allRowsSelected: Function
    }
    totalItems?: number
    main: {
      label: string
      handleCallback: Function
    }
    others: {
      label: string
      handleCallback: Function
    }[]
  }
}

export type OnRowClickHandler<TItem> = ({ rowData }: { rowData: TItem }) => void
export type IntlMessage = string | JSX.Element

const messages = defineMessages({
  of: {
    id: 'admin/table.of',
    defaultMessage: 'of',
  },
  showRowsLabel: {
    id: 'admin/table.show-rows',
    defaultMessage: 'Show rows',
  },
})

const PaginatedTable = <
  TItem,
  TQueryVariables extends { to: number; from: number },
  TSchema extends JSONSchema6Type
>(
  props: Props<TItem, TQueryVariables, TSchema>
) => {
  const [from, setFrom] = useState(0)
  const [to, setTo] = useState(INITIAL_ELEMENTS_PER_PAGE)
  const [currentPage, setCurrentPage] = useState(0)
  const [elementsPerPage, setElementsPerPage] = useState(INITIAL_ELEMENTS_PER_PAGE)
  const [sortedBy, setSortedBy] = useState('')
  const [sortOrder, setSortOrder] = useState('ASC')

  const { formatMessage } = useIntl()

  const {
    items = [],
    updateQuery,
    total,
    fetchMore,
    updatePaginationKey,
    onSortChange = () => {},
    ...tableProps
  } = props

  useEffect(() => {
    setFrom(0)
    setTo(elementsPerPage)
    setCurrentPage(0)
  }, [updatePaginationKey])

  const onPageChange = (
    newPage: number,
    currentElementsPerPage: number = elementsPerPage
  ) => async () => {
    const from = newPage * currentElementsPerPage

    const to = Math.min((newPage + 1) * currentElementsPerPage, total)

    if (items.slice(from, to).length !== to - from) {
      await fetchMore({
        updateQuery,
        variables: { from, to },
      })
    }

    setTo(to)
    setFrom(from)
    setCurrentPage(newPage)
  }

  const totalPages = Math.ceil(total / elementsPerPage)

  const nextPage = (currentPage + 1) % totalPages

  const previousPage = totalPages - 1 - ((totalPages - currentPage) % totalPages)

  return (
    <Table
      fullWidth
      items={items.slice(from, to)}
      pagination={{
        currentItemFrom: from + 1,
        currentItemTo: to,
        onNextClick: onPageChange(nextPage),
        onPrevClick: onPageChange(previousPage),
        rowsOptions: [10, 15, 25],
        selectedOption: elementsPerPage,
        onRowsChange: async (e: React.ChangeEvent<HTMLSelectElement>) => {
          setElementsPerPage(parseInt(e.target.value))
          onPageChange(currentPage, parseInt(e.target.value))()
        },
        textOf: formatMessage(messages.of),
        textShowRows: formatMessage(messages.showRowsLabel),
        totalItems: total,
      }}
      density="low"
      sort={{
        sortedBy,
        sortOrder,
      }}
      onSort={({
        sortOrder: newSortOrder,
        sortedBy: newSortedBy,
      }: {
        sortOrder: string
        sortedBy: string
      }) => {
        setSortOrder(newSortOrder)
        setSortedBy(newSortedBy)
        onSortChange(newSortedBy, newSortOrder)
      }}
      {...tableProps}
    />
  )
}

export default PaginatedTable

```


[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 paginated-table/react/useInverseTableSort.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useState } from 'react'

export default function useInverseTableSort(initialState?: { by: string; order: string }) {
  const [by, setBy] = useState<string | undefined>(initialState?.by)
  const [order, setOrder] = useState<string | undefined>(initialState?.order)

  const sort = (id: string) => {
    if (!by || by !== id) {
      setOrder('DSC')
      setBy(id)
    } else {
      setOrder((currentOrder: string | undefined) => {
        return currentOrder === 'DSC' ? 'ASC' : 'DSC'
      })
      setBy(id)
    }
  }

  const clear = () => {
    setBy(undefined)
    setOrder(undefined)
  }

  return {
    sorted: {
      order: order,
      by: by,
    },
    sort: sort,
    clear: clear,
    defaultOrder: 'DSC',
  }
}

```


[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 paginated-table/react/usePersistedPagination.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useRuntime } from 'vtex.render-runtime'
import { useState, useCallback, useEffect, useRef } from 'react'
import { useIntl, defineMessages } from 'react-intl'

const INITIAL_ELEMENTS_PER_PAGE = 15

const messages = defineMessages({
  itemLabel: {
    defaultMessage: '{total, plural, one {item} other {items}}',
    id: 'admin/table.item-label',
  },
  of: {
    defaultMessage: 'of',
    id: 'admin/table.of',
  },
  showRowsLabel: {
    defaultMessage: 'Show rows',
    id: 'admin/table.show-rows',
  },
})

export default function usePersistedPagination(props: {
  hasPageTopIndicator?: boolean
  defaultElementsPerPage?: number
  resetPaginationOnChangeKey: string
}) {
  const {
    defaultElementsPerPage = INITIAL_ELEMENTS_PER_PAGE,
    hasPageTopIndicator = false,
    resetPaginationOnChangeKey,
  } = props

  const { formatMessage } = useIntl()
  const [total, setTotal] = useState(defaultElementsPerPage)
  const { setQuery, query } = useRuntime()
  const didMountRef = useRef(false)

  const elementsPerPage = parseInt(query.elements, 10) || defaultElementsPerPage

  const onPageChange = (
    currentFrom: number,
    currentElementsPerPage: number,
    direction: string
  ) => () => {
    const c = direction === 'next' ? 1 : -1

    const newFrom = currentFrom + c * currentElementsPerPage

    const newTo = Math.min(newFrom + currentElementsPerPage, total)

    setQuery({ to: newTo, from: newFrom, elements: currentElementsPerPage })
  }

  const resetPagination = useCallback(() => {
    setQuery({ to: elementsPerPage, from: 0, elements: elementsPerPage })
  }, [elementsPerPage, setQuery])

  const from = parseInt(query.from, 10) || 0
  const to = parseInt(query.to, 10) || elementsPerPage

  useEffect(() => {
    if (didMountRef.current) {
      resetPagination()
    } else {
      didMountRef.current = true
    }
  }, [resetPaginationOnChangeKey])

  return {
    resetPagination,
    from,
    to,
    setTotal,
    paginationProps: {
      currentItemFrom: from + 1,
      currentItemTo: to,
      hasPageTopIndicator,
      onNextClick: onPageChange(from, elementsPerPage, 'next'),
      onPrevClick: onPageChange(from, elementsPerPage, 'prev'),
      onRowsChange: (e: React.ChangeEvent<HTMLSelectElement>) => {
        const newElementsPerPage = parseInt(e.target.value, 10)
        const currentPage = Math.floor(from / newElementsPerPage)
        const newFrom = currentPage * newElementsPerPage
        setQuery({
          elements: newElementsPerPage,
          from: newFrom,
          to: newFrom + newElementsPerPage,
        })
      },
      rowsOptions: [10, 15, 25],
      selectedOption: elementsPerPage,
      textOf: formatMessage(messages.of),
      textShowRows: formatMessage(messages.showRowsLabel),
      totalItems: total,
    },
  }
}

```


[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 paginated-table/react/useExpandableRows.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useState, useEffect, useMemo } from 'react'

export type IdMap = Record<string, boolean> | undefined

export default function useExpandableRows(props: { items: Array<{ id: string }> }) {
  const idsSummarizedString = props.items.reduce(
    (acc: string, currentItem) => `${acc}.${currentItem.id}`,
    ''
  )
  const itemsQuant = props.items.length

  const [expandedRowsAmount, setExpandedRowsAmount] = useState(0)
  const [isRowExpandedMap, setIsRowExpandedMap] = useState<IdMap>()

  const allExpandedMap = useMemo(() => {
    return props.items.reduce(
      (acc: IdMap, currentItem) => ({
        ...acc,
        [currentItem.id]: true,
      }),
      {}
    )
    // since props.items is an array and useMemo doesn't perform
    // deep compare idsSummarizedString is replacing props.items here
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [idsSummarizedString])

  useEffect(() => {
    setIsRowExpandedMap({})
    // since props.items is an array and useEffect doesn't perform
    // deep compare idsSummarizedString is replacing props.items here
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [idsSummarizedString])

  const toggleRow = (id: string) => {
    if (!isRowExpandedMap || !isRowExpandedMap[id]) {
      setExpandedRowsAmount(current => current + 1)
    } else {
      setExpandedRowsAmount(current => current - 1)
    }

    setIsRowExpandedMap(currentMap => ({
      ...currentMap,
      [id]: currentMap ? !currentMap[id] : false,
    }))
  }

  const expandAll = () => {
    setIsRowExpandedMap(allExpandedMap)
    setExpandedRowsAmount(itemsQuant)
  }

  const collapseAll = () => {
    setIsRowExpandedMap({})
    setExpandedRowsAmount(0)
  }

  return {
    toggleExpandRow: toggleRow,
    isRowExpandedMap,
    expandAll,
    collapseAll,
    expandedRowsAmount,
  }
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "apollo-client": "^2.4.7",
    "graphql": "^14.0.2",
    "react": "^16.6.3",
    "react-apollo": "^2.3.1",
    "react-dom": "^16.0.0",
    "react-intl": "^3.9.2"
  },
  "devDependencies": {
    "@apollo/react-testing": "^4.0.0",
    "@types/jest": "^24.0.11",
    "@types/json-schema": "^7.0.3",
    "@types/node": "^10.12.17",
    "@types/react": "^16.8.23",
    "@vtex/styleguide": "^9.125.0",
    "@vtex/test-tools": "^3.1.0",
    "prettier": "^1.16.4",
    "tslint": "^5.12.0",
    "tslint-config-vtex": "^2.1.0",
    "typescript": "3.9.7"
  },
  "scripts": {
    "lint": "tsc --noEmit && tslint -c tslint.json './**/*.ts'",
    "test": "vtex-test-tools test"
  },
  "version": "0.14.0"
}

```


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

[User] Show me the implementation of paginated-table/react/useDynamicMeasures.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useCallback, useLayoutEffect, useState } from 'react'

const getHeight = (node: HTMLElement) => {
  const rect = node.getBoundingClientRect()

  return rect.height
}

const BASE_ROW_HEIGHT = 48
const TABLE_HEADER_HEIGHT = 36
const EMPTY_STATE_SIZE = 5 * BASE_ROW_HEIGHT

export function calculateTableHeight(
  rowHeight: number,
  tableSize: number,
  headless?: boolean
): number {
  const multiplicator = Boolean(tableSize) ? tableSize * rowHeight : EMPTY_STATE_SIZE
  return (headless ? 0 : TABLE_HEADER_HEIGHT) + multiplicator
}

const useDynamicMeasures = ({ lenght, headless }: { lenght: number; headless?: boolean }) => {
  const [node, setNode] = useState<HTMLElement | null>(null)
  const [tableHeight, setTableHeight] = useState(
    calculateTableHeight(BASE_ROW_HEIGHT, lenght, headless)
  )

  const ref = useCallback((element: HTMLElement) => {
    setNode(element)
  }, [])

  const measure = (bodyNode: HTMLElement) => {
    window.requestAnimationFrame(() => {
      const bodyHeight = getHeight(bodyNode)
      const newHeight = bodyHeight >= BASE_ROW_HEIGHT ? bodyHeight : EMPTY_STATE_SIZE
      setTableHeight(newHeight + TABLE_HEADER_HEIGHT)
    })
  }

  useLayoutEffect(() => {
    if (!node) {
      return
    }
    measure(node)

    window.addEventListener('resize', () => measure(node))

    return () => {
      window.removeEventListener('resize', () => measure(node))
    }
  }, [node])

  return {
    measures: { tableHeight, rowHeight: 'auto' },
    ref,
    triggerResize: node ? () => measure(node) : () => {},
  }
}

export default useDynamicMeasures

```


[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 paginated-table/react/ExtendedTable.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { EXPERIMENTAL_Table as Table } from 'vtex.styleguide'
import { IdMap } from './useExpandableRows'

interface Column {
  id?: string
  title?: any
  width?: number | string
  sortable?: boolean
  cellRenderer?: any
  extended?: boolean
  condensed?: string[]
}

interface TableProps {
  /** Return of the useTableMeasures hook */
  measures: any
  /** Array of columns */
  columns: Column[]
  /** Array of items */
  items: object[]
  /** Function that generates row keys */
  rowKey?: (data: { rowData: unknown }) => string
  /** If the table is empty or not */
  empty?: boolean
  /** If the Table is loading or not */
  loading?: { renderAs: () => React.ReactNode } | boolean
  /** Function trigged on a row click */
  onRowClick?: (data: { rowData: any }) => void
  /** Function that defines if a row is active or not */
  isRowActive?: (data: unknown) => boolean
  /** Table EmptyState component */
  emptyState?: any
  /** Sorting properties */
  sorting?: {
    sorted?: {
      by?: string,
      order?: string,
    },
    sort: (id: string) => void,
    clear: () => void
    // prop specific to this component
    defaultOrder?: string
  }
  /** Base testId */
  testId?: string
  /** If the rows should be highlighted on :hover */
  highlightOnHover?: boolean
  /** If the header is sticky or not */
  stickyHeader?: boolean

  // props specific to this component
  hovering?: any
  measuringRef?: any
  // return of useExpandableRows hook
  rowExpansion?: {
    isRowExpandedMap?: IdMap
  }
  children?: any
}

const HeadWithoutUpperLine = () => (
  <Table.Sections.Head>
  {({ props, column, key }: any) => {
    return (
      <Table.Sections.Head.Cell key={key} {...props} style={{borderTopStyle: "none"}}>
        {column.title}
      </Table.Sections.Head.Cell>
    )
  }}
  </Table.Sections.Head>
)

const HeadWithDefaultSorting = ({sorting}: {sorting: {
  sorted?: {
    by?: string,
    order?: string,
  },
  sort: (id: string) => void,
  clear: () => void
  defaultOrder?: string
}}) => {
 return (<Table.Sections.Head>
 {({ props, column, key }: any) => {
   const isCurrentlySortedColumn = sorting.sorted?.by === column.id
   const sortingDefaultOrder = sorting.defaultOrder || 'ASC'
   const isAscending = !isCurrentlySortedColumn ? sortingDefaultOrder === 'ASC' : sorting.sorted?.order == 'ASC'
   return (
     <Table.Sections.Head.Cell key={key} {...props} style={{borderTopStyle: "none"}}>
       {column.title}
       <Table.Sections.Head.Cell.Suffix sorting={isCurrentlySortedColumn} ascending={isAscending} />
     </Table.Sections.Head.Cell>
   )
 }}
</Table.Sections.Head> )
}

const CollapsableRow = (props: {key: string,
  onMouseEnter: () => void,
  onRowClick: (data: { rowData: any }) => void,
  isExpanded: boolean
  columns: Column[],
  data: any
}) => {
  const { columns, isExpanded, onRowClick, ...rowProps} = props

  const rowPropsWithExtraInfo = {
    ...rowProps,
    data: {
      ...rowProps.data,
      isExpanded
    }
  }

  return (
    <>
    <Table.Sections.Body.Row
      {...rowPropsWithExtraInfo}
      >
       {({ key, props, content }: any) => (
        <Table.Sections.Body.Row.Cell key={key}
          style= {isExpanded && {backgroundColor: '#EDF4FE', borderBottomStyle: "none"}}
          {...props}
        >
          {content}
        </Table.Sections.Body.Row.Cell>
       )}
      </Table.Sections.Body.Row>
    {
      isExpanded && <tr  onClick={() => onRowClick({ rowData: rowPropsWithExtraInfo.data })}><td colSpan={columns.length} className="bb b--muted-4" style={{backgroundColor: '#EDF4FE'}}>
        <div className="flex justify-center items-center pointer">
          {rowProps.data.extendedRowRenderer}
        </div>
      </td></tr>
    }
    </>
  )
}

const CustomTable = (props: TableProps) => {
  const { children, measuringRef, hovering, ...tableProps } = props

  const { onMouseEnter = () => {}, onMouseLeave = () => {} } = hovering || {}
  const { sorting } = tableProps
  return (
    <Table composableSections {...tableProps}>
      {children}
      <Table.Sections>
        {
          !sorting ?
            <HeadWithoutUpperLine />
          : (
            <HeadWithDefaultSorting sorting={sorting} />
          )
        }
        <Table.Sections.Body ref={measuringRef} onMouseLeave={onMouseLeave}>
          {({ key, props: rowProps }: { key: string; props: any }) => {
            return !rowProps.data.isExpandable || !props.rowExpansion?.isRowExpandedMap ? (
              <Table.Sections.Body.Row
                key={key}
                onMouseEnter={() => onMouseEnter(rowProps.data.id)}
                {...rowProps}
              />
            ) : (
              <CollapsableRow
                key={key}
                onMouseEnter={() => onMouseEnter(rowProps.data.id)}
                onRowClick={tableProps.onRowClick}
                columns={props.columns}
                isExpanded ={props.rowExpansion?.isRowExpandedMap[rowProps.data.id]}
                {...rowProps}
              />
            )
          }}
        </Table.Sections.Body>
      </Table.Sections>
    </Table>
  )
}

export default CustomTable

```


[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 paginated-table/react/PersistedPaginatedTable.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { JSONSchema6Type } from 'json-schema'
import React, { useEffect, useRef } from 'react'
import { defineMessages, useIntl } from 'react-intl'

import { useRuntime } from 'vtex.render-runtime'
import { Table } from 'vtex.styleguide'

const INITIAL_ELEMENTS_PER_PAGE = 15

type Props<TItem, TSchema extends JSONSchema6Type> = {
  total: number
  updatePaginationKey?: string
  defaultElementsPerPage?: number
  defaultSortOrder?: string
  defaultSortedBy?: string
} & TableProps<TItem, TSchema>

interface TableProps<TItem, TSchema extends JSONSchema6Type> {
  items: TItem[]
  schema: TSchema
  loading?: boolean
  fullWidth?: boolean
  density?: 'low' | 'medium' | 'high'
  emptyStateLabel?: React.ReactNode
  emptyStateChildren?: React.ReactNode
  dynamicRowHeight?: boolean
  onRowClick?: OnRowClickHandler<TItem>
  onRowHover?: () => void
  totalizers?: any
  filters?: any
  toolbar?: {
    inputSearch?: {
      value: IntlMessage
      placeholder: React.ReactNode
      onChange: React.ChangeEventHandler<HTMLInputElement>
      onClear: React.ChangeEventHandler<HTMLInputElement>
      onSubmit: React.FormEventHandler<HTMLFormElement>
    }
    density?: {
      buttonLabel: IntlMessage
      lowOptionLabel: IntlMessage
      mediumOptionLabel: IntlMessage
      highOptionLabel: IntlMessage
    }
    fields?: {
      label: IntlMessage
      showAllLabel: IntlMessage
      hideAllLabel: IntlMessage
    }
    download?: {
      label: IntlMessage
      handleCallback: () => void
    }
    upload?: {
      label: IntlMessage
      handleCallback: () => void
    }
    extraActions?: {
      label: IntlMessage
      actions: Array<{
        label: IntlMessage
        handleCallback: () => void
      }>
    }
    newLine?: {
      label: IntlMessage
      handleCallback: () => void
    }
  }
  lineActions?: Array<{
    label: () => IntlMessage
    isDangerous?: boolean
    onClick: () => void
  }>
  bulkActions?: {
    texts: {
      secondaryActionsLabel: string
      rowsSelected: (qty: number) => void
      selectAll: string
      allRowsSelected: () => void
    }
    totalItems?: number
    main: {
      label: string
      handleCallback: (params: { selectedRows: TItem[] }) => void
    }
    others: Array<{
      label: string
      handleCallback: (params: { selectedRows: TItem[] }) => void
    }>
  }
  pagination?: {
    hasPageTopIndicator: boolean
  }
}

export type OnRowClickHandler<TItem> = ({ rowData }: { rowData: TItem }) => void
export type IntlMessage = string | JSX.Element

const messages = defineMessages({
  itemLabel: {
    defaultMessage: '{total, plural, one {item} other {items}}',
    id: 'admin/table.item-label',
  },
  of: {
    defaultMessage: 'of',
    id: 'admin/table.of',
  },
  showRowsLabel: {
    defaultMessage: 'Show rows',
    id: 'admin/table.show-rows',
  },
})

const PersistedPaginatedTable = <TItem, TSchema extends JSONSchema6Type>(
  props: Props<TItem, TSchema>
) => {
  const didMountRef = useRef(false)

  const { setQuery, query } = useRuntime()
  const { formatMessage } = useIntl()

  const {
    items = [],
    total,
    updatePaginationKey,
    defaultSortOrder = 'ASC',
    defaultElementsPerPage = INITIAL_ELEMENTS_PER_PAGE,
    defaultSortedBy = '',
    pagination: { hasPageTopIndicator } = { hasPageTopIndicator: false },
    ...tableProps
  } = props

  const elementsPerPage = parseInt(query.elements, 10) || defaultElementsPerPage

  useEffect(() => {
    if (didMountRef.current) {
      setQuery({ to: elementsPerPage, from: 0, elements: elementsPerPage })
    } else {
      didMountRef.current = true
    }
  }, [updatePaginationKey])

  useEffect(() => {
    if (total && total < query.to) {
      setQuery({ to: elementsPerPage, from: 0, elements: elementsPerPage })
    }
  }, [total])

  const onPageChange = (
    currentFrom: number,
    currentElementsPerPage: number,
    direction: string
  ) => async () => {
    const c = direction === 'next' ? 1 : -1

    const newFrom = currentFrom + c * currentElementsPerPage

    const newTo = Math.min(newFrom + currentElementsPerPage, total)

    setQuery({ to: newTo, from: newFrom, elements: currentElementsPerPage })
  }

  const from = parseInt(query.from, 10) || 0
  const to = parseInt(query.to, 10) || elementsPerPage
  const sortOrder = query.sortOrder || defaultSortOrder
  const sortedBy = query.sortedBy || defaultSortedBy

  return (
    <Table
      fullWidth
      items={items}
      pagination={{
        currentItemFrom: from + 1,
        currentItemTo: to,
        hasPageTopIndicator,
        itemLabel: formatMessage(messages.itemLabel, { total }),
        onNextClick: onPageChange(from, elementsPerPage, 'next'),
        onPrevClick: onPageChange(from, elementsPerPage, 'prev'),
        onRowsChange: async (e: React.ChangeEvent<HTMLSelectElement>) => {
          const newElementsPerPage = parseInt(e.target.value, 10)
          const currentPage = Math.floor(from / newElementsPerPage)
          const newFrom = currentPage * newElementsPerPage
          setQuery({
            elements: newElementsPerPage,
            from: newFrom,
            to: newFrom + newElementsPerPage,
          })
        },
        rowsOptions: [10, 15, 25],
        selectedOption: elementsPerPage,
        textOf: formatMessage(messages.of),
        textShowRows: formatMessage(messages.showRowsLabel),
        totalItems: total,
      }}
      density="low"
      sort={{
        preferentialSortOrder: defaultSortOrder,
        sortOrder,
        sortedBy,
      }}
      onSort={({
        sortOrder: newSortOrder,
        sortedBy: newSortedBy,
      }: {
        sortOrder: string
        sortedBy: string
      }) => {
        setQuery({ sortOrder: newSortOrder, sortedBy: newSortedBy })
      }}
      {...tableProps}
    />
  )
}

export default PersistedPaginatedTable

```


[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 paginated-table/react/usePersistedTableSort.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useRuntime } from 'vtex.render-runtime'

const reverse = (order: string) => {
  if (order === 'DSC') {
    return 'ASC'
  }
  return 'DSC'
}

export default function usePersistedTableSort({
  defaultSortOrder = 'ASC',
}: {
  defaultSortOrder?: string
}) {
  const { setQuery, query } = useRuntime()

  const { sortOrder } = query
  const { sortedBy } = query

  const sort = (id: string) => {
    if (!sortedBy || sortedBy !== id) {
      setQuery({
        sortOrder: defaultSortOrder,
        sortedBy: id,
      })
    } else {
      setQuery({
        sortOrder: reverse(sortOrder),
        sortedBy: id,
      })
    }
  }

  const clear = () => {
    setQuery({
      sortOrder: undefined,
      sortedBy: undefined,
    })
  }

  return {
    sortOrder,
    sortedBy,
    sorting: {
      sorted: {
        order: sortOrder,
        by: sortedBy,
      },
      sort,
      clear: clear,
      defaultOrder: defaultSortOrder,
    },
  }
}

```


[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 paginated-table/react/__tests__/tableRowHovering.test.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

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

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(_query => ({
    matches: false,
    addListener: jest.fn(),
    removeListener: jest.fn(),
  })),
})

const TableWithRowHovering = ({ items }: { items: any[] }) => {
  const [hoveredId, setHoveredId] = useState(null)

  const columns = [
    {
      id: 'name',
      title: 'Name',
      cellRenderer: ({ data }: { data: string }) => <div data-testid="name-cell">{data}</div>,
    },
    {
      id: 'hoverIndicator',
      title: '',
      cellRenderer: ({ data }: { data: { id: string } }) => (
        <div data-testid="hover-indicator-cell">
          {data.id === hoveredId ? 'This row is hovered' : 'This row is NOT hovered'}
        </div>
      ),
      extended: true,
    },
  ]

  const hovering = {
    onMouseEnter: (id: string) => {
      setHoveredId(id)
    },
    onMouseLeave: () => {
      setHoveredId(null)
    },
  }

  return (
    <ExtendedTable
      measures={{ tableHeight: items.length * 100 }}
      items={items}
      columns={columns}
      loading={false}
      hovering={hovering}
    />
  )
}

test('should indicate hovered rows with text', () => {
  const mockItems = [
    {
      id: 1,
      name: 'Product',
    },
    {
      id: 2,
      name: 'Product',
    },
    {
      id: 3,
      name: 'Product',
    },
    {
      id: 4,
      name: 'Product',
    },
    {
      id: 5,
      name: 'Product',
    },
    {
      id: 6,
      name: 'Product',
    },
  ]

  const { getAllByTestId } = render(<TableWithRowHovering items={mockItems} />)

  const firstNameCell = getAllByTestId('name-cell')[0]
  const secondtNameCell = getAllByTestId('name-cell')[1]
  const firstHoverCell = getAllByTestId('hover-indicator-cell')[0]
  const secondHoverCell = getAllByTestId('hover-indicator-cell')[1]
  fireEvent.mouseOver(firstNameCell)

  expect(getNodeText(firstHoverCell)).toBe('This row is hovered')
  expect(getNodeText(secondHoverCell)).toBe('This row is NOT hovered')

  fireEvent.mouseOver(secondtNameCell)

  expect(getNodeText(secondHoverCell)).toBe('This row is hovered')
  expect(getNodeText(firstHoverCell)).toBe('This row is NOT hovered')
})

```


[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 paginated-table/react/__tests__/tableSorting.test.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

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

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(_query => ({
    matches: false,
    addListener: jest.fn(),
    removeListener: jest.fn(),
  })),
})

const TableWithInverseSorting = ({ items }: { items: any[] }) => {
  const { sortOrder, sortedBy: sortBy, sorting } = usePersistedTableSort({
    defaultSortOrder: 'DSC',
  })

  const columns = [
    {
      id: 'name',
      title: 'Name',
      cellRenderer: ({ data }: { data: string }) => <div data-testid="name-cell">{data}</div>,
    },
    {
      id: 'price',
      title: 'Price',
      cellRenderer: ({ data }: { data: number }) => <div data-testid="price-cell">{data}</div>,
      sortable: true,
    },
  ]

  const sortedItems =
    sortBy == 'price' && sortOrder
      ? items.sort((itemA: any, itemB: any) => {
          return sortOrder === 'ASC' ? itemA.price - itemB.price : itemB.price - itemA.price
        })
      : items

  return (
    <ExtendedTable
      measures={{ tableHeight: items.length * 100 }}
      items={sortedItems}
      columns={columns}
      sorting={sorting}
      loading={false}
    />
  )
}

test('should sort in reverse order (dsc first)', () => {
  const mostExpensiveName = 'Most expensive'
  const leastExpensiveName = 'Least expensive'

  const mockItems = [
    {
      id: 1,
      name: 'Product',
      price: 5,
    },
    {
      id: 2,
      name: 'Product',
      price: 5,
    },
    {
      id: 3,
      name: 'Product',
      price: 5,
    },
    {
      id: 4,
      name: mostExpensiveName,
      price: 20,
    },
    {
      id: 5,
      name: leastExpensiveName,
      price: 1,
    },
    {
      id: 6,
      name: 'Product',
      price: 5,
    },
  ]

  const { getByText, getAllByTestId } = render(<TableWithInverseSorting items={mockItems} />)

  const priceHeader = getByText(/price/i)
  fireEvent.click(priceHeader)

  let firstNameCell = getAllByTestId('name-cell')[0]

  expect(getNodeText(firstNameCell)).toBe(mostExpensiveName)

  fireEvent.click(priceHeader)

  firstNameCell = getAllByTestId('name-cell')[0]

  expect(getNodeText(firstNameCell)).toBe(leastExpensiveName)
})

```


[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 paginated-table/react/__tests__/usePersistedPagination.test.ts from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { act, renderHook } from '@vtex/test-tools/react'

import usePersistedPagination from '../usePersistedPagination'

const DEFAULT_TOTAL_ITEMS = 200

jest.mock('react-intl', () => ({
  defineMessages: (messages: any) => messages,
  useIntl: () => ({
    formatMessage: ({ defaultMessage }: any) => defaultMessage,
  }),
}))

const setupHook = (totalItems?: number) => {
  const hook = renderHook(props => usePersistedPagination(props), {
    initialProps: { resetPaginationOnChangeKey: '' }
  })

  act(() => {
    hook.result.current.setTotal(totalItems || DEFAULT_TOTAL_ITEMS)
  })

  return hook
}

const selectEvent = (rows: number) =>
  ({
    target: {
      value: rows.toString(),
    },
  } as any)

test('navigating to last doesnt surpass total', () => {
  const totalItems = 37
  const { result } = setupHook(totalItems)

  expect(result.current.from).toBe(0)
  expect(result.current.to).toBe(15)

  act(() => result.current.paginationProps.onNextClick())

  expect(result.current.from).toBe(15)
  expect(result.current.to).toBe(30)

  act(() => result.current.paginationProps.onNextClick())

  expect(result.current.from).toBe(30)
  expect(result.current.to).toBe(totalItems)
})

test('changing resetPaginationOnChangeKey redirects back to first page', () => {
  const { result, rerender } = setupHook()

  act(() => result.current.paginationProps.onRowsChange(selectEvent(25)))

  act(() => result.current.paginationProps.onNextClick())
  act(() => result.current.paginationProps.onNextClick())

  expect(result.current.from).toBe(50)
  expect(result.current.to).toBe(75)

  rerender({ resetPaginationOnChangeKey: '..' })

  expect(result.current.from).toBe(0)
  expect(result.current.to).toBe(25)
})

test('adjusting elements per page floors page to closest multiple', () => {
  const { result } = setupHook()

  act(() => result.current.paginationProps.onNextClick())

  expect(result.current.paginationProps.selectedOption).toBe(15)
  expect(result.current.from).toBe(15)
  expect(result.current.to).toBe(30)

  act(() => result.current.paginationProps.onRowsChange(selectEvent(10)))

  expect(result.current.paginationProps.selectedOption).toBe(10)
  expect(result.current.from).toBe(10)
  expect(result.current.to).toBe(20)

  act(() => result.current.paginationProps.onRowsChange(selectEvent(25)))

  expect(result.current.paginationProps.selectedOption).toBe(25)
  expect(result.current.from).toBe(0)
  expect(result.current.to).toBe(25)

  act(() => result.current.paginationProps.onNextClick())
  act(() => result.current.paginationProps.onRowsChange(selectEvent(10)))

  expect(result.current.paginationProps.selectedOption).toBe(10)
  expect(result.current.from).toBe(20)
  expect(result.current.to).toBe(30)
})

```


[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 paginated-table/react/__tests__/tablePagination.test.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect } from 'react'
import { render, fireEvent } from '@vtex/test-tools/react'
import ExtendedTable from '../ExtendedTable'
import usePersistedPagination from '../usePersistedPagination'
import { EXPERIMENTAL_Table as Table } from 'vtex.styleguide'

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(_query => ({
    matches: false,
    addListener: jest.fn(),
    removeListener: jest.fn(),
  })),
})

const buildMockItems = (lenght: number) =>
  Array.from(Array(lenght), (_, i) => ({
    id: `${i + 1}`,
    name: `Product ${i + 1}`,
  }))

const TableWithPagination = ({ items, colorFilter }: { items: any[]; colorFilter?: string }) => {
  const columns = [
    {
      id: 'name',
      title: 'Name',
      cellRenderer: ({ data }: { data: string }) => <div data-testid="name-cell">{data}</div>,
    },
  ]

  const totalItems = items.length

  const { to, from, setTotal, paginationProps } = usePersistedPagination({
    defaultElementsPerPage: 15,
    resetPaginationOnChangeKey: `${colorFilter}`,
  })

  useEffect(() => {
    setTotal(totalItems)
  })

  const paginatedItems = items.slice(from, to)

  return (
    <>
      <ExtendedTable
        measures={{ tableHeight: items.length * 100 }}
        items={paginatedItems}
        columns={columns}
        loading={false}>
        <Table.Pagination {...paginationProps} />
      </ExtendedTable>
      <div onClick={() => paginationProps.onNextClick()}>Next Page button</div>
    </>
  )
}

test('pagination resets on filter change', () => {
  const itemsMock = buildMockItems(37)

  const { getByText, rerender } = render(<TableWithPagination items={itemsMock} />)

  expect(getByText('Product 1')).toBeDefined()
  expect(getByText('Product 15')).toBeDefined()

  fireEvent.click(getByText(/next page button/i))

  expect(getByText('Product 16')).toBeDefined()

  rerender(<TableWithPagination items={itemsMock} colorFilter={'pink'} />)

  expect(getByText('Product 1')).toBeDefined()
  expect(getByText('Product 15')).toBeDefined()
})

```


[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 paginated-table/react/__tests__/usePersistedTableSort.test.ts from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { act, renderHook } from '@vtex/test-tools/react'

import usePersistedTableSort from '../usePersistedTableSort'

const columnId = 'column_id'
const differentColumnId = 'column_id2'

test('performing sort updates sort values correctly', () => {

  const { result } = renderHook(() => usePersistedTableSort({}))

  act(() => result.current.sorting.sort(columnId))

  expect(result.current.sortOrder).toBe('ASC')
  expect(result.current.sortedBy).toBe(columnId)

  act(() => result.current.sorting.sort(columnId))

  expect(result.current.sortOrder).toBe('DSC')
  expect(result.current.sortedBy).toBe(columnId)

  act(() => result.current.sorting.sort(differentColumnId))

  expect(result.current.sortOrder).toBe('ASC')
  expect(result.current.sortedBy).toBe(differentColumnId)
})

test('performing clear clears sort', () => {

  const { result } = renderHook(() => usePersistedTableSort({}))

  act(() => result.current.sorting.sort(columnId))
  act(() => result.current.sorting.clear())

  expect(result.current.sortOrder).toBe(undefined)
  expect(result.current.sortedBy).toBe(undefined)
})

test('performing sort with dsc default order starts ordering by dsc', () => {

  const { result } = renderHook(() => usePersistedTableSort({ defaultSortOrder: 'DSC' }))

  act(() => result.current.sorting.sort(columnId))

  expect(result.current.sortOrder).toBe('DSC')
  expect(result.current.sortedBy).toBe(columnId)

  act(() => result.current.sorting.sort(columnId))

  expect(result.current.sortOrder).toBe('ASC')
  expect(result.current.sortedBy).toBe(columnId)

  act(() => result.current.sorting.sort(differentColumnId))

  expect(result.current.sortOrder).toBe('DSC')
  expect(result.current.sortedBy).toBe(differentColumnId)
})

```


[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 paginated-table/react/__tests__/tableRowExpansion.test.tsx from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

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

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(_query => ({
    matches: false,
    addListener: jest.fn(),
    removeListener: jest.fn(),
  })),
})

const TableWithRowExpansion = ({ items }: { items: any[] }) => {
  const columns = [
    {
      id: 'name',
      title: 'Name',
      cellRenderer: ({ data }: { data: string }) => <div data-testid="name-cell">{data}</div>,
    },
  ]

  const rowExpansion = useExpandableRows({
    items,
  })

  return (
    <ExtendedTable
      measures={{ tableHeight: items.length * 100 }}
      items={items}
      columns={columns}
      loading={false}
      onRowClick={({
        rowData: { id },
      }: {
        rowData: {
          id: any
        }
      }) => {
        rowExpansion.toggleExpandRow(id)
      }}
      rowExpansion={rowExpansion}
    />
  )
}

test('should toggle collapsed info on row click', () => {
  const mockItems = [
    {
      id: 1,
      name: 'Product',
      isExpandable: true,
      extendedRowRenderer: <div>Extra hidden data for product 1</div>,
    },
    {
      id: 2,
      name: 'Product',
      isExpandable: true,
      extendedRowRenderer: <div>Extra hidden data for product 2</div>,
    },
    {
      id: 3,
      name: 'Product',
      isExpandable: true,
      extendedRowRenderer: <div>Extra hidden data for product 3</div>,
    },
    {
      id: 4,
      name: 'Product',
      isExpandable: true,
      extendedRowRenderer: <div>Extra hidden data for product 4</div>,
    },
    {
      id: 5,
      name: 'Product',
      isExpandable: true,
      extendedRowRenderer: <div>Extra hidden data for product 5</div>,
    },
    {
      id: 6,
      name: 'Product',
      isExpandable: true,
      extendedRowRenderer: <div>Extra hidden data for product 6</div>,
    },
  ]

  const { getAllByTestId, getByText, findByText } = render(
    <TableWithRowExpansion items={mockItems} />
  )

  const firstNameCell = getAllByTestId('name-cell')[0]
  const secondNameCell = getAllByTestId('name-cell')[1]

  fireEvent.click(firstNameCell)

  expect(getByText('Extra hidden data for product 1')).toBeDefined
  expect(findByText('Extra hidden data for product 2')).not.toBeDefined

  fireEvent.click(secondNameCell)

  expect(getByText('Extra hidden data for product 1')).toBeDefined
  expect(getByText('Extra hidden data for product 2')).toBeDefined

  fireEvent.click(firstNameCell)

  expect(findByText('Extra hidden data for product 1')).not.toBeDefined
  expect(getByText('Extra hidden data for product 2')).toBeDefined
})

```


[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 paginated-table/react/__tests__/useExpandableRows.test.ts from the paginated-table VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { act, renderHook } from '@vtex/test-tools/react'

import useExpandableRows from '../useExpandableRows'

const mockItems = [
  {
    id: "1",
  },
  {
    id: "2",
  },
  {
    id: "3",
  },
  {
    id: "4",
  },
  {
    id: "5",
  },
  {
    id: "6",
  },
  {
    id: "7",
  },
  {
    id: "8",
  }
]

test('starts with no rows expanded', () => {

  const { result } = renderHook(() => useExpandableRows({ items: mockItems }))

  expect(result.current.expandedRowsAmount).toBe(0)
  expect(result.current.isRowExpandedMap["1"]).toBeFalsy()
})

test('toggling rows updates expanded rows map and amount', () => {

  const { result } = renderHook(() => useExpandableRows({ items: mockItems }))

  act(() => result.current.toggleExpandRow("1"))
  act(() => result.current.toggleExpandRow("4"))
  act(() => result.current.toggleExpandRow("5"))

  expect(result.current.expandedRowsAmount).toBe(3)
  expect(result.current.isRowExpandedMap["1"]).toBeTruthy()
  expect(result.current.isRowExpandedMap["4"]).toBeTruthy()
  expect(result.current.isRowExpandedMap["5"]).toBeTruthy()

  act(() => result.current.toggleExpandRow("4"))
  act(() => result.current.toggleExpandRow("5"))

  expect(result.current.expandedRowsAmount).toBe(1)
  expect(result.current.isRowExpandedMap["4"]).toBeFalsy()
  expect(result.current.isRowExpandedMap["5"]).toBeFalsy()

})

test('expanding all updates all rows to expanded', () => {

  const { result } = renderHook(() => useExpandableRows({ items: mockItems }))

  act(() => result.current.expandAll())

  expect(result.current.expandedRowsAmount).toBe(mockItems.length)
  expect(result.current.isRowExpandedMap["1"]).toBeTruthy()
  expect(result.current.isRowExpandedMap["4"]).toBeTruthy()
  expect(result.current.isRowExpandedMap["5"]).toBeTruthy()

  act(() => result.current.toggleExpandRow("5"))

  expect(result.current.expandedRowsAmount).not.toBe(mockItems.length)

  act(() => result.current.expandAll())
  expect(result.current.expandedRowsAmount).toBe(mockItems.length)
  expect(result.current.isRowExpandedMap["5"]).toBeTruthy()

})

test('collapse all updates all rows to collapsed', () => {

  const { result } = renderHook(() => useExpandableRows({ items: mockItems }))

  act(() => result.current.expandAll())
  act(() => result.current.collapseAll())

  expect(result.current.expandedRowsAmount).toBe(0)
  expect(result.current.isRowExpandedMap["1"]).toBeFalsy()
  expect(result.current.isRowExpandedMap["4"]).toBeFalsy()
  expect(result.current.isRowExpandedMap["5"]).toBeFalsy()

  act(() => result.current.toggleExpandRow("5"))
  act(() => result.current.collapseAll())

  expect(result.current.expandedRowsAmount).toBe(0)
  expect(result.current.isRowExpandedMap["5"]).toBeFalsy()

})

```


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

[User] Show me the implementation of store-media/messages/pt.json from the store-media VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.media.title": "Mídia",
  "admin/editor.media.description": "Bloco de mídia que suporta imagens e vídeos",
  "admin/editor.mediaType.title": "Tipo de mídia",
  "admin/editor.mediaType.image": "Imagem",
  "admin/editor.mediaType.video": "Vídeo",
  "admin/editor.mediaList.title": "Lista de Mídias",
  "admin/editor.mediaList.description": "Bloco de Lista de Mídias que suporta uma lista de imagens e vídeos",
  "admin/editor.mediaList.mobileVideo.title": "URL para mobile"
}

```


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

[User] Show me the implementation of store-media/messages/en.json from the store-media VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.media.title": "Media",
  "admin/editor.media.description": "Media block that supports images and videos",
  "admin/editor.mediaType.title": "Media type",
  "admin/editor.mediaType.image": "Image",
  "admin/editor.mediaType.video": "Video",
  "admin/editor.mediaList.title": "Media List",
  "admin/editor.mediaList.description": "Media List block that supports a list of images and videos",
  "admin/editor.mediaList.mobileVideo.title": "URL for mobile"
}

```


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

[User] Show me the implementation of store-media/messages/context.json from the store-media VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.media.title": "Media",
  "admin/editor.media.description": "Media block that supports images and videos",
  "admin/editor.mediaType.title": "Media type",
  "admin/editor.mediaType.image": "Image",
  "admin/editor.mediaType.video": "Video",
  "admin/editor.mediaList.title": "Media List",
  "admin/editor.mediaList.description": "Media List block that supports a list of images and videos",
  "admin/editor.mediaList.mobileVideo.title": "URL for mobile"
}

```


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

[User] Show me the implementation of store-media/messages/es.json from the store-media VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.media.title": "Medio",
  "admin/editor.media.description": "Bloque de medio que admite imágenes y videos",
  "admin/editor.mediaType.title": "Tipo de medio",
  "admin/editor.mediaType.image": "Imagen",
  "admin/editor.mediaType.video": "Vídeo",
  "admin/editor.mediaList.title": "Lista de Medios",
  "admin/editor.mediaList.description": "Bloque de Lista de Medios que admite una lista de imágenes y videos",
  "admin/editor.mediaList.mobileVideo.title": "URL para móvil"
}

```