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

[User] Show me the implementation of formula-graphql/node/resources/profile.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

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

import {AuthenticationError, NotVTEXUserError} from '../errors'

interface VtexIdUser {
  userId: string
  user: string
  userType: string
}

const FIVE_MIN_MS = 5 * 60 * 1000
const VTEX_ID_COOKIE = 'VtexIdclientAutCookie'
const VTEX_EMAIL_REGEX = /\@vtex\.com(\.br)?$/

const profileCache = new LRUCache<string, any>({
  max: 2000,
  maxAge: FIVE_MIN_MS,
  stale: true,
})

metrics.trackCache('profile', profileCache)

const capitalizeFirstLetter = (s: string) => {
  return s.charAt(0).toUpperCase() + s.slice(1)
}

const emailToName = (email: string) => {
  const [user] = email.split('@')
  const maybeWords = user.split('.')
  return maybeWords.map(capitalizeFirstLetter).join(' ')
}

export default class Profile {
  private http: HttpClient
  private vtexIdToken: string
  private headers: Record<string, string>
  private topbarPath: string
  private vtexIdPath: string

  public constructor(ctx: ServiceContext) {
    this.http = new HttpClient({
      metrics,
      userAgent: process.env.VTEX_APP_ID,
    })

    this.vtexIdToken = ctx.cookies.get(VTEX_ID_COOKIE)

    this.topbarPath = `http://${ctx.vtex.account}.vtexcommercestable.com.br/api/license-manager/site/pvt/newtopbar`
    this.vtexIdPath = `http://vtexid.vtex.com.br/api/vtexid/pub/authenticated/user?authToken=${this.vtexIdToken}`

    this.headers = {
      'Proxy-Authorization': ctx.vtex.authToken,
      VtexIdclientAutCookie: this.vtexIdToken,
    }
  }

  public getProfile = async () => {
    if (!this.vtexIdToken) {
      throw new AuthenticationError()
    }

    let profile

    const topbarResponse: {profile: ProfileData} = await profileCache.getOrSet(this.vtexIdToken, this.fetchProfile)

    profile = topbarResponse.profile

    if (!profile) {
      profile = await this.fetchFallbackProfile()
      profileCache.set(this.vtexIdToken, {profile})
    }

    if (!profile || !profile.email || !VTEX_EMAIL_REGEX.test(profile.email)) {
      throw new NotVTEXUserError()
    }

    return profile
  }

  private fetchProfile = () => this.http.get(this.topbarPath, {headers: this.headers})

