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

[User] Show me the implementation of tiktok-tbp-callback/node/middlewares/redirect.ts from the tiktok-tbp-callback VTEX app.

[Assistant]
Here's the implementation:

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

export async function redirect(ctx: ServiceContext, next: () => Promise<void>) {
  const redirectState = ctx.state as State

  const redirectUri = `https://${
    redirectState.workspace && redirectState.workspace !== 'master'
      ? `${redirectState.workspace}--`
      : ''
  }${redirectState.account}.myvtex.com/admin/app/tiktok-loading?authCode=${
    redirectState.authCode
  }&tradePolicyId=${redirectState.tradePolicyId}&passPhrase=${
    redirectState.passPhrase
  }`

  ctx.redirect(redirectUri)

  await next()
}

```


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

[User] Show me the implementation of tiktok-tbp-callback/node/middlewares/checkHealth.ts from the tiktok-tbp-callback VTEX app.

[Assistant]
Here's the implementation:

```typescript
export async function checkHealth(ctx: Context, next: () => Promise<void>) {
  const OK = 200

  ctx.status = OK

  await next()
}

```


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

[User] Show me the implementation of admin-ab-tester/messages/pt.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/admin-abtest.navigation.label": "AB Tester",
  "admin/admin.app.abtest.title": "AB Tester",
  "admin/admin.app.abtest.form.label.winnerLabel": "Vencedor",
  "admin/admin.app.abtest.form.label.createTestAB": "Criar Novo Teste AB",
  "admin/admin.app.abtest.form.label.proportion": "Proporção de tráfego ao workspace (1 a 100)",
  "admin/admin.app.abtest.form.label.hours": "Quantas horas o teste durara",
  "admin/admin.app.abtest.form.label.type": "Tipo de teste",
  "admin/admin.app.abtest.form.label.invalidWorkspaceName": "That's not a valid workspace name. Please use only lowercase letters and numbers",
  "admin/admin.app.abtest.form.createTest.success": "Test A/B criado com sucesso",
  "admin/admin.app.abtest.form.finishTest.success": "Test A/B concluído com sucesso",
  "admin/admin.app.abtest.form.saveButton": "Salve",
  "admin/admin.app.abtest.table.label.finish": "Concluir Test A/B",
  "admin/admin.app.abtest.table.label.workspaceName": "Nome Workspace",
  "admin/admin.app.abtest.table.label.conversionLastHours": "Conversão (últimas 24 hs)",
  "admin/admin.app.abtest.table.label.sessions": "Sessões",
  "admin/admin.app.abtest.table.label.sessionsLastHours": "Sessões (últimas 24h)",
  "admin/admin.app.abtest.table.label.hours": "Duração",
  "admin/admin.app.abtest.table.label.proportion": "Proporção",
  "admin/admin.app.abtest.table.label.type": "Modelo",
  "admin/admin.app.abtest.table.label.conversion": "Conversion",
  "admin/admin.app.abtest.table.label.abtestbeginning": "Data de criação",
  "admin/admin.app.abtest.table.label.workspace": "Workspace",
  "admin/admin.app.abtest.table.label.workspaceb": "Workspace B",
  "admin/admin.app.abtest.table.label.winner": "Vencedor",
  "admin/admin.app.abtest.table.label.conversiona": "Conversão A",
  "admin/admin.app.abtest.table.label.conversionb": "Conversão B",
  "admin/admin.app.abtest.table.label.conversionlast24hours": "Conversão (últimas 24h)",
  "admin/admin.app.abtest.table.label.workspaceasessions": "Workspace A Sessões",
  "admin/admin.app.abtest.table.label.workspacesessions": "Sessões do espaço de trabalho",
  "admin/admin.app.abtest.table.label.workspacebsessions": "Workspace B Sessões",
  "admin/admin.app.abtest.table.label.workspacesessionslast24hours": "Sessões do espaço de trabalho A (últimas 24h)",
  "admin/admin.app.abtest.table.label.finishLabel": "Concluir"
}

```


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

[User] Show me the implementation of admin-ab-tester/messages/en.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/admin-abtest.navigation.label": "AB Tester",
  "admin/admin.app.abtest.title": "AB Tester",
  "admin/admin.app.abtest.form.label.winnerLabel": "Winner",
  "admin/admin.app.abtest.form.label.createTestAB": "Create New AB Test",
  "admin/admin.app.abtest.form.label.proportion": "Traffic Proportion for workspace (1 to 100)",
  "admin/admin.app.abtest.form.label.hours": "How many hours will last",
  "admin/admin.app.abtest.form.label.type": "Test Type",
  "admin/admin.app.abtest.form.label.invalidWorkspaceName": "That's not a valid workspace name. Please use only lowercase letters and numbers",
  "admin/admin.app.abtest.form.createTest.success": "A/B Test beginning saved successfully",
  "admin/admin.app.abtest.form.finishTest.success": "A/B Test finished successfully",
  "admin/admin.app.abtest.form.saveButton": "Save",
  "admin/admin.app.abtest.table.label.finish": "Finish A/B Test",
  "admin/admin.app.abtest.table.label.workspaceName": "Workspace Name",
  "admin/admin.app.abtest.table.label.conversionLastHours": "Conversion (last 24h)",
  "admin/admin.app.abtest.table.label.sessions": "Sessions",
  "admin/admin.app.abtest.table.label.sessionsLastHours": "Sessions (last 24h)",
  "admin/admin.app.abtest.table.label.hours": "Duration",
  "admin/admin.app.abtest.table.label.proportion": "Proportion",
  "admin/admin.app.abtest.table.label.type": "Type",
  "admin/admin.app.abtest.table.label.conversion": "Conversion",
  "admin/admin.app.abtest.table.label.abtestbeginning": "Creation Date",
  "admin/admin.app.abtest.table.label.workspace": "Workspace",
  "admin/admin.app.abtest.table.label.workspaceb": "Workspace B",
  "admin/admin.app.abtest.table.label.winner": "Winner",
  "admin/admin.app.abtest.table.label.conversiona": "Conversion A",
  "admin/admin.app.abtest.table.label.conversionb": "Conversion B",
  "admin/admin.app.abtest.table.label.conversionlast24hours": "Conversion (last 24h)",
  "admin/admin.app.abtest.table.label.workspaceasessions": "Workspace A Sessions",
  "admin/admin.app.abtest.table.label.workspacesessions": "Workspace Sessions",
  "admin/admin.app.abtest.table.label.workspacebsessions": "Workspace B Sessions",
  "admin/admin.app.abtest.table.label.workspacesessionslast24hours": "Workspace Sessions (last 24h)",
  "admin/admin.app.abtest.table.label.finishLabel": "Finish"
}

```


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

[User] Show me the implementation of admin-ab-tester/messages/context.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/admin-abtest.navigation.label": "AB Tester",
  "admin/admin.app.abtest.title": "AB Tester",
  "admin/admin.app.abtest.form.label.winnerLabel": "Winner",
  "admin/admin.app.abtest.form.label.createTestAB": "Create New AB Test",
  "admin/admin.app.abtest.form.label.proportion": "Traffic Proportion for workspace (1 to 100)",
  "admin/admin.app.abtest.form.label.hours": "How many hours will last",
  "admin/admin.app.abtest.form.label.type": "Test Type",
  "admin/admin.app.abtest.form.label.invalidWorkspaceName": "That's not a valid workspace name. Please use only lowercase letters and numbers",
  "admin/admin.app.abtest.form.createTest.success": "A/B Test beginning saved successfully",
  "admin/admin.app.abtest.form.finishTest.success": "A/B Test finished successfully",
  "admin/admin.app.abtest.form.saveButton": "Save",
  "admin/admin.app.abtest.table.label.finish": "Finish A/B Test",
  "admin/admin.app.abtest.table.label.workspaceName": "Workspace Name",
  "admin/admin.app.abtest.table.label.conversionLastHours": "Conversion (last 24h)",
  "admin/admin.app.abtest.table.label.sessions": "Sessions",
  "admin/admin.app.abtest.table.label.sessionsLastHours": "Sessions (last 24h)",
  "admin/admin.app.abtest.table.label.hours": "Duration",
  "admin/admin.app.abtest.table.label.proportion": "Proportion",
  "admin/admin.app.abtest.table.label.type": "Type",
  "admin/admin.app.abtest.table.label.conversion": "Conversion",
  "admin/admin.app.abtest.table.label.abtestbeginning": "Creation Date",
  "admin/admin.app.abtest.table.label.workspace": "Workspace",
  "admin/admin.app.abtest.table.label.workspaceb": "Workspace B",
  "admin/admin.app.abtest.table.label.winner": "Winner",
  "admin/admin.app.abtest.table.label.conversiona": "Conversion A",
  "admin/admin.app.abtest.table.label.conversionb": "Conversion B",
  "admin/admin.app.abtest.table.label.conversionlast24hours": "Conversion (last 24h)",
  "admin/admin.app.abtest.table.label.workspaceasessions": "Workspace A Sessions",
  "admin/admin.app.abtest.table.label.workspacesessions": "Workspace Sessions",
  "admin/admin.app.abtest.table.label.workspacebsessions": "Workspace B Sessions",
  "admin/admin.app.abtest.table.label.workspacesessionslast24hours": "Workspace Sessions (last 24h)",
  "admin/admin.app.abtest.table.label.finishLabel": "Finish"
}

```


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