  private fetchFallbackProfile = () =>
    this.http.get(this.vtexIdPath, {headers: {'Proxy-Authorization': this.headers['Proxy-Authorization']}})
    .then((vtexIdUser: VtexIdUser) => ({
      email: vtexIdUser.user,
      id: vtexIdUser.userId.replace(/\-/g, '').toLowerCase(),
      name: emailToName(vtexIdUser.user),
      picture: null,
    }))
    .catch((e) => {
      console.error(e)
      return 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 formula-graphql/node/resources/index.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {Logger, LRUCache, VBase} from '@vtex/api'

import Profile from './profile'
import Projects from './projects'
import Scores from './scores'
import Votes from './votes'

const vbaseCache = new LRUCache<string, any>({
  max: 200,
})

metrics.trackCache('vbase', vbaseCache)

export default class Resources {
  public logger: Logger
  public profile: Profile
  public projects: Projects
  public votes: Votes
  public scores: Scores

  private vbase: VBase

  constructor (ctx: ResolverContext) {
    this.logger = new Logger(ctx.vtex)
    this.vbase = new VBase(ctx.vtex, {cacheStorage: vbaseCache})

    this.profile = new Profile(ctx)
    this.projects = new Projects(ctx, this.vbase, this.logger)
    this.votes = new Votes(ctx, this.vbase, this.logger)
    this.scores = new Scores(ctx, this.vbase, this.logger)
  }
}

```


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

[User] Show me the implementation of formula-graphql/node/resolvers/info.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
enum FormulaStatus {
  REGISTRATION = 'REGISTRATION',
  RUNNING = 'RUNNING',
  VOTING = 'VOTING',
  RESULTS = 'RESULTS',
}

interface FormulaInfo {
  status: FormulaStatus
  timeRemainingSeconds: number
  timeTotalSeconds: number
}

const editions = {
 '2018.10': {
   startDate: new Date('2018-10-18T12:00:00.000Z'),
   timeTotalSeconds: 32 * 60 * 60,
 }
}

async function info(_: any, {edition}: any, ctx: any): Promise<FormulaInfo> {
  const {startDate, timeTotalSeconds} = editions[edition]
  const {resources: {scores: scoresResource}} = ctx

  const scores = await scoresResource.getScores(edition)

  const nowMillis = (new Date()).getTime()
  const startDateMillis = startDate.getTime()
  const finishDateMillis = startDateMillis + timeTotalSeconds * 1000

  const status = nowMillis < startDateMillis
    ? FormulaStatus.REGISTRATION
    : nowMillis < finishDateMillis
      ? FormulaStatus.RUNNING
      : scores.length === 0
        ? FormulaStatus.VOTING
        : FormulaStatus.RESULTS

  const timeRemainingMillis = status === FormulaStatus.REGISTRATION
    ? startDateMillis - nowMillis
    : status === FormulaStatus.RUNNING
      ? finishDateMillis - nowMillis
      : 0

  return {
    status,
    timeRemainingSeconds: Math.round(timeRemainingMillis / 1000),
    timeTotalSeconds,
  }
}

export const infoQueries = {
  info,
}

```


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

[User] Show me the implementation of formula-graphql/node/resolvers/projects.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {concat, difference, uniq} from 'ramda'

import {Project} from '../resources/projects'

interface ProjectArgs {
  edition: string
  id?: string
  demoURL?: string
  description?: string
  name?: string
}

interface ProjectsArgs {
  edition: string
}

async function project(_: any, {edition, id}: ProjectArgs, ctx: ResolverContext): Promise<Project> {
  return ctx.resources.projects.find(edition, id)
}

async function projects(_: any, {edition}: ProjectsArgs, ctx: ResolverContext): Promise<Project[]> {
  return ctx.resources.projects.list(edition)
}

async function updateProject(_: any, {edition, id, demoURL, description, name}: ProjectArgs, ctx: ResolverContext): Promise<Project> {
  if (!id) {
    return ctx.resources.projects.update(edition, id, {demoURL, description, name})
  }

  const saved = await ctx.resources.projects.find(edition, id)

  const updated = {
    ...saved,
    demoURL,
    description,
    edition,
    id,
    name,
  }

  await ctx.resources.projects.update(edition, id, updated)

  return updated
}

async function deleteProject(_: any, {edition, id}: ProjectArgs, ctx: ResolverContext): Promise<boolean> {
  return ctx.resources.projects.delete(edition, id)
}

async function joinProject(_: any, {edition, id}: ProjectArgs, ctx: ResolverContext): Promise<Project> {
  const saved = await ctx.resources.projects.find(edition, id)

  const updated = {
    ...saved,
    team: uniq(concat([ctx.profile], saved.team)),
  }

  return ctx.resources.projects.update(edition, id, updated)
}

async function leaveProject(_: any, {edition, id}: ProjectArgs, ctx: ResolverContext): Promise<Project> {
  const saved = await ctx.resources.projects.find(edition, id)

  const updated = {
    ...saved,
    team: difference(saved.team, [ctx.profile]),
  }

  return ctx.resources.projects.update(edition, id, updated)
}

export const projectsMutations = {
  deleteProject,
  joinProject,
  leaveProject,
  updateProject,
}

export const projectsQueries = {
  project,
  projects,
}

```


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

[User] Show me the implementation of formula-graphql/node/resolvers/scores.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {map} from 'ramda'
import {ScoreData} from '../resources/scores'

interface ScoresArgs {
  edition: string
}

async function updateScores(_: any, {edition}: ScoresArgs, ctx: ResolverContext): Promise<ScoreData[]> {
  const {scores: scoresResource} = ctx.resources
  const projectScores = await scoresResource.updateScores(edition)
  return projectScores
}

async function scores(_: any, {edition}: ScoresArgs, ctx: ResolverContext): Promise<ScoreData[]> {
  const {scores: scoresResource} = ctx.resources
  const scoreData = await scoresResource.getScores(edition)
  return scoreData
}

async function finalists(_: any, {edition}: ScoresArgs, ctx: ResolverContext): Promise<any[]> {
  const {scores: scoresResource, projects: projectsResource} = ctx.resources
  const scoreData = await scoresResource.getScores(edition)
  const initialCutPosition = Math.min(3, scoreData.length)
  let cutPosition = initialCutPosition
  while (cutPosition < scoreData.length && scoreData[cutPosition].score === scoreData[initialCutPosition-1].score) {
    cutPosition++
  }
  const finalistsData = scoreData.slice(0,cutPosition)
  const finalistsPromises = map(finalist => projectsResource.find(edition, finalist.projectID), finalistsData)
  const finalistProjects = await Promise.all(finalistsPromises)
  return finalistProjects || []
}

export const scoreQueries = {
  finalists,
  scores,
}

export const scoreMutations = {
  updateScores,
}

```


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

[User] Show me the implementation of formula-graphql/node/resolvers/votes.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {mapObjIndexed,values} from 'ramda'

export interface Vote {
  execution: number
  relevance: number
  projectID: string
  userID: string
}

interface VotesArgs {
  edition: string
}

interface UpdateVoteArgs {
  edition: string
  projectID: string
  execution: number
  relevance: number
}

async function votes(_: any, {edition}: VotesArgs, ctx: ResolverContext): Promise<Vote[]> {
  const {profile: {id}, resources: {votes: votesResource} } = ctx
  const userVotes = await votesResource.getVotes(edition)
  return values(mapObjIndexed((vote,projectID) => ({...vote,projectID,userID:id}), userVotes))
}

async function updateVote(_: any, {edition,projectID,execution,relevance}: UpdateVoteArgs, ctx: ResolverContext): Promise<Vote> {
  const {profile: {id}, resources: {votes: votesResource} } = ctx
  const vote = await votesResource.setVote(edition, projectID, {execution,relevance})
  return {...vote,projectID,userID:id}
}

export const votesMutations = {
  updateVote,
}

export const votesQueries = {
  votes,
}

```


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

[User] Show me the implementation of formula-graphql/node/resolvers/profile.ts from the formula-graphql VTEX app.

[Assistant]
Here's the implementation:

```typescript
function profile(_: any, __: any, ctx: ResolverContext): ProfileData {
  return ctx.profile
}

export const profileQueries = {
  profile,
}

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/messages/pt.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/more-details": "Mais detalhes",
  "store/none-stores": "Nenhuma loja por perto",
  "store/load-all": "Listar todas as lojas",
  "store/back-link": "Voltar para lista de lojas",
  "store/address-label": "Endereço",
  "store/information-label": "Informações",
  "store/store-closed": "Fechado",
  "store/hours-label": "Horário de funcionamento",
  "store/day-of-week-sunday": "Domingo",
  "store/day-of-week-monday": "Segunda",
  "store/day-of-week-tuesday": "Terça",
  "store/day-of-week-wednesday": "Quarta",
  "store/day-of-week-thursday": "Quinta",
  "store/day-of-week-friday": "Sexta",
  "store/day-of-week-saturday": "Sábado"
}
```


[System] You are an expert VTEX IO developer. You specialize 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-locator/messages/en.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/more-details": "More details",
  "store/none-stores": "None stores nearby",
  "store/load-all": "Load all stores",
  "store/back-link": "Back to all stores",
  "store/address-label": "Store address",
  "store/information-label": "Information",
  "store/store-closed": "Closed",
  "store/hours-label": "Store hours",
  "store/day-of-week-sunday": "Sunday",
  "store/day-of-week-monday": "Monday",
  "store/day-of-week-tuesday": "Tuesday",
  "store/day-of-week-wednesday": "Wednesday",
  "store/day-of-week-thursday": "Thursday",
  "store/day-of-week-friday": "Friday",
  "store/day-of-week-saturday": "Saturday"
}

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/messages/context.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/more-details": "store/more-details",
  "store/none-stores": "store/none-stores",
  "store/load-all": "store/load-all",
  "store/back-link": "store/back-link",
  "store/address-label": "store/address-label",
  "store/information-label": "store/information-label",
  "store/store-closed": "store/store-closed",
  "store/hours-label": "store/hours-label",
  "store/day-of-week-sunday": "store/day-of-week-sunday",
  "store/day-of-week-monday": "store/day-of-week-monday",
  "store/day-of-week-tuesday": "store/day-of-week-tuesday",
  "store/day-of-week-wednesday": "store/day-of-week-wednesday",
  "store/day-of-week-thursday": "store/day-of-week-thursday",
  "store/day-of-week-friday": "store/day-of-week-friday",
  "store/day-of-week-saturday": "store/day-of-week-saturday"
}
```


[System] You are an expert VTEX IO developer. You specialize 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-locator/messages/es.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/more-details": "Más detalles",
  "store/none-stores": "Ninguna tienda cercana",
  "store/load-all": "Cargar todas las tiendas",
  "store/back-link": "Volver a todas las tiendas",
  "store/address-label": "Dirección de la tienda",
  "store/information-label": "Información",
  "store/store-closed": "Cerrado",
  "store/hours-label": "Horario de la tienda",
  "store/day-of-week-sunday": "Domingo",
  "store/day-of-week-monday": "Lunes",
  "store/day-of-week-tuesday": "Martes",
  "store/day-of-week-wednesday": "Miércoles",
  "store/day-of-week-thursday": "Jueves",
  "store/day-of-week-friday": "Viernes",
  "store/day-of-week-saturday": "Sábado"
}
```


[System] You are an expert VTEX IO developer. You specialize 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-locator/docs/README.md from the store-locator VTEX app.

[Assistant]
Here's the implementation:

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

# Store Locator

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

---

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

The Store Locator app fetches the Pickup point data in order to display address location for retail stores.

![store-list](https://user-images.githubusercontent.com/52087100/99975140-9f809500-2d80-11eb-87ce-2f9cfcf567d6.png)
![store-detail](https://user-images.githubusercontent.com/52087100/99975130-9abbe100-2d80-11eb-95ac-49ea37490c50.png)

## Configuration

1. [Install](https://vtex.io/docs/recipes/development/installing-an-app/) the Store Locator app in your VTEX account by running `vtex install vtex.store-locator` in your terminal.
2. In your account's admin page, select **Inventory & Shipping** section and then access **Settings**.
3. Type in the Google Geolocation API key and save your changes.
4. Open your Store Theme app directory in your code editor.
5. Add the Store Locator app as a `peerDependency` in the `manifest.json` file:

```diff
 "peerDependencies": {
+  "vtex.store-locator": "0.x"
 }
```

Once installed, the app will generate a new route called `/stores` for your store, listing the retail stores registered in the **Pickup Points** section (under the **Inventory & Shipping** module).

The new page already contains a default template with all blocks exported by the Store Locator app, meaning the `/stores` page is ready to be rendered and no further actions are required. However, you can **customize the new page overwriting the template by creating a brand new one**. To do so, check the [**Advanced configuration**](./README.md#advanced-configuration) section below.

> ℹ _This app will also **add a new entry to your store's `/sitemap.xml` file so that all your pickup points are available to search engines** - make sure you already have the `vtex.store-sitemap@2.x` app installed in your VTEX account!_

### Advanced configuration

In order to define the Store Locator custom page UI, you must use the blocks exported by the `vtex.store-locator` app. Namely, they are:

|      Block name      |                                                                              Description                                                                              |
| :------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|     `store-list`     |                                              Renders a list of retail stores and a map with all their locations marked.                                               |
|    `store-group`     |                                  Provides the Pickup Point data to other blocks exported by the app, such as the ones listed below.                                   |
|     `store-name`     |                                                                        Renders the store name.                                                                        |
|  `store-back-link`   |                                                            Renders a link to return to the previous page.                                                             |
|     `store-map`      |                                                            Renders a map with the retail store's location.                                                            |
|   `store-address`    |                                                                     Renders the store's address.                                                                      |
|    `store-hours`     | Renders the store's opening hours. This information comes by default from the Pickup Points configuration, but you can also define manually through the Store's theme |
| `store-instructions` |                                                     Renders the desired instructions to access the retail store.                                                      |

1. Open your Store Theme app directory in your code editor.
2. In the `/store/blocks` folder of your Store Theme app, create a new file called `storelocator.json`.
3. Create a new store template in it called `store.storelocator`. In its blocks array, paste the default implementation stated below:

```json
{
  "store.storelocator": {
    "blocks": ["flex-layout.row#title", "flex-layout.row#container"]
  },
  "flex-layout.row#title": {
    "children": ["flex-layout.col#title"]
  },
  "flex-layout.row#container": {
    "children": ["store-list"]
  },
  "flex-layout.col#title": {
    "children": ["rich-text#title"],
    "props": {
      "blockClass": "title",
      "preventVerticalStretch": true
    }
  },
  "rich-text#title": {
    "props": {
      "text": "## Store Locator"
    }
  },
  "store.storedetail": {
    "blocks": ["flex-layout.row#titleStore", "store-group"]
  },
  "store-group": {
    "children": ["flex-layout.row#containerStore"],
    "props": {
      "title": "{storeName} Store"
    }
  },
  "flex-layout.row#titleStore": {
    "children": ["flex-layout.col#titleStore"]
  },
  "flex-layout.row#containerStore": {
    "children": ["flex-layout.col#detail", "flex-layout.col#store"]
  },
  "flex-layout.col#titleStore": {
    "children": ["rich-text#titleStore"],
    "props": {
      "blockClass": "title",
      "preventVerticalStretch": true
    }
  },
  "rich-text#titleStore": {
    "props": {
      "text": "## Store Detail"
    }
  },
  "flex-layout.col#detail": {
    "children": [
      "store-back-link",
      "store-map",
      "store-address",
      "store-hours",
      "store-instructions"
    ],
    "props": {
      "width": "30%",
      "preventVerticalStretch": true
    }
  },
  "flex-layout.col#store": {
    "children": ["store-name"],
    "props": {
      "width": "70%"
    }
  },
  "store-hours": {
    "props": {
      "label": "Business hours:",
      "format": "12h",
      "businessHours": [
        {
          "dayOfWeek": "Sunday",
          "openingTime": "11:00am",
          "closingTime": "5:00pm"
        },
        {
          "dayOfWeek": "Monday",
          "openingTime": "11:00am",
          "closingTime": "6:00pm"
        },
        {
          "dayOfWeek": "Tuesday",
          "openingTime": "11:00am",
          "closingTime": "6:00pm"
        },
        {
          "dayOfWeek": "Wednesday",
          "openingTime": "11:00am",
          "closingTime": "6:00pm"
        },
        {
          "dayOfWeek": "Thursday",
          "openingTime": "11:00am",
          "closingTime": "6:00pm"
        },
        {
          "dayOfWeek": "Friday",
          "openingTime": "11:00am",
          "closingTime": "6:00pm"
        },
        {
          "dayOfWeek": "Saturday",
          "openingTime": "11:00am",
          "closingTime": "5:00pm"
        }
      ]
    }
  },
  "store-back-link": {
    "props": {
      "label": "Back to all stores"
    }
  },
  "store-instructions": {
    "props": {
      "label": ""
    }
  }
}
```

4. Configure each one of the blocks previously declared as you wish using their props (check out the following tables).

#### `store-list`

|   Prop name   |   Type   |                                 Description                                  |    Default value     |
| :-----------: | :------: | :--------------------------------------------------------------------------: | :------------------: |
| `filterByTag` | `string` |                  Filter fetched Pickup Points by this tag.                   |      undefined       |
|    `icon`     | `string` | Icon used to display store location in map. Input icon URL (`svg` or `png`). |   Google's default   |
|  `iconWidth`  | `number` |                         Icon width in pixels (`px`).                         | Image default width  |
| `iconHeight`  | `number` |                        Icon height in pixels (`px`).                         | Image default height |
|    `zoom`     | `number` |                            Map zoom as a number.                             |         `10`         |
|     `lat`     | `number` |                             Latitude coordinate.                             |      undefined       |
|    `long`     | `number` |                            Longitude coordinate.                             |      undefined       |
|   `sortBy`    | `string` |        Property (`name` or `distance`) used to sort the stores list.         |      `distance`      |

> ℹ _Use the `lat` and `long` props to display Pickup Points configured in seller accounts. If these props are not configured and you do not have any pick up points set up in your main account, the app will display no stores._

> ℹ _The `filterByTag` prop cannot be used along with `lat` and `long`. If you set a value for `filterByTag`, the `lat` and `long` props will be ignored._

#### `store-group` props

|       Prop name       |   Type    |                                                                                Description                                                                                | Default value |
| :-------------------: | :-------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------: |
|        `title`        | `string`  |                                  Title used in the page's HTML `title` tag and Structured Data for SEO purposes. The `{storeName}`, `{storeCity}`, and / or `{storeState}` variables can be used in the title text.                                  | `{storeName}` |
|     `description`     | `string`  |                    Description text used in the page's HTML `description` meta tag and Structured Data for SEO purposes. The `{storeName}`, `{storeCity}`, and / or `{storeState}` variables can be used in the description text.                    | empty string  |
|    `imageSelector`    | `string`  |                                                                                CSS Selector to select the images included in the page's Structured Data.                                                                                | empty string  |
| `instructionsAsPhone` | `boolean` | To provide a unique phone number for each store, a phone number can be entered in the `Instructions` field in the Pickup Points section. The `store-instructions` will display a phone number and it will be included in the page's Structured Data. |    `false`    |

⚠ _Both `imageSelector` and `instructionsAsPhone` must be declared with valid values in order to provide Structured Data for SEO purposes._

#### `store-name` props

| Prop name |   Type   |                                                               Description                                                                | Default value |
| :-------: | :------: | :--------------------------------------------------------------------------------------------------------------------------------------: | :-----------: |
|  `text`   | `string` | Text to be displayed as store name. `{storeName}`, `{storeCity}`, and / or `{storeState}` values can be used to generate the store name. |   undefined   |
|   `tag`   | `string` |                                   HTML element to wrap the `store-name` block when rendered on the UI.                                   |     `div`     |

#### `store-back-link` props

| Prop name |   Type   |                            Description                             |    Default value     |
| :-------: | :------: | :----------------------------------------------------------------: | :------------------: |
|  `label`  | `string` | Text displayed by `store-back-link` block when rendered on the UI. | `Back to all stores` |

#### `store-map` props

| Prop name |   Type    |                                 Description                                  | Default value |
| :-------: | :-------: | :--------------------------------------------------------------------------: | :-----------: |
|  `width`  | `string`  |                                  Map width.                                  |    `100%`     |
| `height`  | `string`  |                                 Map height.                                  |    `200px`    |
|  `zoom`   | `integer` |                            Map zoom as a `number`                            |     `14`      |
|  `icon`   | `string`  | Icon used to display store location in map. Input icon URL (`svg` or `png`). |   undefined   |

#### `store-address` props

| Prop name |   Type   |                         Description                          |  Default value  |
| :-------: | :------: | :----------------------------------------------------------: | :-------------: |
|  `label`  | `string` | Label for the `store-address` block when rendered on the UI. | `Store address` |

#### `store-hours` props

|    Prop name    |       Type        |                                    Description                                    | Default value. |
| :-------------: | :---------------: | :-------------------------------------------------------------------------------: | :------------: |
|     `label`     |     `string`      |            Label for the `store-hours` block when rendered on the UI.             | `Store hours`  |
|    `format`     |      `enum`       |                 Hour format. Possible values are `12h` and `24h`.                 |     `24h`      |
| `businessHours` | `array of object` | format `{"dayOfWeek": "Sunday","openingTime": "11:00am","closingTime": "5:00pm"}` |   undefined    |

#### `store-description` props

| Prop name |   Type   |                                                                     Description                                                                      | Default value |
| :-------: | :------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------: |
|  `text`   | `string` | Text to be displayed on the store page. Use `{storeName}`, `{storeCity}`, or `{storeState}` within your text to display that store's specific value. |   undefined   |

#### `store-instructions` props

| Prop name |   Type   |                            Description                            | Default value |
| :-------: | :------: | :---------------------------------------------------------------: | :-----------: |
|  `label`  | `string` | Label for the `store-instructions` block when rendered on the UI. | `Information` |

## Customization

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

|         CSS Handles         |
| :-------------------------: |
|     `addressContainer`      |
|       `addressLabel`        |
|   `addressListFirstItem`    |
|      `addressListItem`      |
|      `addressListLink`      |
|        `addressList`        |
|    `addressStoreAddress`    |
|     `addressStoreName`      |
| `addressStoreAddressGroupA` |
| `addressStoreAddressNumber` |
| `addressStoreAddressStreet` |
|     `backlinkContainer`     |
|         `backlink`          |
|       `businessHours`       |
|         `container`         |
|   `descriptionContainer`    |
|      `descriptionText`      |
|         `dayOfWeek`         |
|          `divider`          |
|          `hourRow`          |
|      `hoursContainer`       |
|        `hoursLabel`         |
|   `instructionsContainer`   |
|     `instructionsLabel`     |
|     `instructionsText`      |
|    `listingMapContainer`    |
|          `loadAll`          |
|     `markerInfoAddress`     |
|      `markerInfoLink`       |
|    `markerInfoStoreName`    |
|        `markerInfo`         |
|         `noResults`         |
|         `storeName`         |
|       `storesListCol`       |
|        `storesList`         |
|       `storesMapCol`        |

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

## Contributors ✨

Thanks goes to these wonderful people:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!

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

```


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

[User] Show me the implementation of store-locator/graphql/schema.graphql from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Query {
  getStores(latitude: Float, longitude: Float, keyword: String): StoreResponse
    @cacheControl(scope: PRIVATE)
}

type StoreResponse {
  items: [StoreItemType]
}
type StoreItemType {
  id: String
  name: String
  instructions: String
  distance: Float
  isActive: Boolean
  address: Address
  businessHours: [Hours]
  pickupHolidays: [PickupHolidays]
}
type PickupHolidays {
  date: String
  hourBegin: String
  hourEnd: String
}

type Address {
  postalCode: String
  country: String
  city: String
  state: String
  neighborhood: String
  street: String
  number: String
  complement: String
  reference: String
  location: LocationType
}

type LocationType {
  latitude: Float
  longitude: Float
}

type Hours {
  dayOfWeek: Int
  openingTime: String
  closingTime: 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 store-locator/node/service.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "stack": "nodejs",
  "memory": 512,
  "ttl": 60,
  "timeout": 60,
  "routes": {
    "getSitemap": {
      "path": "/sitemap/store-locator.xml",
      "public": true
    }
  }
}

```


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

[User] Show me the implementation of store-locator/node/typings.d.ts from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface Logger {
  // eslint-disable-next-line @typescript-eslint/ban-types
  log(content: string, level: LogLevel, details?: {}): PromiseLike<void>
}

interface OperationState {
  orderFormId: string
  ctx: Context
  data?: OperationData
  logger: Logger
}

interface OperationData {
  orderForm?: any
  userProfileId: string
  cookie: string
}

type ProcessPaymentStep = (
  state: OperationState,
  next: () => Promise<void>
) => Promise<void>

type LogLevel = 'info' | 'error' | 'warning'

type Timings = { [middleware: string]: [number, number] }

declare module '*.json' {
  const value: any
  export default value
}

```


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

[User] Show me the implementation of store-locator/node/package.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "vtex.store-locator",
  "version": "1.0.1",
  "dependencies": {
    "co-body": "^6.0.0",
    "ramda": "^0.25.0",
    "slugify": "^1.2.6"
  },
  "devDependencies": {
    "@types/bluebird": "^3.5.25",
    "@types/co-body": "0.0.3",
    "@types/node": "^12.0.0",
    "@types/ramda": "types/npm-ramda#dist",
    "@vtex/api": "6.45.12",
    "@vtex/prettier-config": "^0.3.1",
    "tslint": "^5.12.0",
    "tslint-config-prettier": "^1.18.0",
    "tslint-config-vtex": "^2.1.0",
    "typescript": "3.9.7",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.flex-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.flex-layout@0.17.0/public/@types/vtex.flex-layout",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.130.0/public/@types/vtex.render-runtime",
    "vtex.rich-text": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.rich-text@0.14.0/public/@types/vtex.rich-text",
    "vtex.store": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.120.0/public/@types/vtex.store",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.142.6/public/@types/vtex.store-graphql",
    "vtex.store-sitemap": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-sitemap@2.13.9/public/@types/vtex.store-sitemap",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.145.0/public/@types/vtex.styleguide"
  },
  "scripts": {
    "lint": "tsc --noEmit && tslint -c tslint.json './**/*.ts'"
  }
}

```


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

[Assistant]
Here's the implementation:

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

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

const TIMEOUT_MS = 60000

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

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

// Export a service that defines route handlers and client options.
export default new Service<Clients, RecorderState, ParamsContext>({
  clients,
  graphql: {
    resolvers: {
      Query: resolvers.Query,
    },
  },
  routes: resolvers.Routes,
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreBackLink.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import React, { FC } from 'react'
import { defineMessages, WrappedComponentProps, injectIntl } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'

const CSS_HANDLES = ['backlinkContainer', 'backlink'] as const
const messages = defineMessages({
  backlink: {
    defaultMessage: 'Back to all stores',
    id: 'store/back-link',
  },
})

interface StoreBackLinkProps {
  label: string
}

const StoreBackLink: FC<StoreBackLinkProps & WrappedComponentProps> = ({
  label,
  intl,
}) => {
  const handles = useCssHandles(CSS_HANDLES)
  const { navigate } = useRuntime()

  const goBack = () => {
    navigate({
      page: 'store.storelocator',
    })
  }

  return (
    <div className={handles.backlinkContainer}>
      <span
        className={`link c-link underline-hover pointer ${handles.backlink}`}
        onClick={() => {
          goBack()
        }}
      >
        {label ?? intl.formatMessage(messages.backlink)}
      </span>
    </div>
  )
}

export default injectIntl(StoreBackLink)

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreName.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import PropTypes from 'prop-types'
import { useCssHandles } from 'vtex.css-handles'

import { useStoreGroup } from './StoreGroup'

const CSS_HANDLES = ['storeName'] as const

const StoreName: FC<StoreNameProps> = ({ text, tag }) => {
  const handles = useCssHandles(CSS_HANDLES)
  const group = useStoreGroup()

  if (!group) {
    return null
  }

  const Wrapper = tag as keyof JSX.IntrinsicElements

  const parseText = (string: string) => {
    const { city, state } = group.address

    return string
      .replace(/{storeName}/gi, group.friendlyName)
      .replace(/{storeCity}/gi, city ?? '')
      .replace(/{storeState}/gi, state ?? '')
  }

  return (
    <Wrapper className={handles.storeName}>
      {text ? parseText(text) : group.friendlyName}
    </Wrapper>
  )
}

interface StoreNameProps {
  text?: string
  tag?: string
}

StoreName.defaultProps = {
  tag: 'div',
}

StoreName.propTypes = {
  text: PropTypes.string,
  tag: PropTypes.string,
}

export default StoreName

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/List.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { FunctionComponent } from 'react'
import React, { useState, useEffect } from 'react'
import type { WrappedComponentProps } from 'react-intl'
import { injectIntl, FormattedMessage } from 'react-intl'
import { useQuery, useLazyQuery } from 'react-apollo'
import { Spinner } from 'vtex.styleguide'
import { useCssHandles } from 'vtex.css-handles'

import ORDER_FORM from './queries/orderForm.gql'
import GET_STORES from './queries/getStores.gql'
import GOOGLE_KEYS from './queries/GetGoogleMapsKey.graphql'
import Listing from './components/Listing'
import Pinpoints from './components/Pinpoints'

const CSS_HANDLES = [
  'container',
  'storesListCol',
  'storesList',
  'storesMapCol',
  'noResults',
  'listingMapContainer',
  'loadAll',
] as const

interface Props {
  filterByTag?: string
  icon?: string
  iconWidth?: number
  iconHeight?: number
  zoom?: number
  lat?: number
  long?: number
  sortBy?: string
}

const StoreList: FunctionComponent<WrappedComponentProps & Props> = ({
  filterByTag,
  icon,
  iconWidth,
  iconHeight,
  zoom,
  lat,
  long,
  sortBy = 'distance',
}) => {
  const { data: ofData, loading: ofLoading } = useQuery(ORDER_FORM, {
    ssr: false,
  })

  const { data: googleMapsKeys } = useQuery(GOOGLE_KEYS, { ssr: false })

  const [getStores, { data, loading }] = useLazyQuery(GET_STORES, {
    fetchPolicy: 'cache-first',
  })

  const [state, setState] = useState({
    allLoaded: false,
    center: null,
    zoom: zoom ?? 10,
  })

  const handles = useCssHandles(CSS_HANDLES)

  const handleLoadAll = () => {
    setState({
      ...state,
      allLoaded: true,
    })
    getStores({
      variables: {
        latitude: lat,
        longitude: long,
        filterByTag: lat && long ? null : filterByTag,
      },
    })
  }

  const handleCenter = (center: any) => {
    setState({
      ...state,
      center,
    })
  }

  useEffect(() => {
    if (!ofData?.orderForm) return

    let longitude: number | undefined
    let latitude: number | undefined

    if (
      ofData?.orderForm?.shippingData?.address?.postalCode &&
      ofData?.orderForm?.shippingData?.address?.postalCode?.indexOf('*') === -1
    ) {
      const [ofLongitude, ofLatitude] =
        ofData?.orderForm?.shippingData.address.geoCoordinates

      longitude = ofLongitude
      latitude = ofLatitude
    }

    if (!longitude || !latitude) {
      setState((prev) => ({
        ...prev,
        allLoaded: true,
      }))
    }

    getStores({
      variables: {
        latitude,
        longitude,
        filterByTag,
      },
    })
  }, [filterByTag, getStores, ofData])

  useEffect(() => {
    if (state.center || !data?.getStores?.items?.length) return

    const [firstResult] = data.getStores.items

    const { latitude, longitude } = firstResult.address.location

    const center = ofData?.orderForm?.shippingData?.address?.geoCoordinates ?? [
      longitude || long,
      latitude || lat,
    ]

    setState({
      ...state,
      center,
    })
  }, [data, lat, long, ofData, state])

  const stores =
    data?.getStores?.items.sort((a, b) => {
      if (a[sortBy] < b[sortBy]) {
        return -1
      }

      if (a[sortBy] > b[sortBy]) {
        return 1
      }

      return 0
    }) ?? []

  return (
    <div
      className={`flex flex-row ${handles.container}`}
      style={{
        maxHeight: 750,
      }}
    >
      <div className={`flex-col w-30 ${handles.storesListCol}`}>
        {(loading || ofLoading) && <Spinner />}
        {!loading && !!data && stores.length > 0 && (
          <div className={`overflow-auto h-100 ${handles.storesList}`}>
            <Listing items={stores} onChangeCenter={handleCenter} />
            {!state.allLoaded && (
              <span
                className={`mt2 link c-link underline-hover pointer ${handles.loadAll}`}
                role="button"
                tabIndex={0}
                onClick={() => {
                  handleLoadAll()
                }}
                onKeyDown={(e) => {
                  if (e.key !== 'Enter' && e.key !== ' ') return
                  e.preventDefault()
                  handleLoadAll()
                }}
              >
                <FormattedMessage id="store/load-all" />
              </span>
            )}
          </div>
        )}
        {!loading && !!data && stores.length === 0 && (
          <div className={handles.noResults}>
            <h3>
              <FormattedMessage id="store/none-stores" />
            </h3>
          </div>
        )}
      </div>
      <div className={`flex-col w-70 ${handles.storesMapCol}`}>
        {!loading &&
          !!data &&
          stores.length > 0 &&
          state.center &&
          googleMapsKeys?.logistics?.googleMapsKey && (
            <Pinpoints
              apiKey={googleMapsKeys.logistics.googleMapsKey}
              className={handles.listingMapContainer}
              items={data.getStores.items}
              zoom={state.zoom}
              center={state.center}
              icon={icon}
              iconWidth={iconWidth}
              iconHeight={iconHeight}
            />
          )}
      </div>
    </div>
  )
}

export default injectIntl(StoreList)

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreDescription.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import PropTypes from 'prop-types'
import { useCssHandles } from 'vtex.css-handles'

import { useStoreGroup } from './StoreGroup'

const CSS_HANDLES = ['descriptionContainer', 'descriptionText'] as const

const StoreDescription: FC<StoreNameProps> = ({ text }) => {
  const handles = useCssHandles(CSS_HANDLES)
  const group = useStoreGroup()

  if (!group || !text) {
    return null
  }

  const parseText = (string: string) => {
    const { city, state } = group.address

    return string
      .replace(/{storeName}/gi, group.friendlyName)
      .replace(/{storeCity}/gi, city ?? '')
      .replace(/{storeState}/gi, state ?? '')
  }

  return (
    <div className={handles.descriptionContainer}>
      <div className={handles.descriptionText}>{parseText(text)}</div>
    </div>
  )
}

interface StoreNameProps {
  text?: string
}

StoreDescription.propTypes = {
  text: PropTypes.string,
}

export default StoreDescription

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreAddress.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

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

import { useStoreGroup } from './StoreGroup'

const CSS_HANDLES = [
  'addressContainer',
  'addressLink',
  'addressLabel',
  'addressStoreAddressGroupA',
  'addressStoreAddressNumber',
  'addressStoreAddressStreet',
] as const

const messages = defineMessages({
  address: {
    defaultMessage: 'Store address',
    id: 'store/address-label',
  },
})

interface StoreAddressProps {
  label: string
}

const StoreAddress: FC<StoreAddressProps & WrappedComponentProps> = ({
  label,
  intl,
}) => {
  const handles = useCssHandles(CSS_HANDLES)

  const group = useStoreGroup()

  if (!group) {
    return null
  }

  const [lng, lat] = group.address.geoCoordinates

  return (
    <div className={handles.addressContainer}>
      <span className={`b ${handles.addressLabel}`}>
        {label ?? intl.formatMessage(messages.address)}
      </span>
      <a
        className={`${handles.addressLink} underline-hover no-underline`}
        target="_blank"
        rel="noreferrer"
        href={`https://www.google.com/maps/dir/?api=1&destination=${lat},${lng}`}
      >
        <br />
        <span className={handles.addressStoreAddressGroupA}>
          <span className={handles.addressStoreAddressNumber}>
            {group.address.number ? `${group.address.number} ` : ''}
          </span>
          <span
            className={handles.addressStoreAddressStreet}
          >{`${group.address.street}`}</span>
        </span>
        <br />
        {group.address.city ? `${group.address.city}` : ''}
        {group.address.state ? `, ${group.address.state}` : ''}
        {group.address.postalCode ? `, ${group.address.postalCode}` : ''}
      </a>
    </div>
  )
}