[User] Show me the implementation of admin-ab-tester/messages/es.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/admin-abtest.navigation.label": "AB Tester",
  "admin/admin.app.abtest.title": "AB Tester",
  "admin/admin.app.abtest.form.label.winnerLabel": "Ganador",
  "admin/admin.app.abtest.form.label.createTestAB": "Crear Nuevo Test AB",
  "admin/admin.app.abtest.form.label.proportion": "Proporción del tráfico al workspace (1 a 100)",
  "admin/admin.app.abtest.form.label.hours": "Cuántas horas durará",
  "admin/admin.app.abtest.form.label.type": "Tipo del test",
  "admin/admin.app.abtest.form.label.invalidWorkspaceName": "No es un nombre de workspace válido. Utilice solo letras y números en minúscula",
  "admin/admin.app.abtest.form.createTest.success": "Test A/B creado correctamente",
  "admin/admin.app.abtest.form.finishTest.success": "Test A/B finalizado correctamente",
  "admin/admin.app.abtest.form.saveButton": "Guardar",
  "admin/admin.app.abtest.table.label.finish": "Terminar Test A/B",
  "admin/admin.app.abtest.table.label.workspaceName": "Nombre del Workspace",
  "admin/admin.app.abtest.table.label.conversionLastHours": "Conversión (últimas 24h)",
  "admin/admin.app.abtest.table.label.sessions": "Sesiones",
  "admin/admin.app.abtest.table.label.sessionsLastHours": "Sesiones (últimas 24h)",
  "admin/admin.app.abtest.table.label.hours": "Duración",
  "admin/admin.app.abtest.table.label.proportion": "Proporción",
  "admin/admin.app.abtest.table.label.type": "Tipo",
  "admin/admin.app.abtest.table.label.conversion": "Conversión",
  "admin/admin.app.abtest.table.label.abtestbeginning": "Fecha de creación",
  "admin/admin.app.abtest.table.label.workspace": "Workspace",
  "admin/admin.app.abtest.table.label.workspaceb": "Workspace B",
  "admin/admin.app.abtest.table.label.winner": "Ganador",
  "admin/admin.app.abtest.table.label.conversiona": "Conversión A",
  "admin/admin.app.abtest.table.label.conversionb": "Conversión B",
  "admin/admin.app.abtest.table.label.conversionlast24hours": "Conversión (últimas 24h)",
  "admin/admin.app.abtest.table.label.workspaceasessions": "Workspace A Sesiones",
  "admin/admin.app.abtest.table.label.workspacesessions": "Sesiones Workspace",
  "admin/admin.app.abtest.table.label.workspacebsessions": "Workspace B Sesiones",
  "admin/admin.app.abtest.table.label.workspacesessionslast24hours": "Sesiones Workspace (últimas 24h)",
  "admin/admin.app.abtest.table.label.finishLabel": "Finalizar"
}

```


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

[User] Show me the implementation of admin-ab-tester/admin/navigation.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "section": "other",
  "titleId": "admin/admin-abtest.navigation.label",
  "path": "/admin/ab-test"
}

```


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

[User] Show me the implementation of admin-ab-tester/admin/routes.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin.app": {
    "component": "ABTest",
    "path": "/admin/app/ab-test"
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/docs/README.md from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

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

# AB Tester

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

##  ⚠ Maintenance ⚠
*Starting June 1st 2023, this application will no longer be maintained by VTEX.*

---

The A/B Tester app allows you to list, start and finish A/B tests via the VTEX Admin.

![A/B Tester Settings](https://user-images.githubusercontent.com/36748003/138300964-63bc3545-efd7-435c-acd6-3e3e3a35b285.png)

In the following, you'll learn how to install and use the A/B Tester app.

----

## Configuration

Take the following steps to install the AB Tester app on your VTEX Admin.

1. Open the terminal and use the [VTEX IO CLI](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-vtex-io-cli-installation-and-command-reference) to log in to the desired VTEX account.
2. Install the A/B Tester app in the `master` workspace to enable A/B testing on your store website by running:
    ```
    vtex use master
    vtex install vtex.ab-tester
    ```
3. Install the **A/B Tester Admin app** in the `master` workspace:
   ```
   vtex install vtexarg.abtester
   ```

## Usage

After installing the AB Tester app, you'll be able to:
- Create A/B tests.
- Compare A/B test results.
- Finish an A/B test.

### Creating an A/B test

In the following step by step, you will learn how to set up a new A/B test. Notice that, before proceeding any further, you must already have a [production workspace](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-creating-a-production-workspace) containing the changes you want to evaluate.

1. Access the VTEX Admin.
2. Go to **Others > AB Tester**.
3. Click on **Create new AB test**.
4. Fill out the presented fields as in the following:
   - **Workspace Name -** Enter the name of the production workspace containing the changes you want to examine via the A/B test.
   - **Traffic Proportion -** Enter the desired traffic proportion to be destined for the **master** workspace during the first hours of the A/B test. This value must be any whole number between 0 and 10000. For example, to set 90% of the traffic to the master workspace, enter 9000.
   - **Amount of Time -** Enter the amount of time (in hours) during which the specified **Traffic Proportion** will be maintained. After this period, the traffic proportions of the test will be automatically updated by the A/B testing system. Enter `0` if you prefer the A/B testing system to take care of your website traffic distribution from the start.
     >ℹ The A/B testing automatically balances traffic every 3 minutes according to the conversion or revenue rates.
   - **Test Type -** Enter what the A/B test must evaluate: revenue or conversion.
5. Click on **Save**.

Once you save your changes, the A/B test will start immediately, splitting your website traffic according to your preferences.

### Comparing results

After creating your A/B test, the **AB Tester** app will provide a table containing some metrics that will help you evaluate and interpret the test status. This table contains the following information:

* **Conversion** - Conversion rate percentage that each workspace presented during the test.
* **Conversion (last 24hrs)** - Conversion rate percentage that each workspace presented during the test's last 24 hours.
* **N. of Sessions** - Total number of sessions of each workspace since the beginning of the test.
* **N. of Sessions (last 24hrs)** - Number of sessions for each workspace during the test's last 24 hours.

### Finishing an A/B Test

Although automatic, an A/B test will not end by itself. Take the following steps to terminate an A/B test:

1. Access the VTEX Admin.
2. Go to **Others > AB Tester** and scroll the horizontal bar until you see a Kebab menu.
3. Click on the Kebab menu and click on **Finish A/B Test**.

----

## Related Resources

- [Running native A/B tests](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-running-native-ab-testing)

----

## 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/tomymehdi"><img src="https://avatars.githubusercontent.com/u/774112?v=4" width="100px;" alt=""/><br /><sub><b>Tomás Alfredo Mehdi</b></sub></a><br /><a href="https://github.com/vtex-apps/admin-ab-tester/commits?author=tomymehdi" 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 are welcome!

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

```


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

[User] Show me the implementation of admin-ab-tester/graphql/schema.graphql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Query {
  getTests: GetTestsResponse
  getData(key: String!): String
  @cacheControl(scope: PUBLIC, maxAge: MEDIUM)
}

type Mutation {
  initialize(workspace: String!, proportion: Int!, hours: Int!, type: String): CreateTestResponse
  finishTest(workspace: String!): FinishTestResponse
  saveData(key: String!, value: 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 admin-ab-tester/node/service.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 256,
  "ttl": 10,
  "timeout": 5,
  "minReplicas": 2,
  "maxReplicas": 4,
  "workers": 1
}

```


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

[User] Show me the implementation of admin-ab-tester/node/utils.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

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

export const BUCKET_NAME = 'product-translation'
export const ALL_TRANSLATIONS_FILES = 'all-translations'

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

  const {
    response: { status },
  } = e

  switch (status) {
    case 401: {
      throw new AuthenticationError(e)
    }

    case 403: {
      throw new ForbiddenError(e)
    }

    case 400: {
      throw new UserInputError(e)
    }

    default:
      throw new TypeError(e.message)
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/node/package.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "co-body": "^6.0.0",
    "moment": "^2.29.4"
  },
  "devDependencies": {
    "@types/co-body": "^0.0.3",
    "@types/node": "12.x",
    "@vtex/api": "6.45.15",
    "eslint": "^7.16.0",
    "eslint-config-vtex": "^12.9.3",
    "prettier": "^1.18.2",
    "typescript": "3.9.7"
  },
  "resolutions": {
    "**/**/lodash": "^4.17.19"
  },
  "scripts": {
    "lint": "tsc --noEmit --pretty"
  },
  "version": "1.0.14"
}

```


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

[User] Show me the implementation of admin-ab-tester/node/index.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { LRUCache, Service, ParamsContext } from '@vtex/api'

import { Clients } from './clients'
import { resolvers } from './resolvers'

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

metrics.trackCache('status', memoryCache)

export default new Service<Clients, State, ParamsContext>({
  clients: {
    implementation: Clients,
    options: {
      default: {
        retries: 2,
        timeout: 10000,
      },
    },
  },
  graphql: {
    resolvers,
  },
})

```


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

[User] Show me the implementation of admin-ab-tester/react/ABTest.tsx from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import Main from './components/Main'
import './styles.global.css'
import { ABTestProvider } from './context/index'

const ABTest: FC = () => {
  return (
    <ABTestProvider>
      <Main />
    </ABTestProvider>
  )
}

export default ABTest

```


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

[User] Show me the implementation of admin-ab-tester/react/package.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.admin-example",
  "version": "1.0.14",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "@types/node": "^11.12.1",
    "@types/react": "^16.8.10",
    "@types/react-intl": "^2.3.17",
    "apollo-client": "^2.4.7",
    "graphql": "^14.0.2",
    "prop-types": "^15.7.2",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-intl": "^2.7.2",
    "typescript": "3.9.7"
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/react/styles.global.css from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```css
html,
body,
#render-container,
#render-provider,
.render-container,
.render-provider {
  height: 100%;
}

```


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

[User] Show me the implementation of admin-ab-tester/react/utils.tsx from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import {
  Button,
} from 'vtex.styleguide'
import { FormattedMessage } from 'react-intl'

import { useABTestContext } from './context/'

export const checkWorkspaceName = (name: string) => {
  if (name === "") return false
  const noSpecialChars = new RegExp(
    '^.*[-!$%^&*()_+|~=`{}[\\]:";\'<>?,./]+.*$'
  );
  const noMayusc = new RegExp('[A-Z]');
  if (!noSpecialChars.test(name) && !noMayusc.test(name)) {
    return true;
  } else {
    return false;
  }
};

export const formatData = (data: any) => {
  const flattenData: any = [];

  const keys = Object.keys(data[0]);

  keys.forEach((key) => {
    const aux: any = {};
    const masterKeys = ['ConversionA', 'ConversionALast24Hours', 'WorkspaceASessions', 'WorkspaceASessionsLast24Hours']
    data.forEach((item: any) => {
      if (key !== '__typename' && key !== 'Finish' && key !== '[[Prototype]]' && key !== 'WorkspaceA' && key !== 'WorkspaceB') {
        if (masterKeys.includes(key)) {
          aux[item.WorkspaceA] = item[key]
          aux[item.WorkspaceB] = null
        } else {
          aux[item.WorkspaceA] = null
          aux[item.WorkspaceB] = item[key]
        }
      }
      if (key === 'Finish') (aux[item.WorkspaceB] = { type: 'finish', value: item[key] })
      if (key === 'proportion') (aux[item.WorkspaceB] = { type: 'proportion', value: item[key] })
      if (key !== '__typename' && key !== "WorkspaceB" && key !== "WorkspaceA") aux.Value = { type: 'key', value: key }
    });
    flattenData.push(aux);
  });

  const toUnify = [
    'ConversionA',
    'ConversionB',
    'ConversionALast24Hours',
    'ConversionBLast24Hours',
    'WorkspaceASessions',
    'WorkspaceBSessions',
    'WorkspaceASessionsLast24Hours',
    'WorkspaceBSessionsLast24Hours'
  ]

  const formattedData: any = flattenData.filter((item: any) => {
    return !toUnify.includes(item?.Value?.value) && Object.keys(item).length !== 0
  });

  const newData = formattedData.slice(0, -1)

  for (let i = 0; i < toUnify.length; i = i + 2) {
    merge(flattenData.find((item: any) => item.Value?.value === toUnify[i]), flattenData.find((item: any) => item.Value?.value === toUnify[i + 1]))
  }

  function merge(obj1: any, obj2: any) {
    const answer: any = {}
    for (let key in obj1) {
      if (answer[key] === undefined || answer[key] === null)
        answer[key] = obj1[key];
    }
    for (let key in obj2) {
      if (answer[key] === undefined || answer[key] === null)
        answer[key] = obj2[key];
    }
    if (obj1?.Value) {
      switch (obj1.Value?.value) {
        case 'ConversionA' || 'ConversionB': {
          answer.Value.value = 'Conversion'
          newData.push(answer)
          break
        }
        case 'ConversionALast24Hours' || 'ConversionBLast24Hours': {
          answer.Value.value = 'ConversionLast24Hours'
          newData.push(answer)
          break
        }
        case 'WorkspaceASessions' || 'WorkspaceBSessions': {
          answer.Value.value = 'WorkspaceSessions'
          newData.push(answer)
          break
        }
        case 'WorkspaceASessionsLast24Hours' || 'WorkspaceBSessionsLast24Hours': {
          answer.Value.value = 'workspacesessionslast24hours'
          newData.push(answer)
          break
        }
      }
    }
    return answer
  }
  newData.push(formattedData[formattedData.length - 1])

  return newData
}

export const getPropertiesForSchema = (tests: any) => {
  const { finishTest } = useABTestContext()

  const properties: any = {};
  properties.Value = {
    name: {
      title: '',
      width: 600
    },
  }
  tests.length && Object.keys(tests[0]).forEach((item) => {
    properties[item] = {
      title: item, width: item !== "Value" ? 250 : 300, cellRenderer: ({ cellData }: { cellData: any }) => {
        return (
          <>
            {
              cellData?.type === 'finish' ? <Button onClick={() => finishTest(cellData.value)}><FormattedMessage id={`admin/admin.app.abtest.table.label.finishLabel`} /> </Button> : cellData?.type === 'key' ? <span className="b c-muted-2"><FormattedMessage id={`admin/admin.app.abtest.table.label.${cellData.value.toLowerCase()}`} /></span> : cellData?.type === 'proportion' ? <p>%{cellData.value}</p> : cellData
            }
          </>
        )
      },
    }
  }

  );

  return properties
}