export default injectIntl(StoreAddress)

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/package.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "store-locator",
  "version": "1.0.1",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "@react-google-maps/api": "^2.2.0",
    "apollo-client": "^2.6.8",
    "prop-types": "^15.7.2",
    "react": "^16.12.0",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.12.0",
    "react-intl": "^3.12.0",
    "slugify": "^1.2.6"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/jest": "^25.1.4",
    "@types/node": "^13.9.8",
    "@types/react": "^16.9.31",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.4.4",
    "apollo-cache-inmemory": "^1.6.5",
    "graphql": "^14.6.0",
    "typescript": "3.9.7",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.flex-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.flex-layout@0.17.0/public/@types/vtex.flex-layout",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.130.0/public/@types/vtex.render-runtime",
    "vtex.rich-text": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.rich-text@0.14.0/public/@types/vtex.rich-text",
    "vtex.store": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.120.0/public/@types/vtex.store",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.142.6/public/@types/vtex.store-graphql",
    "vtex.store-sitemap": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-sitemap@2.13.9/public/@types/vtex.store-sitemap",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.145.0/public/@types/vtex.styleguide"
  }
}

```


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

[User] Show me the implementation of store-locator/react/StoreGroup.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { FC, ReactNode } from 'react'
import React, { useContext, useState, useEffect } from 'react'
import { useLazyQuery } from 'react-apollo'
import { useRuntime, Helmet } from 'vtex.render-runtime'

import { OptionsContext } from './contexts/OptionsContext'
import GET_STORE from './queries/getStore.gql'

const DAYS = [0, 1, 2, 3, 4, 5, 6]

const StoreGroupContext = React.createContext<SpecificationGroup | undefined>(
  undefined
)

interface StoreGroupProviderProps {
  group: SpecificationGroup
  hasPhone: boolean
}
const StoreGroupProvider: FC<StoreGroupProviderProps> = ({
  group,
  children,
  hasPhone,
}) => {
  return (
    <OptionsContext.Provider value={hasPhone}>
      <StoreGroupContext.Provider value={group}>
        {children}
      </StoreGroupContext.Provider>
    </OptionsContext.Provider>
  )
}

interface StoreGroupProps {
  children: ReactNode
  title: string
  description: string
  imageSelector: string
  phoneSelector: string
  instructionsAsPhone?: boolean
}

const getImages = (imageSelector: string) => {
  const images: string[] = []
  const elements: NodeListOf<HTMLImageElement> =
    document.querySelectorAll(imageSelector)

  if (elements.length) {
    for (let i = 0; i < elements.length; i++) {
      const { src } = elements[i]

      if (src) {
        images.push(src)
      }
    }
  }

  return images
}

const textParser = (text: string, group: SpecificationGroup) => {
  const {
    friendlyName,
    address: { city, state },
  } = group

  return text
    .replace(/{storeName}/gi, friendlyName)
    .replace(/{storeCity}/gi, city ?? '')
    .replace(/{storeState}/gi, state ?? '')
}

const buildDataType = (
  data: any,
  title: string,
  description: string,
  imageSelector: string,
  hasPhone: boolean
) => {
  const [longitude, latitude] = data.address.geoCoordinates
  const weekDays = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday',
  ]

  return {
    '@context': 'https://schema.org',
    '@type': 'Store',
    '@id': data.id,
    name: title,
    description,
    image: getImages(imageSelector),
    telephone: hasPhone ? data.instructions : '',
    address: {
      '@type': 'PostalAddress',
      streetAddress: `${data.address.number} ${data.address.street}`,
      addressLocality: data.address.city,
      addressRegion: data.address.state,
      postalCode: data.address.postalCode,
      addressCountry: data.address.country,
    },
    geo: {
      '@type': 'GeoCoordinates',
      latitude,
      longitude,
    },
    url: window.location.href,
    openingHoursSpecification: data.businessHours.map((curr: any) => {
      const [opensHour, opensMinute] = curr.openingTime.split(':')
      const [closesHour, closesMinute] = curr.closingTime.split(':')

      return {
        '@type': 'OpeningHoursSpecification',
        dayOfWeek: [weekDays[curr.dayOfWeek]],
        opens: `${opensHour}:${opensMinute}`,
        closes: `${closesHour}:${closesMinute}`,
      }
    }),
  }
}

const StoreGroup: FC<StoreGroupProps> = ({
  children,
  title,
  description,
  imageSelector,
  phoneSelector,
  instructionsAsPhone,
}) => {
  const { history } = useRuntime()
  const [pickupPoint, setPickupPoint] = useState<any>(null)
  const [parsedTitle, setParsedTitle] = useState<string>('')
  const [parsedDescription, setParsedDescription] = useState<string>('')
  const [getStore, { data, called }] = useLazyQuery(GET_STORE)

  if (history && !called) {
    const id = history.location.state.navigationRoute.params.store_id

    getStore({
      variables: {
        id,
      },
    })
  }

  if (pickupPoint?.id !== data?.pickupPoint.id) {
    const businessHours = DAYS.map((day) => {
      const openHours = data.pickupPoint.businessHours.find(
        (hours) => hours.dayOfWeek === day
      )

      if (!openHours) {
        return {
          closingTime: null,
          dayOfWeek: day,
          openingTime: null,
        }
      }

      return openHours
    })

    setPickupPoint({ ...data.pickupPoint, businessHours })
  }

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

    const pageTitle = title
      ? textParser(title, pickupPoint)
      : pickupPoint.friendlyName

    const pageDescription = description
      ? textParser(description, pickupPoint)
      : ''

    setParsedTitle(pageTitle)
    setParsedDescription(pageDescription)
  }, [pickupPoint, title, description])

  return (
    <>
      {pickupPoint && (
        <Helmet>
          <title>{parsedTitle}</title>
          <meta name="description" content={parsedDescription} />
          {!!imageSelector && (
            <script type="application/ld+json">
              {JSON.stringify(
                buildDataType(
                  data.pickupPoint,
                  parsedTitle,
                  parsedDescription,
                  imageSelector,
                  instructionsAsPhone ?? phoneSelector?.length > 0
                )
              )}
            </script>
          )}
        </Helmet>
      )}
      <StoreGroupProvider
        group={pickupPoint}
        hasPhone={instructionsAsPhone ?? phoneSelector.length > 0}
      >
        {children}
      </StoreGroupProvider>
    </>
  )
}

export const useStoreGroup = () => {
  const group = useContext(StoreGroupContext)

  return group
}

StoreGroup.defaultProps = {
  title: '{storeName}',
  description: '',
  imageSelector: '',
  phoneSelector: '',
  instructionsAsPhone: false,
}

export default StoreGroup

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreHours.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { FC } from 'react'
import { defineMessages, WrappedComponentProps, injectIntl } from 'react-intl'
import PropTypes from 'prop-types'
import { useCssHandles } from 'vtex.css-handles'

import { useStoreGroup } from './StoreGroup'

const messages = defineMessages({
  hoursLabel: {
    defaultMessage: 'Store hours',
    id: 'store/hours-label',
  },
  holidayLabel: {
    defaultMessage: 'Holidays',
    id: 'store/holidays-label',
  },
  storeClosed: {
    defaultMessage: 'Closed',
    id: 'store/store-closed',
  },
  '0': {
    defaultMessage: 'Sunday',
    id: 'store/day-of-week-sunday',
  },
  '1': {
    defaultMessage: 'Monday',
    id: 'store/day-of-week-monday',
  },
  '2': {
    defaultMessage: 'Tuesday',
    id: 'store/day-of-week-tuesday',
  },
  '3': {
    defaultMessage: 'Wednesday',
    id: 'store/day-of-week-wednesday',
  },
  '4': {
    defaultMessage: 'Thursday',
    id: 'store/day-of-week-thursday',
  },
  '5': {
    defaultMessage: 'Friday',
    id: 'store/day-of-week-friday',
  },
  '6': {
    defaultMessage: 'Saturday',
    id: 'store/day-of-week-saturday',
  },
})

const CSS_HANDLES = [
  'hoursContainer',
  'hoursLabel',
  'hourRow',
  'dayOfWeek',
  'divider',
  'businessHours',
] as const

const timeFormat = (time: string, format?: string) => {
  if (!time) {
    return ''
  }

  const [hour, minute] = time.split(':')

  if (format?.toLocaleLowerCase() === '12h') {
    return `${
      parseInt(hour, 10) > 12 ? parseInt(hour, 10) - 12 : hour
    }:${minute}${parseInt(hour, 10) >= 12 ? 'pm' : 'am'}`
  }

  return `${hour}:${minute}`
}

const StoreHours: FC<WrappedComponentProps & StoreHoursProps> = ({
  label,
  format,
  businessHours,
  pickupHolidays,
  intl,
}) => {
  const handles = useCssHandles(CSS_HANDLES)
  const group = useStoreGroup()

  if (!group) {
    return null
  }

  const displayHours = (item) => {
    const open = timeFormat(item.openingTime, format)
    const close = timeFormat(item.closingTime, format)

    if (!open && !close) {
      return intl.formatMessage(messages.storeClosed)
    }

    return `${open} - ${close}`
  }

  const displayHolidayDay = (item) => {
    const holiday = new Date(item.date)
    const dayOfWeek = holiday.getDay()
    const { locale } = intl
    const month = new Intl.DateTimeFormat(locale, {
      day: 'numeric',
      month: 'long',
    }).format(holiday)

    const today = new Date()

    if (today >= holiday) {
      return ``
    }

    return (
      <div className={`${handles.dayOfWeek} w-30`}>
        {intl.formatMessage(messages[dayOfWeek])}, {month}
      </div>
    )
  }

  const displayHolidayHours = (item) => {
    const open = timeFormat(item.hourBegin, format)
    const close = timeFormat(item.hourEnd, format)
    const holiday = new Date(item.date)

    holiday.setDate(holiday.getDate() + 1)
    const today = new Date()

    if (open === '' && close === '') {
      return (
        <div className={`${handles.businessHours} tc w-50`}>
          {intl.formatMessage(messages.storeClosed)}
        </div>
      )
    }

    if (today > holiday) {
      return ``
    }

    return (
      <div className={`${handles.businessHours} tc w-50`}>
        {open} - {close}
      </div>
    )
  }

  return (
    <div className={handles.hoursContainer}>
      <span className={`b ${handles.hoursLabel}`}>
        {label ?? intl.formatMessage(messages.hoursLabel)}
      </span>
      <br />
      {businessHours?.map((item: any, i: number) => {
        return (
          <div
            key={`hour_${i}`}
            className={`${handles.hourRow} mv1 flex flex-wrap`}
          >
            <div className={`${handles.dayOfWeek} w-30`}>
              {item.dayOfWeek}
              <span className={handles.divider}>:</span>
            </div>
            <div className={`${handles.businessHours} tc w-50`}>
              {item.openingTime} - {item.closingTime}
            </div>
          </div>
        )
      })}
      {!businessHours &&
        group.businessHours.map((item: any, i: number) => {
          return (
            <div
              key={`hour_${i}`}
              className={`${handles.hourRow} mv1 flex flex-wrap`}
            >
              <div className={`${handles.dayOfWeek} w-30`}>
                {intl.formatMessage(messages[item.dayOfWeek])}
                <span className={handles.divider}>:</span>
              </div>
              <div className={`${handles.businessHours} tc w-50`}>
                {displayHours(item)}
              </div>
            </div>
          )
        })}
      <br />
      <b>{intl.formatMessage(messages.holidayLabel)}</b>
      {!pickupHolidays &&
        group.pickupHolidays.map((item: any, i: number) => (
          <div
            key={`hour_${i}`}
            className={`${handles.hourRow} mv1 flex flex-wrap`}
          >
            {displayHolidayDay(item)}
            {displayHolidayHours(item)}
          </div>
        ))}
    </div>
  )
}

interface StoreHoursProps {
  label?: string
  format?: string
  businessHours?: any
  pickupHolidays?: any
}

StoreHours.propTypes = {
  label: PropTypes.string,
  format: PropTypes.oneOf(['24h', '12h']),
  businessHours: PropTypes.arrayOf(
    PropTypes.shape({
      dayOfWeek: PropTypes.string,
      openingTime: PropTypes.string,
      closingTime: PropTypes.string,
    })
  ),
  pickupHolidays: PropTypes.arrayOf(
    PropTypes.shape({
      date: PropTypes.string,
      hourBegin: PropTypes.string,
      hourEnd: PropTypes.string,
    })
  ),
  intl: PropTypes.any,
}

export default injectIntl(StoreHours)

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreInstructions.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC, useContext } from 'react'
import { defineMessages, WrappedComponentProps, injectIntl } from 'react-intl'
import { useCssHandles } from 'vtex.css-handles'

import { OptionsContext } from './contexts/OptionsContext'
import { useStoreGroup } from './StoreGroup'

const CSS_HANDLES = [
  'instructionsContainer',
  'instructionsLabel',
  'instructionsText',
  'instructionsLink',
] as const

const messages = defineMessages({
  information: {
    defaultMessage: 'Information',
    id: 'store/information-label',
  },
})

interface StoreInstructionsProps {
  label: string
}

const StoreInstructions: FC<StoreInstructionsProps & WrappedComponentProps> = ({
  label,
  intl,
}) => {
  const group = useStoreGroup()
  const hasPhone = useContext(OptionsContext)

  const handles = useCssHandles(CSS_HANDLES)

  if (!group?.instructions) {
    return null
  }

  return (
    <div className={handles.instructionsContainer}>
      <span className={handles.instructionsLabel}>
        {label ?? intl.formatMessage(messages.information)}
      </span>
      {hasPhone ? (
        <a
          className={`${handles.instructionsLink} underline-hover no-underline`}
          href={`tel:${group.instructions}`}
        >
          {group.instructions}
        </a>
      ) : (
        <span className={handles.instructionsText}>{group.instructions}</span>
      )}
    </div>
  )
}

export default injectIntl(StoreInstructions)

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/react/StoreMap.tsx from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { FC } from 'react'
import React from 'react'
import type { WrappedComponentProps } from 'react-intl'
import { injectIntl } from 'react-intl'
import { useQuery } from 'react-apollo'

import { useStoreGroup } from './StoreGroup'
import Map from './components/Map'
import GOOGLE_KEYS from './queries/GetGoogleMapsKey.graphql'

const DEFAULT = {
  WIDTH: '100%',
  HEIGHT: '200px',
  ZOOM: 14,
}

interface StoreMapProps {
  width: string
  height: string
  icon?: string
  iconWidth?: number
  iconHeight?: number
  googleMapsKeys: any
  zoom: number
}

const StoreMap: FC<StoreMapProps & WrappedComponentProps> = ({
  width,
  height,
  icon,
  iconWidth,
  iconHeight,
  zoom,
}) => {
  const { data: googleMapsKeys } = useQuery(GOOGLE_KEYS, { ssr: false })
  const group = useStoreGroup()

  if (!group || !googleMapsKeys?.logistics?.googleMapsKey) {
    return null
  }

  return (
    <div style={{ height, width }}>
      <Map
        apiKey={googleMapsKeys.logistics.googleMapsKey}
        loadingElement={<div style={{ height: `100%` }} />}
        mapElement={<div style={{ height: `100%` }} />}
        icon={icon}
        iconWidth={iconWidth}
        iconHeight={iconHeight}
        center={group.address.geoCoordinates}
        zoom={zoom}
      />
    </div>
  )
}

StoreMap.defaultProps = {
  width: DEFAULT.WIDTH,
  height: DEFAULT.HEIGHT,
  zoom: DEFAULT.ZOOM,
}

export default injectIntl(StoreMap)

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/store/blocks.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store.storelocator": {
    "blocks": ["flex-layout.row#title", "flex-layout.row#container"]
  },
  "flex-layout.row#title": {
    "children": ["flex-layout.col#title"]
  },
  "flex-layout.row#container": {
    "children": ["store-list"]
  },
  "flex-layout.col#title": {
    "children": ["rich-text#title"],
    "props": {
      "blockClass": "title",
      "preventVerticalStretch": true
    }
  },
  "rich-text#title": {
    "props": {
      "text": "## Store Locator"
    }
  },
  "store.storedetail": {
    "blocks": ["flex-layout.row#titleStore", "store-group"]
  },
  "store-group": {
    "children": ["flex-layout.row#containerStore"],
    "props": {
      "title": "{storeName} Store"
    }
  },
  "flex-layout.row#titleStore": {
    "children": ["flex-layout.col#titleStore"]
  },
  "flex-layout.row#containerStore": {
    "children": ["flex-layout.col#detail", "flex-layout.col#store"]
  },
  "flex-layout.col#titleStore": {
    "children": ["rich-text#titleStore"],
    "props": {
      "blockClass": "title",
      "preventVerticalStretch": true
    }
  },
  "rich-text#titleStore": {
    "props": {
      "text": "## Store Detail"
    }
  },
  "flex-layout.col#detail": {
    "children": [
      "store-back-link",
      "store-map",
      "store-address",
      "store-hours",
      "store-instructions"
    ],
    "props": {
      "width": "30%",
      "preventVerticalStretch": true
    }
  },
  "flex-layout.col#store": {
    "children": ["store-name"],
    "props": {
      "width": "70%"
    }
  },
  "store-hours": {
    "props": {
      "label": "Business hours:",
      "format": "12h"
    }
  },
  "store-back-link": {
    "props": {
      "label": "Back to all stores"
    }
  },
  "store-instructions": {
    "props": {
      "label": ""
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/store/interfaces.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store-list": {
    "component": "List"
  },
  "store-group": {
    "component": "StoreGroup",
    "composition": "children"
  },
  "store-name": {
    "component": "StoreName",
    "composition": "children"
  },
  "store-description": {
    "component": "StoreDescription",
    "composition": "children"
  },
  "store-instructions": {
    "component": "StoreInstructions",
    "composition": "children"
  },
  "store-address": {
    "component": "StoreAddress",
    "composition": "children"
  },
  "store-back-link": {
    "component": "StoreBackLink",
    "composition": "children"
  },
  "store-hours": {
    "component": "StoreHours",
    "composition": "children"
  },
  "store-map": {
    "component": "StoreMap",
    "composition": "children"
  },
  "store.storelocator": {},
  "store.storedetail": {}
}

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/store/routes.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store.storelocator": {
    "path": "/stores",
    "isSitemapEntry": true
  },
  "store.storedetail": {
    "path": "/store/:slug/:store_id",
    "isSitemapEntry": 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-locator/cypress/plugins/index.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
// / <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
 * @type {Cypress.PluginConfig}
 */

module.exports = (_on, _config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
}

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/integration/2.2.2-add_multiple_pickup_points_via_csv.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { testSetup, updateRetry } from '../support/common/support'

const prefix = 'Verify Upload XLS File'

describe('Adding Multiple pickup point', () => {
  // Load test setup
  testSetup()

  // If we upload this file cypress/fixtures/pickups.xls then it will create two pickup points
  // pickup example 1 & pickup example 2
  it(`${prefix} - Visit admin endpoint and upload file`, updateRetry(2), () => {
    cy.uploadXLS()
  })
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/integration/wipe.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { updateShippingPolicy } from '../support/graphql_testcase.js'
import { deleteAllPickupPoints } from '../support/api_testcase.js'
import data from '../support/shipping-policy.json'
import { testSetup } from '../support/common/support.js'
import { graphql } from '../support/common/graphql_utils.js'

describe('Wipe the pickup points', () => {
  testSetup(false)

  deleteAllPickupPoints()

  // If we leave the shipping policy active then it is forcing us to use pickup points in checkout
  // So, make shipping policy as inactive
  it('Update shipping policy status to inactive', () => {
    graphql(
      updateShippingPolicy(data, { status: false, pickup: false }),
      (response) => {
        expect(response.status).to.equal(200)
      }
    )
  })
})

```


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