```


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

[User] Show me the implementation of admin-ab-tester/public/metadata/messages/es-AR.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "AB Tester",
  "headline": "Crea, lista y finaliza los AB test.",
  "overview": "AB Tester te permite ejecutar diferentes versiones de tu tienda para probar ideas y mejorar la experiencia de usuario.",
  "features": [
    "Listar AB test",
    "Finalizar AB test",
    "Crear AB tests"
  ],
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://support.vtex.com/hc/requests"
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/public/metadata/messages/pt-BR.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "AB Tester",
  "headline": "Crie, liste e finalize testes AB.",
  "overview": "O AB Tester permite que você execute diferentes versões de sua loja para testar ideias e melhorar a experiência do usuário.",
  "features": [
    "Obter teste AB atual",
    "Terminar um teste AB",
    "Criar um teste AB"
  ],
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://support.vtex.com/hc/requests"
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/public/metadata/messages/en-US.json from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "AB Tester",
  "headline": "Create, list and finish AB tests.",
  "overview": "AB Tester allows you to run different versions of your store to test ideas and improve the user experience.",
  "features": [
    "Get current AB Test",
    "Finish an AB Test",
    "Create a AB Test"
  ],
  "websiteURL": "https://vtex.com/",
  "support": {
    "url": "https://support.vtex.com/hc/requests"
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/graphql/types/createTest.graphql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
type CreateTestResponse{
  status: String,
  data: 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 admin-ab-tester/graphql/types/finishTest.graphql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
type FinishTestResponse{
  status: String,
  data: 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 admin-ab-tester/graphql/types/getTests.graphql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
type GetTestsResponse{
  data: [DataResponse]
  status: Int
  error: String
}

type DataResponse {
  ABTestBeginning: String
  WorkspaceA: String
  WorkspaceB: String
  Winner: String
  ConversionA: Float
  ConversionALast24Hours: Float
  ConversionB: Float
  ConversionBLast24Hours: Float
  WorkspaceASessions: Int
  WorkspaceBSessions: Int
  WorkspaceASessionsLast24Hours: Int
  WorkspaceBSessionsLast24Hours: Int
  hours: Int
  proportion: Int
  type: String
  Finish: 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 admin-ab-tester/node/clients/abtest.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { InstanceOptions, IOContext } from '@vtex/api'
import { ExternalClient } from '@vtex/api'
export default class ABtest extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(`http://app.io.vtex.com/vtex.ab-tester/v0`, context, {
      ...options,
    })
  }

  public async getTests() {
    try {
      const res = await this.http.getRaw(`/${this.context.account}/master/_v/private/abtesting/status`, {
        headers: {
          Authorization: `Bearer ${this.context.adminUserAuthToken}`,
        },
      })
      return res
    } catch (err) {
      return { data: err }
    }

  }

  public async initialize(workspace: string, proportion: number, hours: number, type: string) {
    const payload = {
      "InitializingWorkspaces": workspace,
      "Proportion": proportion,
      "Hours": hours,
      "Type": type
    }
    return await this.http.postRaw(`/${this.context.account}/master/_v/private/abtesting/initialize`, payload, {
      headers: {
        Authorization: `Bearer ${this.context.adminUserAuthToken}`,
      },
    })
  }

  public async finishTest(workspace: string) {
    return await this.http.delete(`/${this.context.account}/master/_v/private/abtesting/finish/${workspace}`, {
      headers: {
        Authorization: `Bearer ${this.context.adminUserAuthToken}`,
      },
    })
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/node/clients/index.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

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

import ABtest from './abtest'

export class Clients extends IOClients {
  public get abtest() {
    return this.getOrSet('abtest', ABtest)
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/node/typings/global.d.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { RecorderState, ServiceContext } from '@vtex/api'

declare global {
  type Context = ServiceContext<IOClients, State>

  interface State extends RecorderState {
    code: number
  }

  interface WorkspaceMetadata {
    name: string;
    weight: number;
    production: boolean;
  }

  interface ABTest {
    ABTestBeginning: string
    Winner: string
    WorkspaceB: string
    ConversionA: number
    ConversionALast24Hours: number
    ConversionB: number
    ConversionBLast24Hours: number
    WorkspaceBSessions: number
    WorkspaceBSessionsLast24Hours: number
    hours: number
    proportion: number
    type: string
    Finish: 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 admin-ab-tester/node/resolvers/index.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  queries as abtestQueries,
  mutations as abtestMutations
} from './abtest'
import { queries as vbaseQueries, mutations as vbaseMutations } from './vbase'

export const resolvers = {
  Query: {
    ...abtestQueries,
    ...vbaseQueries,
  },
  Mutation: {
    ...abtestMutations,
    ...vbaseMutations,
  },
}

```


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

[User] Show me the implementation of admin-ab-tester/node/resolvers/abtest/index.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```typescript
import moment from 'moment'

export const queries = {
  getTests: async (_: unknown, __: unknown, { vtex: { logger }, clients: { abtest, vbase } }: Context
  ): Promise<any> => {
    const { data }: any = await abtest.getTests()
    logger.info({
      message: 'admin-ab-tester',
      action: 'list',
      data: data,
    })
    if (data.length) {
      for await (let element of data) {
        try {
          const extraData = await vbase.getJSON<string>('abtesterData', element.WorkspaceB)
          const parsedExtraData = JSON.parse(extraData.replace(/'/g, '"'));
          Object.entries(parsedExtraData).forEach(
            ([key, value]) => element[key] = value
          );
        } catch (err) {
          continue
        }
      }
      data.forEach((item: ABTest) => {
        item.ABTestBeginning = moment(item.ABTestBeginning).format("DD/MM/YYYY")
        item.Finish = item.WorkspaceB
      });
      return { status: 201, data: data, error: "" }
    } else {
      return { status: 404, data: [""], error: data?.response?.data?.message }
    }

  }
}

export const mutations = {
  initialize: async (
    _: unknown,
    { workspace, proportion, hours, type }: {
      workspace: string, proportion: number, hours: number, type: string
    },
    ctx: Context
  ): Promise<string> => {
    ctx.vtex.logger.info({
      message: 'admin-ab-tester',
      action: 'initialize'
    })
    return await ctx.clients.abtest.initialize(workspace, proportion, hours, type)
  },
  finishTest: async (
    _: unknown,
    { workspace }: { workspace: string },
    ctx: Context
  ): Promise<string> => {
    ctx.vtex.logger.info({
      message: 'admin-ab-tester',
      action: 'finish'
    })
    return await ctx.clients.abtest.finishTest(workspace)
  },
}

```


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

[User] Show me the implementation of admin-ab-tester/node/resolvers/vbase/index.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const queries = {
  getData: async (
    _: unknown,
    { key }: { key: string },
    ctx: Context
  ): Promise<any> => {
    const aux = await ctx.clients.vbase.getJSON<{ key: string }>(
      'abtesterData',
      key
    )

    return aux
  },
}

export const mutations = {
  saveData: async (
    _: unknown,
    {
      key,
      value,
    }: {
      key: string
      value: string
    },
    ctx: Context
  ): Promise<void> => {
    await ctx.clients.vbase.saveJSON('abtesterData', key, value)
  },
}

```


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

[User] Show me the implementation of admin-ab-tester/react/context/index.tsx from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, createContext, useEffect, useContext } from 'react'
import { useMutation, useLazyQuery } from 'react-apollo'
import { useIntl } from 'react-intl'

import getTestsGQL from './../graphql/getTests.gql'
import createTestMutation from './../graphql/createTest.gql'
import finishTestMutation from './../graphql/finishTest.gql'
import saveDataGQL from './../graphql/saveData.gql'
import { formatData } from "./../utils"

export const ABTestContext = createContext({} as ABTestContextInterface)

export const useABTestContext = () => useContext(ABTestContext)

export function ABTestProvider({ children }: ContextChildren) {
  const intl = useIntl()
  const [saveData] = useMutation(saveDataGQL)
  const [getTestsQuery, { data: dataGetTests, loading: loadingGetTests, refetch: refetchGetTests }] = useLazyQuery(getTestsGQL)

  const [tests, setTests] = useState<ABTest[]>([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState("")
  const [success, setSuccess] = useState("")
  const [emptyMessage, setEmptyMessage] = useState("")

  const [testToCreate, setTestToCreate] = useState<NewTest>({
    name: "",
    proportion: 0,
    hours: 0,
    type: ""
  })

  const [createTest,
    {
      loading: loadingCreate,
      error: errorCreate,
      data: dataCreate,
    }] = useMutation(createTestMutation)

  const [finishTestGQL,
    {
      loading: loadingFinish,
      error: errorFinish,
      data: dataFinish,
    }] = useMutation(finishTestMutation)

  const [modalOpen, setModalOpen] = useState({
    isOpen: false,
    type: "CREATE"
  })

  const handleNewModal = (isOpen: boolean, type: string) => {
    setModalOpen({
      isOpen: isOpen,
      type: type
    })
  }

  const clearGeneralState = () => {
    setError("")
    setSuccess("")
    setLoading(false)
  }

  useEffect(() => {
    getTestsQuery()
  }, [])

  useEffect(() => {
    loadingGetTests && setLoading(true)
    if (dataGetTests) {
      if (dataGetTests.getTests?.status === 201) {
        setTests(formatData(dataGetTests.getTests?.data))
        setLoading(false)
      } else {
        setLoading(false)
        setTests([])
        setEmptyMessage(dataGetTests.getTests?.error)
      }
    }
  }, [dataGetTests])

  const createNewTest = (newTest: NewTest) => {
    newTest.proportion = (10000 - newTest.proportion) / 100
    createTest({ variables: { workspace: newTest.name, proportion: Number(newTest.proportion), hours: Number(newTest.hours), type: newTest.type } })
    setTestToCreate(newTest)
  }

  const finishTest = (workspace: string) => {
    finishTestGQL({ variables: { workspace: workspace } })
  }

  useEffect(() => {
    loadingCreate && setLoading(true)
    if (errorCreate) {
      setError(errorCreate.graphQLErrors[0].extensions?.exception?.response?.data)
    }
    if (dataCreate) {
      setLoading(false);
      refetchGetTests()
      setSuccess(intl.formatMessage({ id: 'admin/admin.app.abtest.form.createTest.success' }))
      handleNewModal(false, "CREATE")
      //if the test is successfully created we save the data in vbase to show it in the table
      saveData({ variables: { key: testToCreate.name, value: `"{'proportion':${testToCreate.proportion},'hours':${testToCreate.hours},'type': '${testToCreate.type}'}"` } })
    }
  }, [loadingCreate, errorCreate, dataCreate])

  useEffect(() => {
    loadingFinish && setLoading(true)
    if (errorFinish) {
      setError(errorFinish.graphQLErrors[0].extensions?.exception?.response?.data)
    }
    if (dataFinish) {
      setLoading(false);
      refetchGetTests()
      setSuccess(intl.formatMessage({ id: 'admin/admin.app.abtest.form.finishTest.success' }))
    }
  }, [loadingFinish, errorFinish, dataFinish])

  return (
    <ABTestContext.Provider
      value={{
        tests,
        handleNewModal,
        modalOpen,
        createNewTest,
        finishTest,
        error,
        loading,
        success,
        setError,
        clearGeneralState,
        emptyMessage
      }}
    >
      {children}
    </ABTestContext.Provider>
  )
}

```


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

[User] Show me the implementation of admin-ab-tester/react/typings/storefront.d.ts from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

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

declare global {
  interface ContextChildren {
    children: ReactNode
  }
  interface ABTest {
    [x: string]: any;
    ABTestBeginning: string
    Winner: string
    WorkspaceA: string
    WorkspaceB: string
    ConversionA: number
    ConversionALast24Hours: number
    ConversionB: number
    ConversionBLast24Hours: number
    WorkspaceASessions: number
    WorkspaceBSessions: number
    WorkspaceASessionsLast24Hours: number
    WorkspaceBSessionsLast24Hours: number
  }
  interface ABTestContextInterface {
    tests: ABTest[] | undefined
    handleNewModal: (isOpen: boolean, type: "CREATE" | "DELETE") => void
    modalOpen: Modal
    createNewTest: (test: NewTest) => void
    finishTest: (workspace: string) => void
    loading: boolean
    error: string
    success: string
    setError: (error: string) => void
    clearGeneralState: () => void
    emptyMessage: string
  }
  interface GeneralState {
    loading: boolean,
    error: string,
    success: string
  }
  interface Modal {
    isOpen: boolean,
    type: string
  }
  interface EventInterface {
    target: {
      value: string
      name: string
    }
  }
  interface NewTest {
    name: string
    proportion: number
    hours: number
    type: string
  }
  interface RowHeader {
    rowData: ABTest
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/react/components/Main.tsx from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC, useEffect } from 'react'
import { FormattedMessage } from 'react-intl'
import { Layout, PageBlock, PageHeader } from 'vtex.styleguide'
import ABTable from './Table/Table'
import { useABTestContext } from '../context';

const Main: FC = () => {
  return (
    <Layout
      pageHeader={
        <PageHeader
          title={<FormattedMessage id="admin/admin.app.abtest.title" />}
        />
      }
    >
      <PageBlock variation="full">
        <ABTable />
      </PageBlock>
    </Layout>
  )
}

export default Main

```


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

[User] Show me the implementation of admin-ab-tester/react/graphql/getTests.gql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getTests{
  getTests{
    data {
      ABTestBeginning
      WorkspaceA
      WorkspaceB
      Winner
      ConversionA
      ConversionALast24Hours
      ConversionB
      ConversionBLast24Hours
      WorkspaceASessions
      WorkspaceBSessions
      WorkspaceASessionsLast24Hours
      WorkspaceBSessionsLast24Hours
      hours
      proportion
      type
      Finish
    }
    status
    error
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/react/graphql/createTest.gql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation createTest($workspace: String!, $proportion: Int!, $hours: Int!, $type: String){
  initialize(workspace:$workspace, proportion:$proportion, hours: $hours, type: $type){
    status, data
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/react/graphql/saveData.gql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation saveData($key: String!, $value: String!){
    saveData(key: $key, value: $value)
}
```


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

[User] Show me the implementation of admin-ab-tester/react/graphql/finishTest.gql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation finishTest($workspace: String!){
  finishTest(workspace:$workspace){
    status, data
  }
}

```


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

[User] Show me the implementation of admin-ab-tester/react/graphql/getData.gql from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getData($key: String!){
    getData(key: $key)
}
```


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

[User] Show me the implementation of admin-ab-tester/react/components/Table/Table.tsx from the admin-ab-tester VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import { FormattedMessage, useIntl } from 'react-intl'
import {
  Table,
  Alert,
  Modal,
  Input,
  Dropdown,
  Button,
} from 'vtex.styleguide'

import { useABTestContext } from '../../context'

import { checkWorkspaceName, getPropertiesForSchema } from "./../../utils"

const ABTestTable = () => {
  const { tests, handleNewModal, modalOpen, createNewTest, error, setError, success, clearGeneralState, loading, emptyMessage } = useABTestContext()

  const [newTest, setNewTest] = useState<NewTest>({
    name: "",
    proportion: 0,
    hours: 0,
    type: ""
  })

  const isValid = () => {
    if (checkWorkspaceName(newTest.name) && newTest.proportion && newTest.hours && newTest.type) {
      return true
    }
  }

  const intl = useIntl()

  const defaultSchema = {
    properties: getPropertiesForSchema(tests)
  }

  const selectOptions = [
    { value: 'revenue', label: 'Revenue' },
    { value: 'conversion', label: 'Conversion' },
  ]

  function handleInput(key: string, value: string) {
    if (key === "name") {
      !checkWorkspaceName(value) ? setError(intl.formatMessage({ id: 'admin/admin.app.abtest.form.label.invalidWorkspaceName' })) : setError("")
    }
    setNewTest((prevState: any) => ({ ...prevState, [key]: value }))
  }

  var proportionTableIndex = 3;

  if(tests && tests.length > 0) {
    var firstWorkspaceProportion;
    var amountOfABTests = Object.entries(tests[proportionTableIndex]).length - 2
    var [keys] = Object.entries(tests[proportionTableIndex])

    for (const [key, value] of Object.entries(tests[proportionTableIndex])) {
      if(key == 'master' || key == 'Value'){} else {
        if (!firstWorkspaceProportion) {
          firstWorkspaceProportion = tests[proportionTableIndex][key].value
        }
        tests[proportionTableIndex][key] = { type: 'proportion', value: (firstWorkspaceProportion / amountOfABTests).toFixed(2) }
      }
    }
    tests[proportionTableIndex].master = { type: 'proportion', value: (100 - firstWorkspaceProportion).toFixed(2) }
  }

  return (
    <>
      <div className='mv4'>
        {success &&
          <Alert type={'success'} onClose={() => clearGeneralState()}>
            {success}
          </Alert>
        }
        {error &&
          <Alert type={'error'} onClose={() => clearGeneralState()}>
            {error}
          </Alert>
        }
      </div>
      <Table
        fullWidth
        schema={defaultSchema}
        items={tests}
        loading={loading}
        emptyStateLabel={emptyMessage}
        toolbar={{
          newLine: {
            label: intl.formatMessage({
              id: 'admin/admin.app.abtest.form.label.createTestAB',
            }),
            handleCallback: () => handleNewModal(true, "CREATE"),
          },
        }}
      />
      <Modal centered isOpen={modalOpen.isOpen && modalOpen.type === "CREATE"} onClose={() => handleNewModal(false, "CREATE")}>
        <div className="dark-gray">
          <p className="f3 fw3"><FormattedMessage id="admin/admin.app.abtest.form.label.createTestAB" /></p>
          <div
            style={{
              display: 'flex',
            }}
          >
            <div
              className={'pr4 pb4'}
              style={{
                flex: '1 0 45%',
              }}
            >
              <Input
                dataAttributes={{
                  'hj-white-list': true,
                  test: 'workspace-input',
                }}
                errorMessage={error}
                label={intl.formatMessage({
                  id: 'admin/admin.app.abtest.table.label.workspaceName',
                })}
                type="text"
                onChange={(ev: EventInterface): void => {
                  handleInput("name", ev.target.value)
                }}
              />
            </div>
            <div
              className={'pr4 pb4'}
              style={{
                flex: '1 0 45%',
              }}
            >
              <Input
                dataAttributes={{
                  'hj-white-list': true,
                  test: 'workspace-input',
                }}
                label={intl.formatMessage({
                  id: 'admin/admin.app.abtest.form.label.proportion',
                })}
                type="number" min="0" max="100"
                onChange={(ev: EventInterface): void => {
                  handleInput("proportion", ((100 - parseInt(ev.target.value)) * 100).toString())
                }}
              />
            </div>
          </div>
          <div
            style={{
              display: 'flex',
            }}
          >
            <div
              className={'pr4 pb4'}
              style={{
                flex: '1 0 45%',
              }}
            >
              <Input
                dataAttributes={{
                  'hj-white-list': true,
                  test: 'workspace-input',
                }}
                label={intl.formatMessage({
                  id: 'admin/admin.app.abtest.form.label.hours',
                })}
                type="number"
                onChange={(ev: EventInterface): void => {
                  handleInput("hours", ev.target.value)
                }}
              />
            </div>
            <div
              className={'pr4 pb4'}
              style={{
                flex: '1 0 45%',
              }}
            >
              <Dropdown
                label={intl.formatMessage({
                  id: 'admin/admin.app.abtest.form.label.type',
                })}
                options={selectOptions}
                value={newTest.type}
                onChange={(ev: EventInterface): void => {
                  handleInput("type", ev.target.value)
                }}
              />
            </div>
          </div>
          <div className={'mv4'}>
            <Button disabled={!isValid()} variation="primary" onClick={() => createNewTest(newTest)}>
              <FormattedMessage id="admin/admin.app.abtest.form.saveButton" />
            </Button>
          </div>
        </div>
      </Modal>
    </>
  )
}

export default ABTestTable

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/critical/index.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import critical from 'critical'
import { resolve } from 'path'

const dest = resolve(__dirname, '../build/static/css/critical.css')
const src = 'https://storetheme.vtex.com'

critical.generate({
  // Inline the generated critical-path CSS
  // - true generates HTML
  // - false generates CSS
  inline: false,

  // Your base directory
  // base: 'build/',

  // HTML source
  // html: '<html>...</html>',

  // HTML source file
  src,

  // Your CSS Files (optional)
  // css: ['../build/static/css/critical.css'],

  // Viewport width
  width: 1300,

  // Viewport height
  height: 900,

  // Target for final HTML output.
  // use some CSS file when the inline option is not set
  dest,

  // Minify critical-path CSS when inlining
  minify: true,

  // Extract inlined styles from referenced stylesheets
  // extract: true,

  // Complete Timeout for Operation
  timeout: 30000,

  // Prefix for asset directory
  // pathPrefix: '/MySubfolderDocrot',

  // ignore CSS rules
  // ignore: ['font-face',/some-regexp/],

  // overwrite default options
  // ignoreOptions: {}

  penthouse: {
    renderWaitTime: 5000,
    blockJSRequests: false,
  }
})
```


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

[User] Show me the implementation of store-on-localhost/server/typings.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  Request as ExpressRequest,
  Response as ExpressResponse,
} from 'express'

export interface Response extends ExpressResponse {
  startTime: (name: string, desc: string) => void
  endTime: (name: string) => void
}

export interface Request extends ExpressRequest {}
```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/server/index.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import compression from 'compression'
import path from 'path'
import serverTiming from 'server-timing'
import express from 'express'
import bodyParser from 'body-parser'
import morgan from 'morgan'

import { proxy } from './middlewares/proxy'
import { render } from './middlewares/renderer'

// we'll talk about this in a minute:
const PORT = 8001

// initialize the application and create the routes
const app = express()
const router = express.Router()

app.use(morgan('dev'))
app.use(bodyParser.json())

// root (/) should always serve our server rendered page
router.use('^/$', render)

router.use('/_v/:scope/graphql/v1', proxy)

// other static resources should just be served as they are
router.use(
  express.static(
    path.resolve(__dirname, '../build'),
    { maxAge: '30d' },
  )
)

// tell the app to use the above rules
app.use(compression())
app.use(serverTiming({
  total: true,
  enabled: true,
  autoEnd: true,
}))
app.use(router)

// start the app
app.listen(PORT, (error) => {
  if (error) {
    console.error(error)
    process.exit(1)
  }
  console.log(`Server is listening on http://localhost:${PORT} 🦄`)
})
```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/index.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import './index.css'

import React from 'react'
import ReactDOM from 'react-dom'

import { App, createOrHydrateApolloClient } from './App'

const client = createOrHydrateApolloClient()

const rootElement = document.getElementById('root')

if ((window as any).__APOLLO_CACHE__) {
  console.log('hydating react ...')
  ReactDOM.hydrate(<App client={client}/>, rootElement)
} else {
  ReactDOM.render(<App client={client}/>, rootElement)
}

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/App.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import './App.css'

import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { createHttpLink } from 'apollo-link-http'
import { canUseDOM } from 'exenv'
import React from 'react'
import { ApolloProvider } from 'react-apollo'
import { IntlProvider } from 'react-intl'

import HomeWrapper from './monobloco/HomeWrapper'
import StoreWrapper from './monobloco/StoreWrapper'
import staticRuntime from './runtime.json'
import { RenderContextProvider } from './vtex.render-runtime'

const runtime = {
  ...staticRuntime,
  getSettings: () => {},
  prefetchDefaultPages: () => {},
  addNavigationRouteModifier: () => {},
}

interface Props {
  client: ApolloClient<NormalizedCacheObject>
}

export const createOrHydrateApolloClient = () => {
  const httpLink = createHttpLink({
    fetch: window.fetch,
    credentials: 'include',
    useGETForQueries: false,
    uri: 'http://localhost:8001/_v/private/graphql/v1',
    includeExtensions: true
  })

  const inMemory = new InMemoryCache({
    addTypename: true,
  })

  if (canUseDOM && (window as any).__APOLLO_CACHE__) {
    console.log('Restoring apollo cache...')
    inMemory.restore((window as any).__APOLLO_CACHE__)
  }

  const client = new ApolloClient({
    link: ApolloLink.from([httpLink]),
    cache: inMemory,
    ssrMode: !canUseDOM,
    resolvers: {}
  })

  return client
}

export const App = ({ client }: Props) => (
  <ApolloProvider client={client}>
    <IntlProvider messages={runtime.messages} locale="en">
      <RenderContextProvider runtime={runtime}>
        <StoreWrapper>
          <HomeWrapper />
        </StoreWrapper>
      </RenderContextProvider>
    </IntlProvider>
  </ApolloProvider>
)

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/App.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/index.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/contextLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'

export const contextLink = new ApolloLink((operation: Operation, forward?: NextLink) => {
  return forward ? forward(operation) : null
})
```


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

[User] Show me the implementation of store-on-localhost/src/global.d.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare global {
}

interface Window extends Window, GlobalThis {
  pixelManagerEvents: any[]
  Element: any
  browserHistory: any
  __RUNTIME__: any
  __RENDER_8_SESSION__: any
  hrtime: any
  rendered: any
  __RENDER_8_COMPONENTS__: any
  __STATE__: any
  __hasPortals__: any
  self: any
  top: any
  __provideRuntime: any
  __RENDER_8_HOT__: any
  flags: any
  __hostname__: any
  ReactApollo: any
  ReactIntl: any
  ReactIntlLocaleData: any
}
```


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

[User] Show me the implementation of store-on-localhost/server/middlewares/renderer.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { Request, Response } from '../typings'
import { readFile } from 'fs-extra'
import fetch from 'node-fetch'
import path from 'path'
import React from 'react'
import { renderToStringWithData } from '@apollo/react-ssr'

import { App, createOrHydrateApolloClient } from '../../src/App'

global.window = global
global.fetch = fetch

const filePath = path.resolve(__dirname, '../../build/index.html')

const renderServerSide = async (res: Response, htmlTemplate: string) => {
  const client = createOrHydrateApolloClient()

  res.startTime('renderToStringWithData', 'RenderToStringWithData')
  const renderedHTML = await renderToStringWithData(<App client={client}/>)
  res.endTime('renderToStringWithData')

  res.startTime('extractApolloClient', 'Apollo Client Extraction')
  const extracted = client.extract()
  res.endTime('extractApolloClient')

  return htmlTemplate
    .replace('<div id="root"></div>', `<div id="root">${renderedHTML}</div>`)
    .replace('<script id="apolloCache"></script>', `<script id="apolloCache">window.__APOLLO_CACHE__=${JSON.stringify(extracted)}</script>`)
}

const renderClientSide = (htmlTemplate: string) => htmlTemplate

export const render = async (req: Request, res: Response) => {
  try {
    const { __disableSSR: disableSSR } = req.query

    res.startTime('htmlTemplate', 'Read HTML Template')
    const htmlTemplate = await readFile(filePath, { encoding: 'utf8' })
    res.endTime('htmlTemplate')

    let html: string = ''
    if (disableSSR != null) {
      res.startTime('renderClientSide', 'Client Side Rending')
      html = renderClientSide(htmlTemplate)
      res.endTime('renderClientSide')
    } else {
      res.startTime('serverSideRendering', 'Render Server Side')
      html = await renderServerSide(res, htmlTemplate)
      res.endTime('serverSideRendering')
    }

    res.send(html)
  } catch (err) {
    if (err) {
        console.error('err', err);
        return res.status(404).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 store-on-localhost/server/middlewares/proxy.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import axios, { AxiosRequestConfig } from 'axios'
import { join } from 'path'
import LRU from 'lru-cache'
import crypto from 'crypto'

import { Request, Response } from '../typings'

interface Cached {
  data: any
  headers: Record<string, string>
  status: number
}

const HOST = 'storetheme.vtex.com'
const PROTOCOL = 'https'
const CACHE = new LRU<string, Cached>({
  max: 1e3
})

const http = axios.create({
  baseURL: `${PROTOCOL}://${HOST}`,
  timeout: 5e3,
})

const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

const awaitForOperationName = async (operationName: string) => {

  let amount = 0
  if (operationName === 'pwaData') {
    amount = 0
  } else if (operationName === 'orderForm') {
    amount = 0
  } else if (operationName === 'orderFormCheckout') {
    amount = 0
  }

  console.log(`[${operationName}]: Awaiting ${amount}ms`)
  await delay(amount)
}

const toMD5 = (input: string) => crypto.createHash('md5').update(input).digest('hex')

const optionsToCacheKey = (config: AxiosRequestConfig): string => [
  `url:${config.url}`,
  `data:${toMD5(JSON.stringify(config.data))}`,
  `headers:${toMD5(JSON.stringify(config.headers))}`
].join('--')

export const proxy = async (req: Request, res: Response) => {
  try {
    const body = req.body
    const operationName = body?.operationName

    await awaitForOperationName(operationName)

    const options: AxiosRequestConfig = {
      method: 'POST',
      url: join(req.baseUrl, req.url),
      headers: {
        ...req.headers,
        host: HOST,
      },
      data: body,
      validateStatus: () => true
    }

    const key = optionsToCacheKey(options)
    const isCached = CACHE.has(key)

    if (!isCached) {
      console.log('[MISS]', options.data?.operationName)
      const { headers, status, data } = await http.request(options)

      if (!isCached && status === 200) {
        CACHE.set(key, {
          headers,
          status,
          data,
        })
      }
    } else {
      console.log('[HIT]', options.data?.operationName)
    }

    const { headers, status, data } = CACHE.get(key)

    Object.keys(headers).forEach(header => {
      res.set(header, headers[header])
    })

    res.status(status)
    res.send(data)

  } catch (err) {
    console.error(err)
    res.status(500)
    res.send(err)
  }
}
```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/monobloco/StoreWrapper.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment, useEffect } from 'react'
import Helmet from 'react-helmet'
import PropTypes from 'prop-types'

import PixelContext from './components/new/PixelContext/PixelContext'
import ToastProvider from './components/new/Styleguide/ToastProvider'
import PWAContext from './components/new/StoreResources/PWAContext'
import OrderQueue from './components/new/OrderManager/OrderQueue'
import OrderItems from './components/new/OrderItems/OrderItems'
import OrderManagerForm from './components/new/OrderManager/OrderForm'
import UserDataPixel from './components/UserDataPixel'
import PageViewPixel from './components/PageViewPixel'
import OrderFormProvider from './components/OrderFormProvider'
import NetworkStatusToast from './components/NetworkStatusToast'
import WrapperContainer from './components/WrapperContainer'

import { normalizeNavigation } from './utils/navigation'
import { useRuntime } from '../vtex.render-runtime'
// import { canUseDOM } from 'exenv'

const { OrderQueueProvider } = OrderQueue
const { PixelProvider } = PixelContext
const { PWAProvider } = PWAContext
const { OrderFormProvider: OrderFormProviderCheckout } = OrderManagerForm
const { OrderItemsProvider } = OrderItems

const APP_LOCATOR = 'vtex.store'
const CONTENT_TYPE = 'text/html; charset=utf-8'
const META_ROBOTS = 'index, follow'
const MOBILE_SCALING = 'width=device-width, initial-scale=1'

const systemToCanonical = ({ canonicalPath }) => {
  const canonicalHost =
    window.__hostname__ || (window.location && window.location.hostname)
  return {
    canonicalPath,
    canonicalHost,
  }
}

const StoreWrapper = ({ children }) => {
  const {
    amp,
    culture: { country, locale, currency },
    route,
    route: { metaTags, title: pageTitle },
    getSettings,
    rootPath = '',
    prefetchDefaultPages,
    addNavigationRouteModifier,
  } = useRuntime()
  // const isStorefrontIframe =
  //   canUseDOM && window.top !== window.self && window.top.__provideRuntime

  // const supportsServiceWorker = canUseDOM && 'serviceWorker' in navigator

  useEffect(() => {
    prefetchDefaultPages([
      'store.custom',
      'store.product',
      'store.search',
      'store.search#brand',
      'store.search#category',
      'store.search#configurable',
      'store.search#custom',
      'store.search#department',
      'store.search#subcategory',
      'store.search#subcategory-terms',
    ])
  }, [prefetchDefaultPages])

  useEffect(() => {
    addNavigationRouteModifier(normalizeNavigation)
  }, [addNavigationRouteModifier])

  const settings = getSettings(APP_LOCATOR) || {}
  const {
    titleTag,
    metaTagDescription,
    metaTagRobots,
    storeName,
    faviconLinks,
  } = settings

  const { canonicalHost, canonicalPath } = systemToCanonical(route)
  const description = (metaTags && metaTags.description) || metaTagDescription
  const title = pageTitle || titleTag

  // const [queryMatch] = route.path.match(/\?.*/) || ['?']

  const canonicalLink =
    canonicalHost &&
    canonicalPath &&
    `https://${canonicalHost}${rootPath}${canonicalPath}`

  return (
    <Fragment>
      <Helmet
        title={title}
        meta={[
          // viewport meta tag is already handled in render-server for AMP pages
          !amp && { name: 'viewport', content: MOBILE_SCALING },
          { name: 'description', content: description },
          { name: 'copyright', content: storeName },
          { name: 'author', content: storeName },
          { name: 'country', content: country },
          { name: 'language', content: locale },
          { name: 'currency', content: currency },
          { name: 'robots', content: metaTagRobots || META_ROBOTS },
          { httpEquiv: 'Content-Type', content: CONTENT_TYPE },
        ]
          .filter(Boolean)
          .filter(meta => meta.content && meta.content.length > 0)}
        // script={[
        //   supportsServiceWorker && {
        //     type: 'text/javascript',
        //     src: `${rootPath}/pwa/workers/register.js${queryMatch}&scope=${encodeURIComponent(
        //       rootPath
        //     )}`,
        //     defer: true,
        //   },
        // ].filter(Boolean)}
        link={[
          ...(faviconLinks || []),
          ...(!amp && canonicalLink
            ? [
                {
                  rel: 'canonical',
                  href: encodeURI(canonicalLink),
                },
              ]
            : []),
        ].filter(Boolean)}
      />
      <PixelProvider currency={currency}>
        <PWAProvider rootPath={rootPath}>
          <PageViewPixel title={title} />
          <UserDataPixel />
          <ToastProvider positioning="window">
            <NetworkStatusToast />
            <OrderFormProvider>
              <OrderQueueProvider>
                <OrderFormProviderCheckout>
                  <OrderItemsProvider>
                    <WrapperContainer className="vtex-store__template bg-base">
                      {children}
                    </WrapperContainer>
                  </OrderItemsProvider>
                </OrderFormProviderCheckout>
              </OrderQueueProvider>
            </OrderFormProvider>
          </ToastProvider>
        </PWAProvider>
      </PixelProvider>
    </Fragment>
  )
}

StoreWrapper.propTypes = {
  children: PropTypes.element,
}

export default StoreWrapper

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/monobloco/HomeWrapper.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { useMemo, Fragment } from 'react'
import PropTypes from 'prop-types'
import { useRuntime } from '../vtex.render-runtime'
import { canUseDOM } from 'exenv'
// import SearchAction from 'vtex.structured-data/SearchAction'
import useDataPixel from './hooks/useDataPixel'
import Header from './components/new/header'
import Carousel from './components/new/Carousel/Carousel'
import Row from './components/new/FlexLayout/Row'
import Col from './components/new/FlexLayout/Col'
import StoreImage from './components/new/StoreImage/Image'
import RichText from './components/new/RichText'
import Shelf from './components/new/Shelf/Shelf'
import InfoCard from './components/new/StoreComponents/InfoCard'
import Newsletter from './components/new/StoreComponents/Newsletter'
import Footer from './components/new/Footer/Footer'

const Deals = () => {
  return (
    <div>
      <Row blockClass="deals">
        <Col>
          <StoreImage src="https://storecomponents.vteximg.com.br/arquivos/box.png" maxHeight="24px" />
          <RichText text="Free shipping" blockClass="deals" />
        </Col>
        <Col>
          <StoreImage src="https://storecomponents.vteximg.com.br/arquivos/delivery-fast.png" maxHeight="24px" />
          <RichText text="One day delivery" blockClass="deals" />
        </Col>
        <Col>
          <StoreImage src="https://storecomponents.vteximg.com.br/arquivos/store.png" maxHeight="24px" />
          <RichText text="Pick up in store" blockClass="deals" />
        </Col>
        <Col>
          <StoreImage src="https://storecomponents.vteximg.com.br/arquivos/coupon.png" maxHeight="24px" />
          <RichText text="Exclusive deals" blockClass="deals" />
        </Col>
      </Row>
    </div>
  )
}

const FixedHome = () => {
  return <div>
    <Header />
    <Carousel autoplay={false} banners={
      [{
        "image": "https://storecomponents.vteximg.com.br/arquivos/banner-principal.png",
        "mobileImage": "https://storecomponents.vteximg.com.br/arquivos/banner-principal-mobile.jpg"
      },
      {
        "image": "https://storecomponents.vteximg.com.br/arquivos/banner.jpg",
        "mobileImage": "https://storecomponents.vteximg.com.br/arquivos/banner-principal-mobile.jpg"
      }]
    }
      height={720}
      showArrows
      showDots
    />
    <Deals />
    <Shelf orderBy="OrderByTopSaleDESC" paginationDotsVisibility="desktopOnly" skusFilter="FIRST_AVAILABLE" productList={{
      "maxItems": 10,
      "itemsPerPage": 5,
      "minItemsPerPage": 1,
      "scroll": "BY_PAGE",
      "arrows": true,
      "titleText": "Top sellers"
    }} />
    <InfoCard id="info-card-home" isFullModeStyle={false} textPosition="left" imageUrl="https://storecomponents.vteximg.com.br/arquivos/banner-infocard2.png" headline="Clearance Sale" callToActionText="DISCOVER" callToActionUrl="/sale/d/" blockClass="info-card-home" textAlignment="center" />
    <RichText text="**This is an example store built using the VTEX platform.\nWant to know more?**" blockClass="question" />
    <RichText text="\n**Reach us at**\nwww.vtex.com.br" blockClass="link" />
    <Newsletter />
    <Footer />
  </div>
}

const HomeWrapper = ({ children }) => {
  const { account, route } = useRuntime()

  const pixelEvents = useMemo(() => {
    if (!canUseDOM) {
      return null
    }

    return [
      {
        event: 'pageInfo',
        eventType: 'homeView',
        accountName: account,
        pageTitle: document.title,
        pageUrl: window.location.href,
        pageCategory: 'Home',
      },
    ]
  }, [account])

  useDataPixel(pixelEvents, route.routeId)

  return (
    <Fragment>
      <FixedHome />
    </Fragment>
  )
}

HomeWrapper.propTypes = {
  children: PropTypes.element,
}

export default HomeWrapper

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/vtex.render-runtime/index.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import 'apollo-cache-inmemory'
import 'apollo-client'
import 'apollo-link-http'
import 'apollo-link-persisted-queries'
import 'apollo-upload-client'
import 'apollo-utilities'
import 'classnames'
import * as EventEmitter from 'eventemitter3'
import { canUseDOM } from 'exenv'
import 'graphql'
import { createBrowserHistory as createHistory } from 'history'
import queryString from 'query-string'
import React, { ReactElement } from 'react'
import { getDataFromTree } from 'react-apollo'
import { hydrate, render as renderDOM } from 'react-dom'
import { Helmet } from 'react-helmet'
import NoSSR, { useSSR } from './components/NoSSR'
import { isEmpty } from 'ramda'
import Loading from './components/Loading'
import { LoadingContextProvider } from './components/LoadingContext'

import { ChildBlock, useChildBlock } from './components/ChildBlock'
import ExtensionContainer from './components/ExtensionContainer'
import ExtensionPoint from './components/ExtensionPoint'
import LayoutContainer from './components/LayoutContainer'
import LegacyExtensionContainer from './components/LegacyExtensionContainer'
import Link from './components/Link'
import {
  RenderContext,
  useRuntime,
  withRuntimeContext,
  RenderContextProvider,
} from './components/RenderContext'
import RenderProvider from './components/RenderProvider'
import { getVTEXImgHost } from './utils/assets'
import PageCacheControl from './utils/cacheControl'
import { getState } from './utils/client'
import { buildCacheLocator } from './utils/client'
import { ensureContainer, getContainer, getMarkups } from './utils/dom'
import { registerEmitter } from './utils/events'
import { getBaseURI } from './utils/host'
import registerComponent from './utils/registerComponent'
import { withSession } from './utils/session'
import { TreePathContext, useTreePath } from './utils/treePath'
import {
  isStyleWritable,
  optimizeSrcForVtexImg,
  optimizeStyleForVtexImg,
} from './utils/vteximg'
import withHMR from './utils/withHMR'
import { generateExtensions } from './utils/blocks'

let emitter: EventEmitter | null = null

const renderExtension = (
  extensionName: string,
  destination: HTMLElement,
  props = {}
) => {
  if (emitter) {
    emitter.emit('renderExtensionLoader.addOrUpdateExtension', {
      destination,
      extensionName,
      props,
    })
  } else {
    throw new Error(`ExtensionPortal can't be rendered before RenderProvider`)
  }
}

function renderToStringWithData(
  component: ReactElement<any>,
  renderFn: (root: ReactElement) => string,
  skipQuery = false
): Promise<any> {
  const getDataFn = (): Promise<string | void> => {
    if (skipQuery) return Promise.resolve()
    return getDataFromTree(component)
  }

  const startGetDataFromTree = window.hrtime()
  return getDataFn().then(() => {
    const endGetDataFromTree = window.hrtime(startGetDataFromTree)

    const startRenderToString = window.hrtime()
    const markup = renderFn(component)
    const endRenderToString = window.hrtime(startRenderToString)
    return {
      markup,
      renderTimeMetric: {
        getDataFromTree: endGetDataFromTree,
        renderToString: endRenderToString,
      },
    }
  })
}

// Either renders the root component to a DOM element or returns a {name, markup} promise.
const render = async (
  name: string,
  runtime: any,
  element?: HTMLElement
): Promise<any> => {
  const {
    customRouting,
    disableSSR,
    disableSSQ,
    page,
    pages,
    extensions,
  } = runtime

  const cacheControl = canUseDOM ? undefined : new PageCacheControl()
  const baseURI = getBaseURI(runtime)
  registerEmitter(runtime, baseURI)
  emitter = runtime.emitter

  const isPage =
    !!pages[name] && !!pages[name].path && !!extensions[name].component
  const created = !element && ensureContainer(page)
  const elem = element || getContainer()
  const history = canUseDOM && isPage && !customRouting ? createHistory() : null

  const root = (
    <RenderProvider
      history={history}
      cacheControl={cacheControl}
      baseURI={baseURI}
      root={name}
      runtime={runtime}
    >
      {!isPage ? <ExtensionPoint id={name} /> : null}
    </RenderProvider>
  )

  if (canUseDOM) {
    const renderFn = disableSSR || created ? renderDOM : hydrate

    return (renderFn(root, elem) as unknown) as Element
  }

  // eslint-disable-next-line @typescript-eslint/no-var-requires
  // const { renderToStaticMarkup, renderToString } = require('react-dom/server')
  const { renderToString } = require('react-dom/server')

  const commonRenderResult = {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    maxAge: cacheControl!.maxAge,
    page,
  }

  // if (runtime.amp) {
  //   return import(
  //     /* webpackMode: "weak" */
  //     '../AMP'
  //   ).then(({ setupAMP }) => {
  //     const { ampRoot, getExtraRenderedData } = setupAMP(
  //       root,
  //       renderToStaticMarkup,
  //       runtime
  //     )
  //     return renderToStringWithData(
  //       ampRoot,
  //       renderToStaticMarkup,
  //       disableSSQ
  //     ).then(({ markup, renderTimeMetric }) => ({
  //       ...commonRenderResult,
  //       markups: getMarkups(name, markup),
  //       renderTimeMetric,
  //       ...getExtraRenderedData(),
  //     }))
  //   })
  // }

  return renderToStringWithData(root, renderToString, disableSSQ).then(
    ({ markup, renderTimeMetric }) => ({
      ...commonRenderResult,
      markups: getMarkups(name, markup),
      renderTimeMetric,
    })
  )
}

function validateRootComponent(rootName: string, extensions: any) {
  if (!extensions[rootName]) {
    throw new Error(`Missing extension point for page ${rootName}`)
  }

  if (!extensions[rootName].component) {
    throw new Error(`Missing component for extension point ${rootName}`)
  }
}

function setLazyCookie(setCookie: string) {
  if (setCookie) {
    document.cookie = setCookie
  }
}

function start() {
  try {
    if (
      window.__RUNTIME__.blocksTree &&
      !isEmpty(window.__RUNTIME__.blocksTree)
    ) {
      window.__RUNTIME__.hasNewExtensions = true
      window.__RUNTIME__.extensions = generateExtensions(
        window.__RUNTIME__.blocksTree,
        // eslint-disable-next-line
        window.__RUNTIME__.blocks!,
        // eslint-disable-next-line
        window.__RUNTIME__.contentMap!,
        window.__RUNTIME__.pages[window.__RUNTIME__.page]
      )
    }

    if (canUseDOM && window.location.search) {
      const browserQuery = queryString.parse(window.location.search)
      window.__RUNTIME__.query = {
        ...browserQuery,
        ...(window.__RUNTIME__.query || {}),
      }
    }

    const runtime = window.__RUNTIME__
    const rootName = runtime.page
    validateRootComponent(rootName, runtime.extensions)

    const ReactCreateElement = React.createElement
    const vtexImgHost = getVTEXImgHost(runtime.account)
    React.createElement = function patchedCreateElement(type: any, props: any) {
      if (type === 'a' && props) {
        if (props.target && !props.href) {
          props.target = undefined
        }
        // Follow Google's security recommendations concerning target blank
        // https://developers.google.com/web/tools/lighthouse/audits/noopener
        const rel = props.rel ? props.rel.split(' ') : []
        if (
          props.target === '_blank' &&
          !(rel.indexOf('noopener') !== -1 || rel.indexOf('noreferrer') !== -1)
        ) {
          props.rel = rel.concat('noopener').join(' ')
        }
      }

      if (type === 'img') {
        props.src = optimizeSrcForVtexImg(vtexImgHost, props.src)
        if (
          typeof props.src === 'string' &&
          props.src.startsWith(vtexImgHost)
        ) {
          props.crossOrigin = props.crossOrigin || 'anonymous'
        }
      }

      if (props && props.style && isStyleWritable(props)) {
        props.style = optimizeStyleForVtexImg(vtexImgHost, props.style)
      }
      // This rule was introduced in a eslint-config update.
      // Should be fixed in a future PR
      //eslint-disable-next-line prefer-rest-params
      return ReactCreateElement.apply(React, arguments)
    }

    const maybeRenderPromise = render(rootName, runtime)
    if (!canUseDOM) {
      // Expose render promise to global context.
      window.rendered = (maybeRenderPromise as Promise<
        AsyncGeneratorFunction
      >).then(({ markups, maxAge, page, renderTimeMetric, ...rendered }: any) => ({
        extensions: markups.reduce(
          (acc, { name, markup }) => {(acc[name] = markup); return acc},
          {}
        ),
        head: Helmet.rewind(),
        maxAge,
        renderMetrics: { [page]: renderTimeMetric },
        state: getState(runtime),
        ...rendered,
      }))
    } else {
      setLazyCookie(runtime.workspaceCookie)
      console.log(
        'Welcome to Render! Want to look under the hood? https://careers.vtex.com'
      )
    }
  } catch (error) {
    console.error('Unexpected error rendering:', error)
    if (!canUseDOM) {
      window.rendered = { error }
    }
  }
}

const RenderContextConsumer = RenderContext.Consumer
const TreePathContextConsumer = TreePathContext.Consumer

export {
  ExtensionContainer,
  /** Block is the preferred nomenclature now, ExtensionPoint is kept for
   * backwards compatibility
   */
  ExtensionPoint as Block,
  ExtensionPoint,
  LayoutContainer,
  LegacyExtensionContainer,
  Helmet,
  Link,
  NoSSR,
  useSSR,
  RenderContextConsumer,
  RenderContextProvider,
  TreePathContextConsumer,
  canUseDOM,
  render,
  start,
  withHMR,
  RenderProvider,
  registerComponent,
  withRuntimeContext,
  ChildBlock,
  useChildBlock,
  useRuntime,
  useTreePath,
  withSession,
  Loading,
  LoadingContextProvider,
  buildCacheLocator,
  renderExtension,
  // These unstable APIs should be deprecated shortly
  ChildBlock as Unstable__ChildBlock,
  useChildBlock as useChildBlock__unstable,
}

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/monobloco/utils/navigation.js from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { contains, path as ramdaPath, zip, flatten } from 'ramda'
import queryString from 'query-string'

const SPEC_FILTER = 'specificationFilter'
const MAP_CATEGORY_CHAR = 'c'
const MAP_VALUES_SEP = ','
const PATH_SEPARATOR = '/'

const isLegacySearchFormat = (pathSegments, map) => {
  if (!map) {
    return false
  }
  return (
    map.includes(SPEC_FILTER) ||
    map.split(MAP_VALUES_SEP).length === pathSegments.length
  )
}

const categoriesInSequence = mapValues => {
  let count = 0
  for (const value of mapValues) {
    if (value !== MAP_CATEGORY_CHAR) {
      return count
    }
    count++
  }
  return count
}

const queryMapComparator = (tuple1, tuple2) => {
  const [, specFilterVal1] = tuple1 && tuple1[0].split(`${SPEC_FILTER}_`)
  const [, specFilterVal2] = tuple2 && tuple2[0].split(`${SPEC_FILTER}_`)
  const facetName1 = tuple1[1]
  const facetName2 = tuple2[1]

  const considerSpecificationFilter =
    specFilterVal1 &&
    specFilterVal2 &&
    !isNaN(Number(specFilterVal1)) &&
    !isNaN(Number(specFilterVal2))

  return considerSpecificationFilter
    ? Number(specFilterVal1) -
        Number(specFilterVal2) +
        facetName1.localeCompare(facetName2)
    : facetName1.localeCompare(facetName2)
}

const normalizeQueryMap = (pathSegments, mapSegments) => {
  const categoryTreeDepth = categoriesInSequence(mapSegments)
  const zippedMapQuery = zip(mapSegments, pathSegments)

  const sorted =
    zippedMapQuery &&
    zippedMapQuery.slice(categoryTreeDepth).sort(queryMapComparator)

  const assembledSortedQuery = zippedMapQuery
    .slice(0, categoryTreeDepth)
    .concat(sorted)

  const sortedMap = assembledSortedQuery
    .map(value => (Array.isArray(value) ? value[0] : value))
    .join(',')
  const sortedPathSegments = assembledSortedQuery.map(tuple => tuple[1])

  return {
    map: sortedMap,
    pathSegments: sortedPathSegments,
  }
}

const normalizeSearchNavigation = (pathSegments, map, segmentsToIgnore) => {
  const normalizedSegments = pathSegments.map(segment =>
    segmentsToIgnore.includes(segment) ? segment : segment.toLowerCase()
  )
  return { pathSegments: normalizedSegments, map }
}

const getIgnoredSegments = ignore => {
  return ignore
    ? flatten(
        Object.values(ignore).map(routeModifier =>
          routeModifier.path.split(PATH_SEPARATOR)
        )
      )
    : []
}

const normalizeLegacySearchNavigation = (pathSegments, queryMap, query) => {
  if (queryMap.map) {
    const mapValues = queryMap.map.split(MAP_VALUES_SEP)
    let convertedSegments = zip(pathSegments, mapValues).map(
      ([pathSegment, mapValue]) =>
        contains(SPEC_FILTER, mapValue)
          ? pathSegment
          : pathSegment.toLowerCase()
    )

    const {
      pathSegments: sortedPathSegments,
      map: sortedMap,
    } = normalizeQueryMap(
      queryMap.query ? queryMap.query.split('/').slice(1) : convertedSegments,
      mapValues
    )

    queryMap.map = sortedMap
    if (queryMap.query) {
      queryMap.query = `/${sortedPathSegments.join('/')}`
    } else {
      convertedSegments = sortedPathSegments
    }

    const normalizedQuery = queryString.stringify(queryMap, {
      encode: false,
    })

    return { pathSegments: convertedSegments, query: normalizedQuery }
  }
  return { pathSegments: pathSegments, query: query }
}

export const normalizeNavigation = navigation => {
  if (ramdaPath(['__RUNTIME__', 'route', 'domain'], window) !== 'store') {
    return navigation
  }

  const { path, query, options } = navigation
  const parsedQuery = query ? queryString.parse(query) : {}
  const { map } = parsedQuery

  const pathSegments = path.startsWith(PATH_SEPARATOR)
    ? path.split(PATH_SEPARATOR).slice(1)
    : path.split(PATH_SEPARATOR)

  const segmentsToIgnore = getIgnoredSegments(options)

  const normalizedNavigation =
    parsedQuery.query || isLegacySearchFormat(pathSegments, map)
      ? normalizeLegacySearchNavigation(pathSegments, parsedQuery, query)
      : normalizeSearchNavigation(pathSegments, query, segmentsToIgnore)

  navigation.path = path.startsWith('/')
    ? '/' + normalizedNavigation.pathSegments.join('/')
    : normalizedNavigation.pathSegments.join('/')
  navigation.query = normalizedNavigation.query
  return navigation
}

```


[System] You are an expert VTEX IO developer. You specialize 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-on-localhost/src/monobloco/components/UserDataPixel.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useEffect, FC } from 'react'
import {usePixel} from './new/PixelContext/PixelContext'

const fields = ['firstName', 'lastName', 'document', 'id', 'email', 'phone', 'isAuthenticated'] as const

interface SessionResponse {
  response: {
    namespaces: {
      profile?: {
        firstName?: {
          value: string
        }
        lastName?: {
          value: string
        }
        document?: {
          value: string
        }
        id?: {
          value: string
        }
        email?: {
          value: string
        }
        phone?: {
          value: string
        }
        isAuthenticated?: {
          value: string
        }
      }
    }
  }
}

const getSessionPromiseFromWindow: any = () =>
  !(window as any).__RENDER_8_SESSION__ || !(window as any).__RENDER_8_SESSION__.sessionPromise
    ? Promise.resolve(null)
    : (window as any).__RENDER_8_SESSION__.sessionPromise

const toBoolean = (value: string) => value.toLowerCase() === 'true'

function getUserData(profileFields: SessionResponse['response']['namespaces']['profile']) {
  if (!profileFields) {
    return {}
  }

  return fields.reduce<Record<string, string | boolean>>(
    (acc, key) => {
      const value = profileFields[key]?.value

      if (value) {
        acc[key] = key === 'isAuthenticated'
          ? toBoolean(value)
          : value
      }

      return acc
    },
    {}
  )
}

const UserDataPixel: FC = () => {
  const { push } = usePixel()

  useEffect(() => {
    getSessionPromiseFromWindow().then((data: SessionResponse) => {
      const profileFields = data?.response?.namespaces?.profile

      if (!profileFields) {
        return
      }

      const userData = getUserData(profileFields)

      push({
        event: 'userData',
        ...userData,
      } as any)
    })
  }, [push])

  return null
}

export default UserDataPixel

```