[User] Show me the implementation of store-locator/cypress/integration/2.2.1-add_pickup_point.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { testSetup, updateRetry } from '../support/common/support'
import { addPickUpPoint } from '../support/common.js'
import { pickupTestCase } from '../support/outputvalidation.js'

describe('Adding Multiple pickup point', () => {
  // Load test setup
  testSetup()

  it('Adding PickUp Point', updateRetry(1), () => {
    addPickUpPoint(pickupTestCase.pickupPointName)
  })
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/integration/2.4-order_product_via_pick_up_store.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { testSetup, updateRetry } from '../support/common/support'
import { pickupTestCase } from '../support/outputvalidation.js'

describe('Test pickup in checkout with one of the pickup points created in 2.2 testcase', () => {
  // Load test setup
  testSetup()

  const { productName, postalCode } = pickupTestCase
  const prefix = 'Pickup In Store'

  it(`${prefix} - Adding product to cart`, updateRetry(2), () => {
    // Search the product
    cy.searchProduct(productName)
    // Add product to cart
    cy.addProduct(productName)
  })

  it(`In ${prefix} - Updating Shipping Information`, updateRetry(2), () => {
    // Update Shipping Section
    cy.updateShippingInformation({ postalCode, pickup: true, timeout: 12000 })
  })

  it(`In ${prefix} - Order the product using promisory`, updateRetry(2), () => {
    cy.orderProduct()
  })
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/integration/2.1.2-rest_graphql_apis.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { testSetup, updateRetry } from '../support/common/support'
import {
  createPickupPointAPI,
  deletePickupPointAPI,
  getPickupPointByIdAPI,
  listallPickupPointsAPI,
  searchPickupPointAPI,
  updatePickupPointAPI,
} from '../support/api_testcase.js'
import { restAPITestCase } from '../support/outputvalidation.js'
import data from '../support/shipping-policy.json'
import { updateShippingPolicy } from '../support/graphql_testcase'
import { logisticsCarrier } from '../support/app_list'
import { graphql } from '../support/common/graphql_utils'

/*
How to get shippingPolicy Id?
1. Go to /admin endpoint
2. Search for shipping strategy and from search results click to open
3. Edit any of the available shipping strategies
4. Now in url, you will get admin/shipping-strategy/shipping-policy/?id=sha1920ede3r
*/

const shippingPolicyId = 'sha1920ede3r'

const { pickupPoint1Payload, pickupPoint2Payload, pickupPoint3Payload } =
  restAPITestCase

describe('Rest & Graphql API testcases', () => {
  testSetup()

  listallPickupPointsAPI()
  createPickupPointAPI(pickupPoint1Payload)
  updatePickupPointAPI(pickupPoint1Payload, pickupPoint2Payload)
  getPickupPointByIdAPI(pickupPoint2Payload)
  deletePickupPointAPI(pickupPoint2Payload)
  searchPickupPointAPI()
  createPickupPointAPI(pickupPoint3Payload)
  // Shipping policy should be updated to active
  // Then only we can use pickup in 2.4 testcase
  it(
    'Update shipping policy status to active and enable pickup points',
    updateRetry(5),
    () => {
      cy.addDelayBetweenRetries(1000)
      graphql(
        logisticsCarrier,
        updateShippingPolicy(data, {
          status: true,
          pickup: true,
        }),
        (response) => {
          expect(response.status).to.equal(200)
          expect(response.body.data.updateShippingPolicy.id).to.equal(
            shippingPolicyId
          )
        }
      )
    }
  )
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/integration/2.5-inactive_pickup_scenarios.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { testSetup, updateRetry } from '../support/common/support'
import {
  listallPickupPointsAPI,
  INTIAL_PICKUP_POINTS_ENV,
  updatePickupPointdata,
} from '../support/api_testcase'
import { restAPITestCase } from '../support/outputvalidation.js'
import storelocatorSelectors from '../support/selectors.js'
import { clickLoadAllStores } from '../support/common.js'
import { graphql } from '../support/common/graphql_utils'
import { getStores } from '../support/graphql_testcase'
import { storeLocator } from '../support/app_list'

const { pickupPoint3Payload } = restAPITestCase

describe('Inactive Pickup Points should not be visible in storefront', () => {
  testSetup()

  listallPickupPointsAPI()

  updatePickupPointdata(pickupPoint3Payload)

  it(
    `Verify the inactive pickup point "${pickupPoint3Payload.name}" is not visible in stores page`,
    updateRetry(3),
    () => {
      cy.getPickupPointItem().then((pickupCount) => {
        cy.visitStore()
        cy.get(storelocatorSelectors.StorePickUpPointList, {
          timeout: 8000,
        }).should('be.visible')
        clickLoadAllStores()
        cy.get(storelocatorSelectors.MoreItems, { timeout: 8000 }).should(
          'have.length',
          pickupCount[INTIAL_PICKUP_POINTS_ENV] + 3
        )
        cy.get(storelocatorSelectors.StorePickUpPointList, {
          timeout: 8000,
        }).should('not.contain', `${pickupPoint3Payload.name}`)
      })
    }
  )

  it('verify getStores with latitude and longitude', updateRetry(5), () => {
    graphql(storeLocator, getStores(-22.94, -43.18), (response) => {
      cy.addDelayBetweenRetries(10000)
      expect(response.status).to.equal(200)
      const pickupPoints = response.body.data.getStores.items.map((p) =>
        p.name.includes('pickup example')
      )

      expect(pickupPoints.length).to.equal(2)
    })
  })

  it('verify getStores without latitude and longitude', updateRetry(5), () => {
    graphql(storeLocator, getStores(), (response) => {
      cy.addDelayBetweenRetries(4000)
      expect(response.status).to.equal(200)
      expect(response.body.data.getStores.items.length).to.not.equal(0)
    })
  })
})

```


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

[User] Show me the implementation of store-locator/cypress/integration/2.3-verify_pickup_points.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { testSetup, updateRetry } from '../support/common/support'
import { verifyAllPickUpPoint } from '../support/common.js'
import { listallPickupPointsAPI } from '../support/api_testcase.js'

describe('Verify all pickup points is displayed', () => {
  // Load test setup
  testSetup()

  listallPickupPointsAPI()
  it('Verify all pickup points is shown in stores', updateRetry(5), () => {
    cy.addDelayBetweenRetries(10000)
    verifyAllPickUpPoint()
  })
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/integration/2.1.1-delete_pickup_points.spec.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { deleteAllPickupPoints } from '../support/api_testcase.js'
import { testSetup } from '../support/common/support.js'

describe('Wipe the pickup points', () => {
  testSetup(false)

  deleteAllPickupPoints()
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/support/selectors.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
export default {
  AddPickUpButton: '.vtex-button .vtex-button__label div',
  SaveChanges: '.vtex-button > .vtex-button__label',
  ChangesSaved: 'div[class*=vtex-toast] .pr5',
  ListOfStores: '.overflow-auto > .list',
  LoadStores: 'span[class*=loadAll]',
  MoreItems: 'span[class*=addressListLink]',
  AddressContainer: 'div[class*=addressContainer]',
  BackToPickUpPoint: 'span[class*=backlink]',
  VtexButton: '.vtex-button',
  UploadInput: 'input[type=file]',
  CloseIcon: '.vtex-modal__close-icon',
  VtexAlert: '.vtex-alert .ph5',
  VtexStoreName: 'span[class*=addressStoreName]',
  HoursContainer: 'div[class*=hoursContainer]',
  SaveButton: '.flex.justify-end > .pb7 > .vtex-button > .vtex-button__label',
  StorePickUpPointList: '.overflow-auto > .list',
  PickupInStoresAddressLink: '.srp-address-title',
  PickupInStoresShowList: '#pkpmodal-show-list-btn',
  ShippingPolicyPickUpPointToggle: '#active',
  ShippingPolicySaveChanges:
    '.styleguide__floating-action-bar > :nth-child(2) > .vtex-button',
  PickUpModelSearch: 'form[class*=modalSearch] input',
  FindPickupLink: '#find-pickup-link',
  ShippingPolicyStatusToggle: '#isActive',
  ShippingPolicyActiveStatus:
    'label[for="isActive"] > div > div[class*=primary]',
  ShippingPolicyPickupPointStatus:
    'label[for="active"] > div > div[class*=primary]',
  FillInvoiceAddress: 'p[class*=omnishipping] ~ button[class*=omnishipping]',
}

export function getAddressLink(index) {
  return `span[class*=addressListItem]:nth-child(${
    index + 1
  }) span[class*=addressListLink]`
}

export function getPickupPoint(pickupPoint) {
  return `.pickupPoint-1_${pickupPoint}`
}

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/support/app_list.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
export default {
  storeLocator: 'vtex.store-locator',
  logisticsCarrier: 'vtex.logistics-carrier-graphql',
}

```


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

[User] Show me the implementation of store-locator/cypress/support/shipping-policy.json from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "shippingPolicy": {
    "numberOfItemsPerShipment": 1,
    "id": "sha1920ede3r",
    "name": "Test Shipping",
    "shippingMethod": "Test",
    "carrierSchedule": [
      {
        "dayOfWeek": 0,
        "timeLimit": "23:59:59"
      },
      {
        "dayOfWeek": 1,
        "timeLimit": "23:59:59"
      },
      {
        "dayOfWeek": 2,
        "timeLimit": "23:59:59"
      },
      {
        "dayOfWeek": 3,
        "timeLimit": "23:59:59"
      },
      {
        "dayOfWeek": 4,
        "timeLimit": "23:59:59"
      },
      {
        "dayOfWeek": 5,
        "timeLimit": "23:59:59"
      },
      {
        "dayOfWeek": 6,
        "timeLimit": "23:59:59"
      }
    ],
    "pickupPointsSettings": {
      "pickupPointIds": ["1"],
      "pickupPointTags": [],
      "sellers": []
    },
    "shippingHoursSettings": {
      "shippingHours": [
        {
          "dayOfWeek": 0,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        },
        {
          "dayOfWeek": 1,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        },
        {
          "dayOfWeek": 2,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        },
        {
          "dayOfWeek": 3,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        },
        {
          "dayOfWeek": 4,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        },
        {
          "dayOfWeek": 5,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        },
        {
          "dayOfWeek": 6,
          "ranges": [
            {
              "openingTime": "00:00:00",
              "closingTime": "23:59:59"
            }
          ]
        }
      ],
      "acceptOrdersOutsideShippingHours": true
    }
  }
}

```


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

[User] Show me the implementation of store-locator/cypress/support/index.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
// Import commands.js using ES2015 syntax:
import './common/commands'
import './common/api_commands'
import './commands'

// Configure it to preserve cookies
Cypress.Cookies.defaults({
  preserve: /VtexIdclientAutCookie/,
})

```


[System] You are an expert VTEX IO developer. You specialize 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-locator/cypress/support/api_testcase.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { VTEX_AUTH_HEADER, FAIL_ON_STATUS_CODE } from './common/constants'
import { updateRetry } from './common/support'
import {
  getPickupPoints,
  createPickupPoint,
  updatePickupPoint,
  getPickupPointById,
  deletePickupPoint,
  searchPickupPoint,
} from './apis'

export const INTIAL_PICKUP_POINTS_ENV = 'INTIAL_PICKUP_POINTS_ENV'

const FILTER_PICKUP_POINT_KEY = 'pickup example'

export function filterPickupPoint(response, filterByPickupExample = true) {
  return response.body.filter((b) =>
    filterByPickupExample
      ? b.name.includes(FILTER_PICKUP_POINT_KEY)
      : !b.name.includes(FILTER_PICKUP_POINT_KEY)
  )
}

export function setIntialPickupPoints(response) {
  const pickupointsCount = filterPickupPoint(response, false).length

  cy.setPickupPointItem(INTIAL_PICKUP_POINTS_ENV, pickupointsCount)
}

export function listallPickupPointsAPI() {
  it('List all pickup points via API', updateRetry(2), () => {
    cy.addDelayBetweenRetries(2000)
    cy.getVtexItems().then((vtex) => {
      cy.getAPI(getPickupPoints(vtex.baseUrl)).then((response) => {
        expect(response.status).to.equal(200)
        setIntialPickupPoints(response)
      })
    })
  })
}

export function createPickupPointAPI(pickupPointPayload) {
  it(
    `Create a pickup point "${pickupPointPayload.name}" via API`,
    updateRetry(2),
    () => {
      cy.addDelayBetweenRetries(2000)
      cy.getVtexItems().then((vtex) => {
        cy.request({
          method: 'POST',
          url: createPickupPoint(vtex.baseUrl),
          headers: {
            ...VTEX_AUTH_HEADER(vtex.apiKey, vtex.apiToken),
          },
          body: pickupPointPayload,
          ...FAIL_ON_STATUS_CODE,
        }).then((response) => {
          cy.log(response)
          expect(response.status).to.equal(200)
          expect(response.body).to.have.property('name')
          expect(response.body).to.have.property('id')
          // In storelocators.json -> {pickup_point_name : response.body.id }
          cy.setPickupPointItem(pickupPointPayload.name, response.body.id)
        })
      })
    }
  )
}

export function updatePickupPointAPI(
  currentPickupPointPayload,
  updatedPickupPointPayload
) {
  it(
    `Update a pickup point "${currentPickupPointPayload.name}" payload with "${updatedPickupPointPayload.name}" payload via API`,
    updateRetry(2),
    () => {
      cy.addDelayBetweenRetries(2000)
      cy.getVtexItems().then((vtex) => {
        cy.getPickupPointItem().then((data) => {
          cy.request({
            method: 'POST',
            url: updatePickupPoint(vtex.baseUrl),
            headers: {
              ...VTEX_AUTH_HEADER(vtex.apiKey, vtex.apiToken),
            },
            body: updatedPickupPointPayload,
            qs: { id: data[currentPickupPointPayload.name] },

            ...FAIL_ON_STATUS_CODE,
          }).then((response) => {
            // In storelocators.json -> {pickup_point_name : response.body.id }
            cy.setPickupPointItem(
              updatedPickupPointPayload.name,
              response.body.id
            )
            expect(response.status).to.equal(200)
            expect(response.body).to.have.property(
              'name',
              updatedPickupPointPayload.name
            )
          })
        })
      })
    }
  )
}

export function getPickupPointByIdAPI(pickupPointPayload) {
  it(
    `List the pickup point by "${pickupPointPayload.name}'s" id via API`,
    updateRetry(2),
    () => {
      cy.addDelayBetweenRetries(2000)
      cy.getVtexItems().then((vtex) => {
        cy.getPickupPointItem().then((data) => {
          cy.getAPI(
            getPickupPointById(vtex.baseUrl, data[pickupPointPayload.name])
          ).then((response) => {
            expect(response.status).to.equal(200)
            expect(response.body).to.have.property('name')
            expect(response.body).to.have.property('id')
          })
        })
      })
    }
  )
}

export function deletePickupPointAPI(pickupPointPayload) {
  it(
    `Delete a pickup point ${pickupPointPayload.name} via API`,
    updateRetry(2),
    () => {
      cy.addDelayBetweenRetries(2000)
      cy.getVtexItems().then((vtex) => {
        cy.getPickupPointItem().then((data) => {
          cy.request({
            method: 'DELETE',
            url: deletePickupPoint(vtex.baseUrl, data[pickupPointPayload.name]),
            headers: {
              ...VTEX_AUTH_HEADER(vtex.apiKey, vtex.apiToken),
            },
            ...FAIL_ON_STATUS_CODE,
          }).then((response) => {
            expect(response.status).to.equal(204)
          })
        })
      })
    }
  )
}

export function deleteAllPickupPoints() {
  it(
    `Filter and delete pickup point which starts with "${FILTER_PICKUP_POINT_KEY}"`,
    updateRetry(5),
    () => {
      cy.getVtexItems().then((vtex) => {
        cy.getAPI(getPickupPoints(vtex.baseUrl)).then((response) => {
          // Pickup points created in E2E tests should start with text "pickup example"
          // If we create other pickup points then it will not be deleted in wipe
          const filterPickUpPoints = filterPickupPoint(response, true)

          if (filterPickUpPoints.length > 0) {
            for (const element of filterPickUpPoints) {
              cy.request({
                method: 'DELETE',
                url: deletePickupPoint(vtex.baseUrl, element.id),
                headers: {
                  ...VTEX_AUTH_HEADER(vtex.apiKey, vtex.apiToken),
                },
                ...FAIL_ON_STATUS_CODE,
              }).then((deleteResponse) => {
                expect(deleteResponse.status).to.equal(204)
              })
            }
          }
        })
      })
    }
  )
}

export function searchPickupPointAPI() {
  it('Search pickup points via API', updateRetry(2), () => {
    cy.addDelayBetweenRetries(2000)
    cy.getVtexItems().then((vtex) => {
      cy.request({
        method: 'GET',
        url: searchPickupPoint(vtex.baseUrl),
        headers: {
          ...VTEX_AUTH_HEADER(vtex.apiKey, vtex.apiToken),
        },
        qs: {
          page: 1,
          pageSize: 5,
        },
        ...FAIL_ON_STATUS_CODE,
      }).then((response) => {
        expect(response.status).to.equal(200)
        expect(response.body).to.have.property('paging')
      })
    })
  })
}

export function updatePickupPointdata(pickupPointPayload) {
  it(
    `Update a pickup point "${pickupPointPayload.name}" as inactive`,
    updateRetry(2),
    () => {
      cy.addDelayBetweenRetries(2000)
      cy.getVtexItems().then((vtex) => {
        cy.getPickupPointItem().then((data) => {
          pickupPointPayload.isActive = false

          cy.request({
            method: 'POST',
            url: updatePickupPoint(vtex.baseUrl),
            headers: {
              ...VTEX_AUTH_HEADER(vtex.apiKey, vtex.apiToken),
            },
            body: pickupPointPayload,

            qs: { id: data[pickupPointPayload.name] },

            ...FAIL_ON_STATUS_CODE,
          }).then((response) => {
            expect(response.status).to.equal(200)
            expect(response.body).to.have.property('isActive', 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-locator/cypress/support/outputvalidation.js from the store-locator VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { PRODUCTS } from './common/utils.js'

function generatePickupPoint(pickupPointName) {
  return {
    address: {
      country: {
        acronym: 'CAN',
        name: 'CANADA',
      },
      location: {},
      postalCode: '600079',
      city: 'TORONTO',
      state: 'ONTARIO',
      neighborhood: 'BOTAFOGO',
      street: '92 Rue de Strasbourg',
      number: '10025698',
      complement: '3 RD FLOOR',
      reference: 'GREY BUILDING',
    },
    businessHours: [
      {
        dayOfWeek: 1,
        openingTime: '08:00:00',
        closingTime: '20:00:00',
      },
    ],
    id: '45678',
    name: pickupPointName,
    description: 'do it',
    instructions: 'do it properly',
    formatted_address: 'undefined',
    isActive: true,
  }
}

// NOTE: pickup point name should starts with pickup example

export default {
  restAPITestCase: {
    pickupPoint1Payload: {
      address: {
        country: {
          acronym: 'IND',
          name: 'INDIA',
        },
        location: {},
        postalCode: '600077',
        city: 'france',
        state: 'TAMILNADU',
        neighborhood: 'BOTAFOGO',
        street: '92 Rue de Strasbourg',
        number: '10025698',
        complement: '3 RD FLOOR',
        reference: 'GREY BUILDING',
      },
      businessHours: [
        {
          dayOfWeek: 1,
          openingTime: '08:00:00',
          closingTime: '20:00:00',
        },
      ],
      id: '45678',
      name: 'pickup example puma',
      description: 'do it',
      instructions: 'do it properly',
      formatted_address: 'undefined',
      isActive: true,
    },
    pickupPoint2Payload: generatePickupPoint('pickup example walmart'),
    /*
     pickupPoint1 is created in cypress/integration/2.1.2-rest_graphql_apis.spec.js
     & in same testcase it is been replaced with pickupPoint2
    */
    pickupPoint3Payload: generatePickupPoint('pickup example adidas'),
    /*
    pickupPoint3 is created in cypress/integration/2.1.2-rest_graphql_apis.spec.js
    & will make it inactive in cypress/integration/2.5-inactive_pickup_scenarios.spec.js
    */
  },

  pickupTestCase: {
    productName: PRODUCTS.coconut,
    postalCode: '94536',
    // This pickup will be created in cypress/integration/2.2.2-add_multiple_pickup_points.spec.js
    // & it will be used in cypress/integration/2.4-order_product_via_pick_up_store.spec.js
    pickupPointName: 'pickup example reebok',
  },
}

```