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

[User] Show me the implementation of wish-list-v2/docs/README.md from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

# My Wishlists

<!-- 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 **My Wishlists** app handles the favorite products of users. Users can create multiple lists and add the products they like to those lists. They can manage them and Add them to the cart and buy.

![Alt text](image-1.png)

## Configuration

To configure the My Wishlists app, check the sections below.

### Adding the My Wishlists app to your theme's dependencies

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

```json
"dependencies": {
    "vtex.my-wishlists": "2.x"
}
```

Now, you can use all the blocks exported by the `my-wishlists` app.

Add the `wishlist-button` to Product Details page. In the example below, the `wishlist-button` is added to the `flex-layout.row` block from the `store.product` template, which uses the product context:

```json
  "store.product": {
    "children": [
      "flex-layout.row#wishlist-button-pdp",
    ]
  },
  "flex-layout.row#wishlist-button-pdp": {
    "children": [
      "button-wishlist-pdp"
    ]
  }
```

Add the `wishlist-button` to Search page. In the example below, the `wishlist-button` is added to the `product-summary.shelf` block under the `gallery` in `store.search` template:

```json
  "product-summary.shelf": {
    "children": ["responsive-layout.desktop#productSummary"]
  },
  "responsive-layout.desktop#productSummary": {
    "children": [
      "flex-layout.row#wishlist-button-plp"
    ]
  },
  "flex-layout.row#wishlist-button-plp": {
    "children": [
      "button-wishlist-pdp"
    ]
  }
```

## Master Data

Data in the wishlist are stored in VTEX masterdata entity named `myWishlists`.

This entity is created automatically when first time accessing the wishlist.

### Updating schema

If masterdata schema is updated during the development (if any changes added to schema), schema version needs to be updated.
On each schema version update new schema is created automatically with following format `{versionNumber}-mywishlists` (i.e. `0.0.2-mywishlists`).

#### Master data schema

Here is the latest masterdata schema.

Data Entity Name: `myWishlists`
Schema Name: `0.0.4-mywishlists`

<details><summary>myWishlists</summary>

```json
{
  "properties": {
    "email": {
      "type": "string",
      "format": "email"
    },
    "wishlistType": {
      "type": "string"
    },
    "products": {
      "type": "array"
    },
    "isPublic": {
      "type": "boolean"
    },
    "fieldsConfig": {
      "type": "array"
    }
  },
  "required": ["email", "wishlistType", "products", "isPublic"],
  "v-indexed": [
    "email",
    "wishlistType",
    "products",
    "isPublic",
    "fieldsConfig"
  ],
  "v-default-fields": [
    "email",
    "wishlistType",
    "products",
    "isPublic",
    "fieldsConfig"
  ],
  "v-cache": false,
  "v-immediate-indexing": true,
  "v-security": {
    "allowGetAll": true,
    "publicRead": [
      "id",
      "email",
      "wishlistType",
      "products",
      "isPublic",
      "fieldsConfig"
    ],
    "publicWrite": [
      "email",
      "wishlistType",
      "products",
      "isPublic",
      "fieldsConfig"
    ],
    "publicFilter": [
      "email",
      "wishlistType",
      "products",
      "isPublic",
      "fieldsConfig"
    ]
  }
}
```

</details>

## Wishlist Share Component

To use the Wishlist Share component you must add the route to your store theme

1. Add the route
```routes.json```
```json
{
  "store.custom#wishlistshare": {
    "path": "/wishlist-share"
  }
}
```
2. Add the block to the store

**Example**

```wishlistshare.jsonc```
```json
{
  "store.custom#wishlistshare": {
    "blocks": [
      "flex-layout.row#wishlistshare"
    ]
  },
  "flex-layout.row#wishlistshare": {
    "children": [
      "wishlist-share"
    ]
  }
}
```

## 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                           |
| ------------------------------------- |
| `notesContainer`                      |
| `addNotesIcons`                       |
| `notesButtonContainer`                |
| `notesSubmitButtonContainer`          |
| `notesSubmitButton`                   |
| `notesSubmitDisabledButton`           |
| `notesModalContainer`                 |
| `notesModalTitle`                     |
| `notesModalBottomRow`                 |
| `notesCancelButton`                   |
| `productSummary`                      |
| `productSummaryImageContainer`        |
| `productSummaryImage`                 |
| `productSummaryInfo`                  |
| `productSummaryInfoName`              |
| `productSummaryInfoDetails`           |
| `productSummaryInfoDetailsPartNumber` |
| `productSummaryInfoDetailsPrice`      |
| `noteSubTitle`                        |
| `autocompleteInputWrapper`            |
| `productPriceContainer`               |
| `unitPriceContainer`                  |
| `wishlistNameContainer`               |
| `buttonWishlistName`                  |
| `titleWishlistName`                   |
| `wishlistName`                        |
| `wishlistSearchContainer`             |
| `wishlistProductTexts`                |
| `wishlistSelector`                    |
| `wishlistSearchSKUContainer`          |
| `wishlistPrivacyOptionsContainer`     |
| `componentContainer`                  |
| `componentContainerHelper`            |
| `addSkuContainer`                     |
| `textContainer`                       |
| `textContainerTitle`                  |
| `textContainerDescription`            |
| `wishlistOptionTexts`                 |
| `wishlistCreationOptions`             |
| `wishlistCreateNew`                   |
| `wishlistDelete`                      |
| `wishlistAddItem`                     |
| `wishlistRemoveItem`                  |
| `wishlistDeleteWishList`              |
| `wishlistDeleteItem`                  |
| `wishlistCreateNewHelper`             |
| `wishlistSearchSKU`                   |
| `wishlistSelectListOne`               |
| `wishlistSelectListOneOption`         |
| `wishlistSelectListOneText`           |
| `MyWishListsPage`                     |
| `containerLinkShare`                  |
| `popupCopy`                           |
| `privacySettings`                     |
| `createListandAndSelectFav`           |
| `nameAndOptionsMobile`                |
| `optionsMobile`                       |

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

---

Check out some documentation models that are already live:

- [Breadcrumb](https://github.com/vtex-apps/breadcrumb)
- [Image](https://vtex.io/docs/components/general/vtex.store-components/image)
- [Condition Layout](https://vtex.io/docs/components/all/vtex.condition-layout@1.1.6/)
- [Add To Cart Button](https://vtex.io/docs/components/content-blocks/vtex.add-to-cart-button@0.9.0/)
- [Store Form](https://vtex.io/docs/components/all/vtex.store-form@0.3.4/)

```


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

[User] Show me the implementation of wish-list-v2/graphql/schema.graphql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
# To really understand GraphQL, go to https://graphql.org/learn/

type Wishlist {
  id: ID
  email: String
  wishlistType: String
  products: [Products]
  isPublic: Boolean
  fieldsConfig: FieldsConfig
  createdIn: String
}

input WishlistInput {
  id: ID
  wishlistType: String
  products: [ProductsInput]
  isPublic: Boolean
  fieldsConfig: FieldsConfigInput
}

input FieldsConfigInput {
  department: String
  description: String
}

type FieldsConfig {
  department: String
  description: String
}

input ProductsInput {
  ID: Int
  Image: String
  linkProduct: String
  nameProduct: String
  quantityProduct: Int
  skuCodeReference: String
  department: String
  bundle: Int
  notes: String
  unitValue: Float
}

type Products {
  ID: Int
  Image: String
  linkProduct: String
  nameProduct: String
  quantityProduct: Int
  skuCodeReference: String
  department: String
  bundle: Int
  notes: String
}

type DocumentCreatedResponse {
  Id: String
  Href: String
  DocumentId: String
}

type DeleteWishlistResponse {
  id: String
  success: Boolean
}

type UpdateWishlistResponse {
  id: String
  success: Boolean
}

type DateRange {
  from: String
  to: String
}

type FixedPrices {
  tradePolicyId: String
  value: Float
  listPrice: Float
  minQuantity: Int
  dateRange: DateRange
}

type Query {
  """
  Return a wishlist
  """
  getWishlist(id: ID!): Wishlist

  """
  Returns a list of wishlist by email user
  """
  getWishlistsByEmail(page: Int, pageSize: Int): [Wishlist]
}

type Mutation {
  """
  Create a new wishlist
  """
  createWishlist(wishlist: WishlistInput!): DocumentCreatedResponse

  """
  Update a existing wishlist
  """
  updateWishlist(wishlist: WishlistInput): UpdateWishlistResponse

  """
  Delete a wishlist
  """
  deleteWishlist(id: ID!): DeleteWishlistResponse
}

```


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

[User] Show me the implementation of wish-list-v2/node/service.json from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

```


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

[User] Show me the implementation of wish-list-v2/node/package.json from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "@graphql-tools/schema": "^10.0.3",
    "@graphql-tools/utils": "^10.1.2",
    "@vtex/clients": "^2.21.0",
    "graphql": "^16.8.1",
    "graphql-tools": "^9.0.1",
    "ramda": "^0.26.1"
  },
  "devDependencies": {
    "@types/node": "^12.0.0",
    "@types/ramda": "types/npm-ramda#dist",
    "@vtex/api": "6.48.0",
    "@vtex/test-tools": "^3.4.3",
    "@vtex/tsconfig": "^0.5.6",
    "typescript": "3.9.7",
    "vtex.apps-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.apps-graphql@3.17.4/public/@types/vtex.apps-graphql",
    "vtex.checkout-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-graphql@0.67.1/public/@types/vtex.checkout-graphql",
    "vtex.checkout-resources": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-resources@0.50.0/public/@types/vtex.checkout-resources",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@1.0.1/public/@types/vtex.css-handles",
    "vtex.my-account": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account@1.29.0/public/@types/vtex.my-account",
    "vtex.my-account-commons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account-commons@1.7.2/public/@types/vtex.my-account-commons",
    "vtex.order-items": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-items@0.14.0/public/@types/vtex.order-items",
    "vtex.order-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-manager@0.12.0/public/@types/vtex.order-manager",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.9.0/public/@types/vtex.pixel-manager",
    "vtex.product-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-context@0.10.1/public/@types/vtex.product-context",
    "vtex.quickorder": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.quickorder@3.16.0/public/@types/vtex.quickorder",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.134.11/public/@types/vtex.render-runtime",
    "vtex.search-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-graphql@0.65.0/public/@types/vtex.search-graphql",
    "vtex.store": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.137.3/public/@types/vtex.store",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.172.1/public/@types/vtex.store-graphql",
    "vtex.store-icons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-icons@0.18.0/public/@types/vtex.store-icons",
    "vtex.store-resources": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-resources@0.101.0/public/@types/vtex.store-resources",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.146.13/public/@types/vtex.styleguide"
  },
  "scripts": {
    "lint": "tsc --noEmit && tslint -c tslint.json './**/*.ts'"
  },
  "version": "2.3.12"
}

```


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

[User] Show me the implementation of wish-list-v2/node/index.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { Clients } from './clients'
import { mutations, queries, resolvers } from './resolvers'

const MEDIUM_TIMEOUT_MS = 5 * 1000

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 resolvers and clients' options
export default new Service<Clients, RecorderState, ParamsContext>({
  clients: {
    implementation: Clients,
    options: {
      default: {
        timeout: MEDIUM_TIMEOUT_MS,
      },
    },
  },
  graphql: {
    resolvers: {
      ...resolvers,
      Mutation: {
        ...mutations,
      },
      Query: {
        ...queries,
      },
    },
  },
})

```


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

[User] Show me the implementation of wish-list-v2/react/MyWishListsPage.jsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```jsx
import React from 'react'
import { Route } from 'vtex.my-account-commons/Router'

import MyWishLists from './components/MyWishLists'
import styles from './styles.css'

const MyWishListsPage = () => (
  <div className={styles.MyWishListsPage}>
    <Route path="/my-wishlists" exact component={MyWishLists} />
  </div>
)

export default MyWishListsPage

```


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

[User] Show me the implementation of wish-list-v2/react/styles.css from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```css
:global(.ReactVirtualized__Grid__innerScrollContainer)
  :global(.flex .items-center .w-100 .h-100) {
  height: 100% !important;
  text-align: center !important;
}

.wishlistNameContainer {
  display: flex;
  justify-content: flex-start;
}

.buttonWishlistName {
  color: #ffffff;
  background-color: #002266;
  margin-left: 1em;
  text-transform: capitalize;
  border-radius: 50px;
  border-color: transparent;
  font-weight: 700;
  cursor: pointer;
  padding: 3px;
  width: 81px;
}

.titleWishlistName {
  margin-bottom: 10px;
  border: 2px solid #e3e4e6;
  border-radius: 4px;
  text-align: -webkit-center;
}

:global(.ReactVirtualized__Grid__innerScrollContainer) :global(span) {
  text-align: center !important;
  width: 100% !important;
}

:global(.ReactVirtualized__Grid__innerScrollContainer)
  .wishlistProductUnitValue {
  text-align: right !important;
  padding-right: 5px;
}

:global(.ReactVirtualized__Grid__innerScrollContainer) :global(div > a) {
  justify-content: center;
  display: flex;
}

/* :global(.ReactVirtualized__Grid__innerScrollContainer) > :global(div):nth-child(3) > :global(div) {
  width: auto;
}

:global(.ReactVirtualized__Grid__innerScrollContainer) > :global(div):nth-child(4) > :global(span) {
  width: auto !important;
}

:global(.ReactVirtualized__Grid__innerScrollContainer) > :global(div):nth-child(5) > :global(div) {
  width: auto;
} */

.wishlistSearchContainer :global(.vtex-input-prefix__group) {
  display: flex;
  align-items: center;
  border-radius: 0.3125rem;
  border: 2px solid #e3e4e6;
  height: 2.375rem;
}

.wishlistSearchContainer :global(.vtex-styleguide-9-x-input) {
  border-right: 0.125rem solid #e3e4e6;
  height: 100%;
}

.wishlistSearchContainer
  :global(.vtex-input-prefix__group)
  :global(.vtex-input__suffix) {
  width: 1.375rem;
  height: 1.375rem;
  padding: 0 0.5rem;
  height: 100%;
}

.wishlistSearchContainer
  :global(.vtex-input-prefix__group)
  :global(.vtex-input__suffix)
  div
  div {
  display: none;
}

.wishlistSearchContainer
  :global(.vtex-input-prefix__group)
  :global(.vtex-input__suffix)
  span {
  padding: 0;
}

.wishlistSearchContainer
  :global(.vtex-input-prefix__group)
  :global(.vtex-input__suffix)
  svg {
  width: 0.8125rem;
  color: #002266;
}

.wishlistSearchContainer
  :global(.vtex-input-prefix__group)
  :global(.vtex__icon-clear) {
  margin-left: 0.375rem;
}

.wishlistSearchContainer
  :global(.vtex-table__container)
  > div:nth-child(2)
  button {
  color: #002266;
}

:global(#toggleFieldsBtn) :global(.vtex-button__label) > span {
  color: #002266;
}

:global(#toggleFieldsBtn) :global(.vtex-button__label) > span:first-child {
  display: none;
}

:global(.ReactVirtualized__Grid__innerScrollContainer) :global(div > a > img) {
  width: 75% !important;
  display: flex;
  justify-content: center !important;
}

:global(.ReactVirtualized__Grid__innerScrollContainer)
  :global(div):nth-child(4) {
  justify-content: initial !important;
}

.wishlistName {
  font-size: 35px;
  font-weight: 700;
  margin-right: 3em;
  text-transform: capitalize;
  cursor: pointer;
}

.wishlistProductTexts,
.wishlistProductTexts a {
  font-weight: 400;
  color: #000000;
  text-decoration: none;
}

:global(.ReactVirtualized__Grid__innerScrollContainer) :global(div) {
  text-align: center;
}
:global(.ReactVirtualized__Grid__innerScrollContainer)
  :global(.vtex-numeric-stepper__plus-button),
:global(.vtex-numeric-stepper__minus-button) {
  border: none !important;
}

:global(.ReactVirtualized__Grid__innerScrollContainer)
  :global(.vtex-numeric-stepper__minus-button__text),
:global(.vtex-numeric-stepper__plus-button__text) {
  font-size: 20px !important;
  font-weight: 700 !important;
}

:global(.ReactVirtualized__Grid__innerScrollContainer)
  :global(.vtex-numeric-stepper__input) {
  width: 50px !important;
}

.wishlistSelector {
  width: 100%;
  align-items: baseline;
}
.wishlistSelector label {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  width: fit-content;
  height: 30px;
}

.wishlistSelector,
.wishlistSearchSKUContainer :global(.vtex-input),
.wishlistPrivacyOptionsContainer,
.wishlistSearchContainer :global(.vtex-input) {
  display: flex;
  align-items: center;
}

.wishlistSelector :global(.vtex-dropdown__container),
.wishlistPrivacyOptionsContainer :global(.vtex-dropdown__container) {
  height: 30px !important;
}

.wishlistSelector :global(.vtex-dropdown__button),
.wishlistPrivacyOptionsContainer :global(.vtex-dropdown__button),
.wishlistSearchSKUContainer :global(.vtex-input-prefix__group) {
  width: 400px !important;
  height: 30px !important;
  padding: 5px 0 8px 10px;
}

.wishlistSearchSKUContainer :global(.vtex-input-prefix__group) {
  padding: 0 !important;
}

.wishlistSearchContainer :global(.vtex-input-prefix__group) {
  width: 30%;
}

.wishlistSelector :global(.vtex-dropdown__label),
.wishlistSearchSKUContainer :global(.vtex-input__label),
.wishlistSearchContainer :global(.vtex-input__label),
.textContainerTitle {
  font-family: Roboto, HelveticaNeue, 'Helvetica Neue', sans-serif, Inter !important;
  font-weight: 700 !important;
  font-size: 16px;
  line-height: 30.26px !important;
  color: #7a8094 !important;
  width: fit-content !important;
  margin-right: 3em;
  width: 196.8px !important;
}

.wishlistSearchContainer :global(.vtex-input__label) {
  margin-right: 0;
}

.componentContainer {
  float: inline-start !important;
  width: 328px !important;
}

@media (max-width: 1290px) {
  .componentContainer {
    width: 100% !important;
  }
}

@media (max-width: 768px) {
  .componentContainer {
    max-width: 100%;
  }
}

.componentContainerHelper {
  padding-left: 0 !important;
  padding-right: 0 !important;
}

.componentContainerHelper {
  width: 100%;
  padding: 0 !important;
}

.addSkuContainer {
  display: flex;
  margin-top: 1rem;
}

.componentContainerHelper label div {
  border-top-right-radius: 0.25rem;
  border-bottom-right-radius: 0.25rem;
}

.componentContainerHelper :global(.vtex__icon-search) {
  color: #026 !important;
}
.textContainer {
  min-width: 150px;
  width: 150px;
  display: flex;
  align-items: center;
}

.textContainerTitle {
  width: fit-content !important;
  max-width: 196.8px !important;
  margin: 0;
  margin-top: 0;
}

.textContainerDescription {
  display: none;
}

.wishlistSearchContainer :global(.w-40) {
  display: flex;
  justify-content: flex-start;
  width: 100%;
}

.wishlistSearchContainer :global(.vtex-input__label) {
  width: 196.8px !important;
  max-width: 191px;
  margin-right: 1.75rem !important;
}

.wishlistOptionTexts {
  font-family: Roboto, HelveticaNeue, 'Helvetica Neue', sans-serif, Inter;
  font-weight: 700;
  font-size: 18px;
  line-height: 30.26px;
  color: #7a8094;
  margin-right: 3em;
  display: inline-block;
  width: 132px !important;
}

.wishlistCreationOptions {
  display: flex;
  justify-content: space-around;
  width: fit-content;
  margin-left: 1.5rem;
  align-items: center;
  width: 100%;
}
.wishlistCreateWishlistUI{
}
.wishlistCreateWishlistPageTitle {
}
.wishlistCreateNew,
.wishlistDelete,
.wishlistAddItem,
.wishlistRemoveItem {
  text-transform: capitalize;
  border-radius: 50px;
  border-color: transparent;
  font-weight: 700;
  cursor: pointer;
  padding: 3px;
  width: 140px;
}

.wishlistDeleteWishList {
  color: #ffffff;
  width: auto;
  border: none;
  background-color: red;
  cursor: pointer;
  margin-left: 1em;
  height: 2.375rem;
  border-radius: 50px;
  text-transform: capitalize;
  border-radius: 50px;
  border-color: transparent;
  font-weight: 700;
  padding: 12px;
}
.wishlistDeleteItem {
  color: rgb(71, 71, 71);
  width: 50px;
  border: none;
  background-color: #ffffff;
  cursor: pointer;
}

.wishlistAddItem {
  margin: 0 !important;
  width: 100px;
}

.wishlistRemoveItem {
  width: 150px;
}

.wishlistAddItem,
.wishlistDeleteItem {
  border-radius: 50px;
  width: 100px;
}

.wishlistCreateNew,
.wishlistAddItem {
  color: #ffffff;
  background-color: #002266;
}

.wishlistCreateNewHelper {
  margin-right: 5px;
}
.wishlistCreateNew {
  width: auto;
  height: 2.375rem;
}

.wishlistAddItem {
  margin-right: 3em;
}

.wishlistDelete,
.wishlistRemoveItem {
  color: #ffffff;
  background-color: #f60000;
}

.wishlistSearchSKU {
  height: 30px;
  width: 405px;
  border-radius: 10px;
  border: 1.8px solid #cacbcc;
  padding-left: 15px;
}
.wishlistSelectListTitle{}
.wishlistSelectListOne {
  cursor: pointer;
  width: 100%;
  height: 40px !important;
  padding: 5px 10px;
  border-width: 2px;
  border-style: solid;
  border-color: #e3e4e6;
  box-sizing: border-box;
  font-size: 16px;
  outline: none;
  color: #979899;
  border-radius: 0.25rem;
}

.wishlistSelectListOne .wishlistSelectListOneOption {
  cursor: pointer;
}
.wishlistSelectListOne:hover {
  border-color: #cacbcc;
}

.wishlistSelectListOneText {
  font-family: Roboto, HelveticaNeue, 'Helvetica Neue', sans-serif, Inter !important;
  font-weight: 700 !important;
  font-size: 18px;
  min-width: 150px !important;
  color: #7a8094;
}

.wishlistSelectListOneOption {
  color: black;
}

.MyWishListsPage {
  padding: 0 20px 0 20px;
  font-size: 12px;
  max-width: 1100px;
}

.wishlistCreateNew {
  padding: 10px;
}
.containerLinkShare {
  position: relative;
  margin: 0;
}

.image--copy {
  max-width: none;
}

.popupCopy {
  position: absolute;
  right: 0;
  top: 2rem;
  color: #fff;
  background-color: #264d9e;
  padding: 0.3rem;
}

.popupCopy::before {
  content: '';
  position: absolute;
  bottom: 100%;
  right: 20%;
  border-width: 5px;
  border-style: solid;
  border-color: transparent transparent #264d9e transparent;
}

.url--link {
  margin-right: 0.6rem;
}

.privacySettings :global(.vtex-styleguide-9-x-dropdown) {
  margin-left: 3.5em !important;
}

.wishlistSearchSKUContainer :global(.vtex-input-prefix__group) {
  margin-left: 3.5em;
  height: 40px !important;
  width: 303px !important;
}

.wishlistSearchContainer :global(.vtex-input-prefix__group) {
  width: 100%;
  margin-left: -2em;
  height: 2.375rem;
}

.wishlistSearchContainer :global(.w-40),
#toolbar {
  position: relative;
}

:global(#toolbar) {
  flex-direction: column !important;
}

.importList__generalContainer {
  margin: 24px 64px 64px;
}

.importList__buttonContainer {
  position: relative;
}

.importList__modalContainer {
  position: absolute;
  top: 0;
  right: -10px;
  transform: translateX(100%);
  z-index: 9;
}

.wishlistOptionsContainer {
  display: flex;
  align-items: center;
}

.wishlistSearchContainer :global(.vtex-input) {
  margin-top: 0;
}

.addSkuContainer .text-container {
  max-width: 140px;
}

/* Edit View button styles */
:global(#toggleFieldsBtn) {
  top: 3.15rem;
  border: 1px solid #e3e4e6;
  border-radius: 0.25rem;
  min-height: 28.09px !important;
  margin-left: 32rem;
  height: 1.875rem;
}

:global(.edit-view-text) {
  text-transform: capitalize;
  font-size: 14px;
  color: #9ba0ae;
  opacity: 1;
  position: relative;
  top: -1px;
  width: auto;
}

.createListandAndSelectFav {
  display: flex;
  width: 100%;
  column-gap: 2rem;
}

.nameAndOptionsMobile {
  display: flex;
  width: 100%;
  justify-content: space-between;
}

.optionsMobile {
  display: flex;
  column-gap: 1rem;
  align-items: center;
}

.quickOrderAutocompleteItemsWrapper {
  row-gap: 0.5rem;
  padding: .75rem;
}

.quickOrderAutocompleteItems {
  gap: 0.5rem;
}

.productThumb {
  min-width: 50px;
}

.productTitle {
  display: -webkit-box;
  max-width: 130px;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-wrap: wrap;
}

.productSku {
  flex-wrap: wrap;
  gap: 0.5rem;
}

.productLabel {
  width: 100%;
  justify-content: space-between;
}

.quickOrderAutocomplete {
  flex-direction: column;
  width: 100%;
  gap: 0.5rem;
}

.addToFavouritebutton {
  max-width: 7rem;
  height: 3rem;
}

.buttonClearWrapper {
  width: fit-content;
  padding-left: .5rem;
}

.buttonClear {
  width: fit-content;
}

.buttonClear :global(.vtex-button) {
  width: fit-content;
}

.buttonClear :global(.vtex-button__label) {
  padding: 0;
  width: fit-content;
}

@media screen and(min-width: 1300px) {
  .wishlistCreationOptions {
    margin-left: -4em;
  }
}
@media screen and (min-width: 1291px) {
  .wishlistSelectListOneText {
    width: unset !important;
    margin: 0;
  }

  .wishlistSelectListOne {
    width: 310px;
  }

  .wishlistCreationOptions {
    justify-content: flex-start;
    margin-left: -4em;
  }

  .wishlistCreateNewHelper {
    margin-right: 1em;
  }

  .componentContainerHelper {
    padding: 0 !important;
    width: 310px;
  }

  .textContainerTitle {
    margin-top: 0rem;
  }

  .wishlistSearchContainer :global(.vtex-input-prefix__group) {
    width: 310px;
  }
  .wishlistSearchContainer :global(.vtex-input__label) {
    margin-right: 0 !important;
    width: 174px !important;
    margin-bottom: 0;
  }
}
@media (max-width: 1024px) {
  .importList__generalContainer {
    margin: 24px 15px 30px;
  }
  .wishlistOptionsContainer {
    display: flex;
    flex-direction: column-reverse;
  }
  .componentContainer {
    /* margin-left: 1.8em; */
    width: 100% !important;
  }
  .wishlistCreationOptions {
    justify-content: flex-start;
    margin-left: 0;
  }
}

@media (max-width: 768px) {
  .wishlistDeleteWishList {
    margin-left: 0.5em;
    padding: 6px 5.3px 6px;
    font-size: 12.5px;
  }
  .wishlistSearchSKUContainer :global(.vtex-input),
  .wishlistPrivacyOptionsContainer,
  .wishlistSearchContainer :global(.vtex-input) {
    margin-bottom: 1em;
  }

  .wishlistCreationOptions {
    justify-content: space-between;
  }

  .textContainerTitle {
    margin-top: 0;
  }

  .componentContainerHelper {
    padding: 0 !important;
  }

  .wishlistSearchContainer :global(.vtex-input__label),
  .textContainer,
  .textContainerTitle,
  .wishlistSelectListOneText {
    width: 100% !important;
    max-width: 100% !important;
    margin: 0.5em 0;
  }

  .wishlistCreateNewHelper {
    margin-right: 4.5px;
  }

  .wishlistCreateNew {
    padding: 6px 5.3px 6px;
    font-size: 12.5px;
  }

  .wishlistOptionsContainer {
    display: flex;
    flex-direction: column-reverse;
  }
  .componentContainer {
    float: none !important;
    width: 100% !important;
    margin-left: 0 !important;
    padding-left: 0 !important;
  }

  .wishlistSearchContainer :global(.w-40),
  #toolbar {
    position: unset;
  }

  .wishlistSelector {
    flex-direction: column !important;
    align-items: flex-start;
  }

  .wishlistSelectListOne {
    width: 100% !important;
  }

  .wishlistCreationOptions {
    margin: 0;
  }

  .wishlistPrivacyOptionsContainer {
    height: max-content !important;
  }

  .containerLinkShare {
    padding: 0;
    margin: 0;
  }

  .url--link {
    margin-bottom: 0;
  }

  .wishlistOptionTexts {
    width: 100% !important;
    margin: 0;
  }

  .wishlistSearchSKUContainer :global(.vtex-input),
  .wishlistSearchContainer :global(.vtex-input),
  .privacySettings,
  .wishlistPrivacyOptionsContainer {
    display: flex !important;
    flex-direction: column !important;
    align-items: flex-start !important;
  }

  .wishlistSelector :global(.vtex-dropdown__button),
  .wishlistPrivacyOptionsContainer :global(.vtex-dropdown__button),
  .wishlistSearchSKUContainer :global(.vtex-input-prefix__group),
  .wishlistSearchContainer :global(.vtex-input__label),
  .privacySettings,
  .privacySettings :global(.vtex-dropdown__container),
  .wishlistSelector :global(.vtex-dropdown__button),
  .wishlistSearchContainer :global(.vtex-input-prefix__group),
  .wishlistPrivacyOptionsContainer :global(.vtex-dropdown) {
    width: 100% !important;
  }

  :global(.vtex-table__container) :global(#toggleFieldsBtn) {
    margin-top: 4.5rem;
    margin-right: 0;
    margin-left: 0;
  }

  :global(.vtex-table__container)
    :global(#toggleFieldsBtn)
    :global(.absolute)
    :global(.left-0)
    :global(.z-999)
    :global(.ba)
    :global(.b--muted-4)
    :global(.br2)
    :global(.mt2)
    :global(.mh2) {
    position: absolute !important;
    left: -22em !important;
  }

  .wishlistSearchContainer :global(.vtex-table__container) {
    margin-bottom: 2em;
  }

  .privacySettings :global(.vtex-styleguide-9-x-dropdown) {
    margin-left: initial !important;
  }

  .wishlistSearchSKUContainer :global(.vtex-input-prefix__group) {
    margin-left: initial;
    width: initial !important;
  }

  .wishlistSearchContainer :global(.vtex-input-prefix__group) {
    margin-left: initial;
  }

  :global(#toolbar) {
    position: relative;
  }
  :global(#toolbar) :global(.w-40) {
    position: absolute;
    width: 100%;
  }

  :global(#toolbar) :global(.flex.flex-row.items-center) {
    justify-content: flex-end;
  }

  .addSkuContainer {
    flex-direction: column;
  }
}

.absolute.br--bottom.br2.bb.bl.br.bw1.b--muted-2.bg-base.w-100.z-1.shadow-5 {
  z-index: 9999;
}

@media (max-width: 640px) {
  .importList__generalContainer {
    margin: 24px 12px 30px;
  }

  .importList__modalContainer {
    top: unset;
    right: unset;
    left: 0;
    bottom: -10px;
    transform: translateY(100%);
    z-index: 9;
  }

  .wishlistCreateNew,
  .wishlistDeleteWishList {
    height: 2rem;
    width: 4.5rem;
  }

  .wishlistName {
    margin-right: 0;
  }

  .wishlistSearchContainer :global(.vtex-input__label),
  .textContainerTitle,
  .wishlistSelectListOneText {
    font-size: 1.5625rem;
  }
}

@media (max-width: 380px) {
  :global(#toolbar) :global(.flex.flex-row.items-center) {
    margin-bottom: 2.5rem;
  }
  :global(#toggleFieldsBtn) {
    margin-top: 2rem !important;
  }
}

.wishlistSearchContainer {
  margin-top: 1rem;
}

.skuSelection,
.skuSelected {
  display: block;
}

.wishlistShare{
}

.wishlistProductImage{
  padding: 2px 0;
  max-width: 36px;
  object-fit: contain;
}

.wishlistShareTableCell,
.wishlistTableCell{
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
```


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

[User] Show me the implementation of wish-list-v2/react/global.css from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```css
.vtex-quickorder-2-x-inputQuantity>label>div>input {
  padding-left : 0;
  padding-right: 0;
  text-align   : center;
}

.vtex-button__label .c-on-base {
  display: none;
}

```


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

[User] Show me the implementation of wish-list-v2/react/WishlistShare.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
import WishlistShare from './components/WishlistShare'

export default WishlistShare

```


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

[User] Show me the implementation of wish-list-v2/react/package.json from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "my-wishlists",
  "version": "2.3.12",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "apollo-client": "^2.6.8",
    "axios": "^0.27.0",
    "react": "^16.12.0",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.12.0",
    "react-intl": "^3.12.0",
    "uuid": "^9.0.1",
    "zustand": "^4.4.3"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/lodash.debounce": "^4.0.9",
    "@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.apps-graphql": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.apps-graphql@3.17.4/public/@types/vtex.apps-graphql",
    "vtex.checkout-graphql": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-graphql@0.67.1/public/@types/vtex.checkout-graphql",
    "vtex.checkout-resources": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-resources@0.50.0/public/@types/vtex.checkout-resources",
    "vtex.css-handles": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@1.0.1/public/@types/vtex.css-handles",
    "vtex.my-account": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account@1.29.0/public/@types/vtex.my-account",
    "vtex.my-account-commons": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account-commons@1.7.2/public/@types/vtex.my-account-commons",
    "vtex.order-items": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-items@0.14.0/public/@types/vtex.order-items",
    "vtex.order-manager": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-manager@0.12.0/public/@types/vtex.order-manager",
    "vtex.pixel-manager": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.9.0/public/@types/vtex.pixel-manager",
    "vtex.product-context": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-context@0.10.1/public/@types/vtex.product-context",
    "vtex.quickorder": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.quickorder@3.16.0/public/@types/vtex.quickorder",
    "vtex.render-runtime": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.134.11/public/@types/vtex.render-runtime",
    "vtex.search-graphql": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-graphql@0.65.0/public/@types/vtex.search-graphql",
    "vtex.store": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.137.3/public/@types/vtex.store",
    "vtex.store-graphql": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.172.1/public/@types/vtex.store-graphql",
    "vtex.store-icons": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-icons@0.18.0/public/@types/vtex.store-icons",
    "vtex.store-resources": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-resources@0.101.0/public/@types/vtex.store-resources",
    "vtex.styleguide": "https://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.146.13/public/@types/vtex.styleguide"
  },
  "resolutions": {
    "@types/jest": "26.0.15"
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/ButtonWishlist.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import ButtonWishlist from './components/buttonWishlist/ButtonWishlist'

export default ButtonWishlist

```


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

[User] Show me the implementation of wish-list-v2/react/MyWishListsLink.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
import PropTypes from 'prop-types'
import { intlShape, injectIntl } from 'react-intl'

const MyWishListsLink = ({ render, intl }) => {
  return render([
    {
      name: intl.formatMessage({ id: 'Favorites Lists' }),
      path: '/my-wishlists',
    },
  ])
}

MyWishListsLink.propTypes = {
  render: PropTypes.func.isRequired,
  intl: intlShape.isRequired,
}

export default injectIntl(MyWishListsLink)

```


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

[User] Show me the implementation of wish-list-v2/store/interfaces.json from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "button-wishlist-pdp": {
    "component": "ButtonWishlist",
    "render": "client"
  },
  "my-account-link.my-wishlists-link": {
    "component": "MyWishListsLink"
  },
  "my-account-page.my-wishlists-page": {
    "component": "MyWishListsPage"
  },
  "wishlist-share": {
    "component": "WishlistShare"
  }
}

```


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

[User] Show me the implementation of wish-list-v2/store/plugins.json from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "my-account-pages > my-account-page": "my-account-page.my-wishlists-page",
  "my-account-menu > my-account-link": "my-account-link.my-wishlists-link"
}
```


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

[User] Show me the implementation of wish-list-v2/masterdata/myWishlist/schema.json from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "title": "wishlist",
  "type": "object",
  "properties": {
    "email": {
      "type": "string",
      "format": "email"
    },
    "wishlistType": {
      "type": "string"
    },
    "products": {
      "type": "array"
    },
    "isPublic": {
      "type": "boolean"
    },
    "fieldsConfig": {
      "type": "array"
    }
  },
  "required": ["email", "wishlistType", "products", "isPublic", "fieldsConfig"],
  "v-indexed": [
    "email",
    "wishlistType",
    "products",
    "isPublic",
    "fieldsConfig"
  ],
  "v-default-fields": [
    "email",
    "wishlistType",
    "products",
    "isPublic",
    "fieldsConfig"
  ],
  "v-cache": false,
  "v-immediate-indexing": 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 wish-list-v2/node/clients/masterdata.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { InstanceOptions, IOContext, RequestConfig } from '@vtex/api'
import { JanusClient } from '@vtex/api'

import { DATA_ENTITY_NAME, FIELDS, SCHEMA_NAME } from '../utils/constant'
import { Wishlist } from '../typings/wishlist'

export default class MasterDataClient extends JanusClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(context, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: context.authToken,
        Accept: 'application/vnd.vtex.pricing.v3+json',
        'Cache-Control': 'no-cache',
        'Content-Type': 'application/json',
      },
    })
  }

  public async getWishlist(id: string): Promise<Wishlist> {
    return this.http.get(
      `/api/dataentities/${DATA_ENTITY_NAME}/documents/${id}?_fields=${FIELDS}&_schema=${SCHEMA_NAME}`
    )
  }

  public async searchWistlist(
    field: string,
    value: string,
    pagination?: { page: number; pageSize: number }
  ): Promise<Wishlist[]> {
    const { page, pageSize } = pagination ?? {}

    return this.http.get(
      `/api/dataentities/${DATA_ENTITY_NAME}/search?_where=${field}="${value}" &_fields=${FIELDS}&_sort=createdIn&_schema=${SCHEMA_NAME}`,
      {
        headers: {
          'REST-Range': `resources=${page ?? 0}-${pageSize ?? 100}`,
        },
      }
    )
  }

  public async searchForExistingWishList(
    where: string,
    pagination?: { page: number; pageSize: number }
  ): Promise<Wishlist[] | null> {
    const { page, pageSize } = pagination ?? {}

    const config: RequestConfig = {
      headers: {
        'REST-Range': `resources=${page ?? 0}-${pageSize ?? 100}`,
      },
      retries: 1,
      initialBackoffDelay: 2000,
      exponentialBackoffCoefficient: 2,
      verbose: true,
    }

    try {
      return this.http.get(
        `/api/dataentities/${DATA_ENTITY_NAME}/search?_where=${where} &_fields=${FIELDS}&_sort=createdIn&_schema=${SCHEMA_NAME}`,
        config
      )
    } catch (err) {
      throw new Error(err)
    }
  }

  public async createWishlist(payload: Wishlist) {
    return this.http.post(
      `/api/dataentities/${DATA_ENTITY_NAME}/documents?_schema=${SCHEMA_NAME}`,
      payload
    )
  }

  public async updateWishlist(id: string, payload: Wishlist) {
    return this.http.patch(
      `/api/dataentities/${DATA_ENTITY_NAME}/documents/${id}?_schema=${SCHEMA_NAME}`,
      payload
    )
  }

  public async deleteWishlist(id: string) {
    return this.http.delete(
      `/api/dataentities/${DATA_ENTITY_NAME}/documents/${id}?_schema=${SCHEMA_NAME}`
    )
  }
}

```


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

[User] Show me the implementation of wish-list-v2/node/clients/vtexId.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { InstanceOptions, IOContext } from '@vtex/api'
import { JanusClient } from '@vtex/api'

interface AuthenticatedUser {
  userId: string
  user: string
}

export default class VtexId extends JanusClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(context, {
      ...options,
      headers: {
        VtexIdclientAutCookie: context.authToken,
        ...options?.headers,
        'x-vtex-user-agent': context.userAgent,
      },
    })
  }

  public async getAuthenticatedUser(
    authToken: string
  ): Promise<AuthenticatedUser> {
    return this.http.get('/api/vtexid/pub/authenticated/user/', {
      metric: 'authenticated-user-get',
      params: { authToken },
    })
  }
}

```


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

[User] Show me the implementation of wish-list-v2/node/clients/index.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { Wishlist } from '../typings/wishlist'
import MasterDataClient from './masterdata'
import VtexId from './vtexId'
import { DATA_ENTITY_NAME } from '../utils/constant'
import RequestHub from '../utils/HUB'

export class Clients extends IOClients {
  public get wishlist() {
    return this.getOrSet(
      'wishlist',
      masterDataFor<Wishlist>(DATA_ENTITY_NAME, undefined, 2)
    )
  }

  public get md() {
    return this.getOrSet('md', MasterDataClient)
  }

  public get vtexId() {
    return this.getOrSet('vtexId', VtexId)
  }

  public get hub() {
    return this.getOrSet('hub', RequestHub)
  }
}

```


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

[User] Show me the implementation of wish-list-v2/node/middleware/auth.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

export const auth = async (ctx: Context) => {
  const {
    cookies,
    clients: { vtexId },
  } = ctx

  let email = cookies.get('vtex-impersonated-customer-email') as string

  if (!email) {
    const cookie = cookies.get(
      `VtexIdclientAutCookie_${ctx.vtex.account}`
    ) as string

    if (!cookie) {
      throw new AuthenticationError('Unauthorized access')
    }

    const user = await vtexId.getAuthenticatedUser(cookie)

    if (!user?.userId) {
      throw new AuthenticationError('Unauthorized access')
    }

    email = user.user
  }

  return { email }
}

```


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

[User] Show me the implementation of wish-list-v2/node/middleware/configuration.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { DATA_ENTITY_NAME, SCHEMA, SCHEMA_NAME } from '../utils/constant'

const getAppId = (): string => {
  return process.env.VTEX_APP_ID ?? ''
}

const routes = {
  baseUrl: (account: string) =>
    `http://${account}.vtexcommercestable.com.br/api`,
  wishListEntity: (account: string, entity: string) =>
    `${routes.baseUrl(account)}/dataentities/${entity}`,
  saveSchema: (account: string, schema_version: string, entity: string) =>
    `${routes.wishListEntity(account, entity)}/schemas/${schema_version}`,
}

const defaultHeaders = (authToken: string) => ({
  'Content-Type': 'application/json',
  Accept: 'application/vnd.vtex.ds.v10+json',
  VtexIdclientAutCookie: authToken,
  'Proxy-Authorization': authToken,
})

const defaultSettings = {
  adminSetup: {
    storeLogoUrl: '',
    hasSchema: false,
    schemaVersion: null,
  },
}

export const configuration = async (ctx: Context) => {
  const {
    vtex: { account, authToken },
    clients: { hub },
  } = ctx

  const apps = new Apps(ctx.vtex)
  const app: string = getAppId()
  let settings = await apps.getAppSettings(app)

  if (!settings.adminSetup) {
    settings = defaultSettings
  }

  if (
    !settings.adminSetup.hasSchema ||
    settings.adminSetup.schemaVersion !== SCHEMA_NAME
  ) {
    try {
      const url = routes.saveSchema(account, SCHEMA_NAME, DATA_ENTITY_NAME)

      const headers = defaultHeaders(authToken)

      await hub.put(url, SCHEMA, headers)

      settings.adminSetup.hasSchema = true
      settings.adminSetup.schemaVersion = SCHEMA_NAME
    } catch (e) {
      if (e.response.status >= 400) {
        settings.adminSetup.hasSchema = false
      } else {
        settings.adminSetup.hasSchema = true
        settings.adminSetup.schemaVersion = SCHEMA_NAME
      }
    }
  }

  await apps.saveAppSettings(app, settings)

  return 'settings'
}

```


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

[User] Show me the implementation of wish-list-v2/node/typings/wishlist.d.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface Wishlist {
  id: string
  email: string
  wishlistType: string
  products: Products[]
  isPublic: boolean
  fieldsConfig?: FieldsConfig
}

export interface FieldsConfig {
  department: string
  description: string
}

export interface Products {
  ID: number
  Image: string
  unitValue: number
  linkProduct: string
  nameProduct: string
  quantityProduct: number
  skuCodeReference: string
  department: string
  bundle: number
  price: number
  notes: string
}

export interface WishlistUpdateArs extends Wishlist {
  id: string
  wishlist: Wishlist
}

export type WishlistInput = {
  wishlist: Wishlist
}

```


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

[User] Show me the implementation of wish-list-v2/node/utils/constant.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const FIELDS =
  'id,email,wishlistType,products,isPublic,fieldsConfig,createdIn'

export const DATA_ENTITY_NAME = 'myWishlists'

export const SCHEMA_NAME = '0.0.4-mywishlists'

export const SCHEMA = {
  properties: {
    email: {
      type: 'string',
      format: 'email',
    },
    wishlistType: {
      type: 'string',
    },
    products: {
      type: 'array',
    },
    isPublic: {
      type: 'boolean',
    },
    fieldsConfig: {
      type: 'array',
    },
  },
  required: ['email', 'wishlistType', 'products', 'isPublic'],
  'v-indexed': [
    'email',
    'wishlistType',
    'products',
    'isPublic',
    'fieldsConfig',
  ],
  'v-default-fields': [
    'email',
    'wishlistType',
    'products',
    'isPublic',
    'fieldsConfig',
  ],
  'v-cache': false,
  'v-immediate-indexing': true,
  'v-security': {
    allowGetAll: true,
    publicRead: [
      'id',
      'email',
      'wishlistType',
      'products',
      'isPublic',
      'fieldsConfig',
    ],
  },
}

```


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

[User] Show me the implementation of wish-list-v2/node/utils/HUB.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ExternalClient, InstanceOptions, IOContext } from '@vtex/api'

type Headers = {
  [key: string]: string
}

type Data = {
  [key: string]: unknown
}

export default class RequestHub extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(
      `http://${context.account}.vtexcommercestable.com.br/api/`,
      context,
      options
    )
  }

  public authToken() {
    return this.context.authToken
  }

  public account() {
    return this.context.account
  }

  public get(url: string, headers?: Headers, data?: Data) {
    return this.http.getRaw(url, {
      headers,
      data,
    })
  }

  public post(url: string, data: Data, headers?: Headers) {
    return this.http.postRaw(url, data, {
      headers,
    })
  }

  public put(url: string, data: Data, headers?: Headers) {
    return this.http.putRaw(url, data, {
      headers,
    })
  }

  public delete(url: string) {
    return this.http.delete(url)
  }
}

```


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

[User] Show me the implementation of wish-list-v2/node/resolvers/getWishlist.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { configuration } from '../middleware/configuration'

export const getWishlist = async (
  _: unknown,
  args: { id: string },
  ctx: Context
) => {
  const {
    clients: { md },
  } = ctx

  const { id } = args

  await configuration(ctx)

  return md.getWishlist(id)
}

```


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

[User] Show me the implementation of wish-list-v2/node/resolvers/getWishlistsByEmail.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { auth } from '../middleware/auth'
import { configuration } from '../middleware/configuration'

export const getWishlistsByEmail = async (
  _: unknown,
  args: {
    email: string
    page: number
    pageSize: number
  },
  ctx: Context
) => {
  const {
    clients: { md },
  } = ctx

  const { page, pageSize } = args

  const pagination = {
    page,
    pageSize,
  }

  await configuration(ctx)
  const { email } = await auth(ctx)

  const wishlists = await md.searchWistlist('email', email, pagination)

  return wishlists || 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 wish-list-v2/node/resolvers/deleteWishlist.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { auth } from '../middleware/auth'

export const deleteWishlist = async (
  _: unknown,
  args: { id: string },
  ctx: Context
) => {
  const {
    clients: { md },
  } = ctx

  const { id } = args

  const { email } = await auth(ctx)

  const getWishlist = await md.getWishlist(id)

  const existWishlist = getWishlist?.id

  if (!existWishlist) {
    throw new Error('An wishlist with this id does not exist')
  }

  if (getWishlist?.email !== email) {
    throw new AuthenticationError('Unauthorized access')
  }

  await md.deleteWishlist(id)

  return {
    id,
    success: 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 wish-list-v2/node/resolvers/createWishlist.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { WishlistInput } from '../typings/wishlist'
import { auth } from '../middleware/auth'

function hasSpecialCharacters(str: string) {
  const specialCharactersRegex = /[!@$%^*(),.?":{}|<>]/g

  return specialCharactersRegex.test(str)
}

export const createWishlist = async (
  _: unknown,
  args: WishlistInput,
  ctx: Context
) => {
  const {
    clients: { md },
  } = ctx

  const { wishlistType } = args?.wishlist || {}

  const { email } = await auth(ctx)

  if (hasSpecialCharacters(wishlistType)) {
    throw new Error(
      `An error occurred. No special characters are allowed in the name.`
    )
  }

  const foundWishlist = await md.searchForExistingWishList(
    `wishlistType = "${encodeURIComponent(wishlistType)}" AND email = ${email}`
  )

  const existWishlistName = foundWishlist && foundWishlist.length > 0

  if (existWishlistName) {
    throw new Error(`Already exist wishlist with name ${wishlistType}`)
  }

  const wishlist = {
    ...args?.wishlist,
    email,
  }

  return md.createWishlist(wishlist)
}

```


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

[User] Show me the implementation of wish-list-v2/node/resolvers/updateWishlist.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { auth } from '../middleware/auth'
import type { Products, WishlistUpdateArs } from '../typings/wishlist'

export const updateWishlist = async (
  _: unknown,
  args: WishlistUpdateArs,
  ctx: Context
) => {
  const {
    clients: { md },
  } = ctx

  const { email } = await auth(ctx)

  const { wishlist } = args || {}

  if (!wishlist?.id) {
    throw new Error('An id must be provided')
  }

  const { email: emailUser, id, wishlistType, isPublic, products } =
    (await md.getWishlist(wishlist.id)) || {}

  const existWishlist = id

  const data = wishlist?.products.map((prod) => {
    const d = products?.find((pro) => pro.ID === prod.ID)

    return {
      ...prod,
      quantityProduct: prod.quantityProduct
        ? prod.quantityProduct
        : d?.quantityProduct ?? 1,
      notes: prod.notes ? prod.notes : d?.notes,
    }
  })

  if (!existWishlist) {
    throw new Error('An wishlist with this id does not exist')
  }

  if (emailUser !== email) {
    throw new AuthenticationError('Unauthorized access')
  }

  const updatedWishlist = {
    id,
    email: wishlist?.email || emailUser,
    wishlistType: wishlist?.wishlistType || wishlistType,
    isPublic: wishlist?.isPublic || isPublic,
    products: data as Products[],
  }

  await md.updateWishlist(wishlist.id, updatedWishlist)

  return {
    id: wishlist.id,
    success: 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 wish-list-v2/node/resolvers/index.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { getWishlist } from './getWishlist'
import { getWishlistsByEmail } from './getWishlistsByEmail'
import { createWishlist } from './createWishlist'
import { updateWishlist } from './updateWishlist'
import { deleteWishlist } from './deleteWishlist'

export const mutations = {
  createWishlist,
  updateWishlist,
  deleteWishlist,
}

export const queries = {
  getWishlist,
  getWishlistsByEmail,
}

export const resolvers = {}

```


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

[User] Show me the implementation of wish-list-v2/react/context/ProductsContext.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useCallback, useEffect, useState } from 'react'

type ProductsContextType = {
  items: any[]
  setItems: React.Dispatch<React.SetStateAction<any[]>>
  updateItem: (item: any) => void
  getItem: (id: string) => any
  updateQuantityBySkuReferenceCode: (
    skuReferenceCode: string,
    quantity: number
  ) => void
}

const ProductsContext = React.createContext<ProductsContextType | undefined>(
  undefined
)

const ProductsProvider = ({
  children,
  items,
}: {
  children: React.ReactNode
  items: any[]
}) => {
  const [localItems, setLocalItems] = useState<any[]>([])

  const updateItem = useCallback(
    (item: any) => {
      const index = localItems.findIndex((i) => i.id === item.id)
      const newItems = [...localItems]

      newItems[index] = item
      setLocalItems(newItems)
    },
    [localItems, setLocalItems]
  )

  const getItem = useCallback(
    (id: string) => {
      return localItems.find((item) => item.itemId === id)
    },
    [localItems]
  )

  const updateQuantityBySkuReferenceCode = useCallback(
    (skuReferenceCode: string, quantity: number) => {
      const item = localItems.find(
        (local) => local.skuReferenceCode === skuReferenceCode
      )

      if (!item) {
        return
      }

      updateItem({ ...item, quantity })
    },
    [localItems, updateItem]
  )

  const value = React.useMemo(
    () => ({
      items: localItems,
      setItems: setLocalItems,
      updateItem,
      getItem,
      updateQuantityBySkuReferenceCode,
    }),
    [localItems, updateItem, getItem, updateQuantityBySkuReferenceCode]
  )

  useEffect(() => {
    setLocalItems(items)
  }, [items])

  return (
    <ProductsContext.Provider value={value}>
      {children}
    </ProductsContext.Provider>
  )
}

const useProducts = () => {
  const context = React.useContext(ProductsContext)

  if (!context) {
    throw new Error('useProducts must be used within a ProductsProvider')
  }

  return context
}

export { ProductsProvider, useProducts }

```


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

[User] Show me the implementation of wish-list-v2/react/context/RowContext.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { useProducts } from './ProductsContext'

type RowContextType = {
  row: any
  updateQuantity: (quantity: number) => void
}
const RowContext = React.createContext<RowContextType | null>(null)

const RowProvider = ({
  children,
  row: rowData,
}: {
  children: React.ReactNode
  row: any
}) => {
  const { getItem } = useProducts()
  const row = getItem(rowData.itemId)
  const [localRow, setLocalRow] = useState<any>(row)

  const updateQuantity = useCallback(
    (quantity: number) => {
      setLocalRow({ ...localRow, quantity })
    },
    [localRow]
  )

  useEffect(() => {
    setLocalRow(row)
  }, [row])

  const value = useMemo(() => ({ row: localRow, updateQuantity }), [
    localRow,
    updateQuantity,
  ])

  return <RowContext.Provider value={value}>{children}</RowContext.Provider>
}

const useRow = () => {
  const context = React.useContext(RowContext)

  if (!context) {
    throw new Error('useRow must be used within a RowProvider')
  }

  return context
}

export { RowProvider, useRow }

```


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

[User] Show me the implementation of wish-list-v2/react/mutation/createWishList.gql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation CreateWishList($wishList: WishlistInput!) {
  createWishlist(wishlist: $wishList) {
    Id
    Href
    DocumentId
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/mutation/removeWishList.gql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation RemoveWishList($id: ID!) {
  deleteWishlist(id: $id) {
    id
    success
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/typings/vtex.product-context.d.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.product-context/useProduct' {
  const useProduct: () => ProductContext
  export default useProduct
}

declare module 'vtex.product-context' {
  export interface ProductContext {
    selectedQuantity: number
    selectedItem?: SelectedItem
  }

  interface SelectedItem {
    itemId: string
    unitMultiplier: number
    measurementUnit: string
    sellers: Array<{
      commertialOffer: {
        AvailableQuantity: number
      }
      sellerDefault: boolean
    }>
  }

  const useProduct: () => ProductContext
  export default useProduct
}

declare module 'vtex.product-context/ProductDispatchContext' {
  type DispatchFunction = (payload: { type: string; args?: unknown }) => void
  export const useProductDispatch: () => DispatchFunction
}

```


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

[User] Show me the implementation of wish-list-v2/react/typings/gql.d.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

  const Schema: DocumentNode

  export default Schema
}

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

  const schema: DocumentNode

  export default schema
}

```


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

[User] Show me the implementation of wish-list-v2/react/typings/css.d.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

  const styles: Styles
  const css: any

  export default styles
}

```


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

[User] Show me the implementation of wish-list-v2/react/typings/vtex.styleguid.d.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.styleguide' {
  export const Button
  export const Input
  export const Tooltip
  export const NumericStepper
  export const Checkbox
  export const Spinner
  export const Modal
  export const ToastContext
  export const ToastProvider
  export const ToastConsumer
  export const AutocompleteInput
  export const Tag
  export const IconClear
  export const Table
  export const withToast
  export const IconDelete
  export const Layout
  export const PageHeader

  interface InputProps {
    [key: string]: any
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/queries/product.gql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
query Product($slug: String) {
  product(slug: $slug) @context(provider: "vtex.search-graphql") {
    properties {
      name
      values
    }
    productName
    description
    link
    priceRange {
      sellingPrice {
        highPrice
      }
    }
    items {
      itemId
      name
      unitMultiplier
      sellers {
        sellerId
        sellerName
        sellerDefault
      }
      referenceId {
        Key
        Value
      }
      images {
        imageUrl
      }
    }
    categoryTree {
      name
    }
    skuSpecifications {
      field {
        name
      }
      values {
        name
      }
    }
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/queries/getWishListsByEmail.gql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
query GetWishListByEmail {
  getWishlistsByEmail {
    id
    email
    wishlistType
    products {
      ID
      Image
      linkProduct
      nameProduct
      quantityProduct
      skuCodeReference
      department
      bundle
      notes
    }
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/queries/autocomplete.gql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
query Autocomplete($inputValue: String!) {
  productSuggestions(fullText: $inputValue, hideUnavailableItems: true)
    @context(provider: "vtex.search-graphql") {
    products {
      items {
        itemId
        name
        images {
          imageUrl
        }
      }
      link
      linkText
      productName
    }
  }
}

```


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

[User] Show me the implementation of wish-list-v2/react/queries/AppSettings.graphql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getSettings {
  publicSettingsForApp(app: "vtex.my-wishlists", version: "2.x")
    @context(provider: "vtex.apps-graphql") {
    message
  }
}
```


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

[User] Show me the implementation of wish-list-v2/react/utils/copyToClipboard.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
export default function copyToClipboard(link, setTextCopied) {
  // Create a hidden textarea element to copy the text
  const textarea = document.createElement('textarea')

  textarea.value = link // Use the link passed as an argument
  document.body.appendChild(textarea)
  textarea.select()
  textarea.setSelectionRange(0, 99999)
  document.execCommand('copy')
  document.body.removeChild(textarea)
  setTextCopied(true)
  setTimeout(() => {
    setTextCopied(false)
  }, 2000)
}

```


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

[User] Show me the implementation of wish-list-v2/react/utils/jsonSchema.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable no-console */
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'
import { IconDelete } from 'vtex.styleguide'

import Notes from '../components/Notes'
import ProductPriceTotal from '../components/ProductPriceTotal'
import { ProductStepper } from '../components/ProductQuantity'
import UnitPrice from '../components/UnitPrice'
import styles from '../styles.css'
// import ProductDescription from '../components/ProductDescription'
import SkuName from '../components/SkuName'
import { RowProvider } from '../context/RowContext'
import { AdminSettings } from '../interfaces'
import { removePrefixRegex } from './stringUtils'

interface CellProps {
  title: string
  width?: number
  active?: boolean
  sortable?: boolean
  cellRenderer: (value: any, rowData: any) => JSX.Element // Tipo genérico para a função de renderização
}

interface IJsonSchema {
  properties: {
    image: CellProps
    skuName: CellProps
    department: CellProps
    skuReferenceCode: CellProps
    quantity: CellProps
    unitValue: CellProps
    totalValue: CellProps
    notes: CellProps
    add: CellProps
    remove: CellProps
  }
}

export const getProductPath = (rowData: any) => {
  const isFastStore = (window?.location?.hostname ?? '').startsWith('secure')

  const linkUrl = rowData.linkProduct || ''
  const parts = linkUrl.split('.br/')
  const id = rowData.itemId || rowData.ID

  // eslint-disable-next-line prefer-destructuring
  const productSlug = parts[parts.length - 1]?.split('/')?.[0] ?? ''
  const productPath = isFastStore ? `${productSlug}-${id}` : productSlug

  const hostUrl = removePrefixRegex(window.location.host ?? '', 'secure.')
  const newBaseUrl = `https://${hostUrl}`

  return `${newBaseUrl}/${productPath}/p`
}

const WrapperProductStepper = ({ selectedWishlist, wishlists }) => {
  const currentWishlist =
    selectedWishlist !== null
      ? wishlists.find((wish) => wish.id === selectedWishlist)
      : wishlists[0]

  return <ProductStepper wishlist={currentWishlist} />
}

export const JsonSchema = ({
  addProductsToCart,
  deleteItemsWishlist,
  selectedWishlist,
  wishlist,
  wishlists,
  updateWishlist,
  wishlistColumns,
}) => {
  const runtime = useRuntime()
  const { culture } = runtime
  const currency = culture.customCurrencySymbol

  const imageCellRenderer = ({ cellData, rowData }) => {
    const productUrl = getProductPath(rowData)

    return (
      <a
        href={productUrl || ''}
        target="_blank"
        rel="noreferrer"
        className={styles.wishlistTableCell}
      >
        <img
          src={cellData || rowData.Image || ''}
          alt={rowData.name || ''}
          className={styles.wishlistProductImage}
        />
      </a>
    )
  }

  const departmentCellRenderer = ({ cellData, rowData }) => {
    return (
      <p className={styles.wishlistProductDepartment}>
        {cellData || rowData.department || ''}
      </p>
    )
  }

  const skuReferenceCodeCellRenderer = ({ cellData, rowData }) => {
    const productUrl = getProductPath(rowData)

    return (
      <a
        href={productUrl || ''}
        className={styles.wishlistProductTexts}
        target="_blank"
        rel="noreferrer"
      >
        {cellData || rowData.skuCodeReference || ''}
      </a>
    )
  }

  // const nameCellRenderer = ({ rowData }) => {
  //   const linkUrl = rowData.linkProduct || ''
  //   const parts = linkUrl.split('.br/')
  //   const productUrl = `${window.location.origin}/${parts[parts.length - 1]}`

  //   return (
  //     <ProductDescription itemId={rowData.itemId} productUrl={productUrl} />
  //   )
  // }

  const qtyCellRenderer = ({ rowData }) => {
    return (
      <RowProvider row={rowData}>
        <div className={styles.wishlistTableCell}>
          <WrapperProductStepper
            selectedWishlist={selectedWishlist}
            wishlists={wishlists}
          />
        </div>
      </RowProvider>
    )
  }

  const unitValueCellRenderer = ({ rowData }) => {
    return (
      <UnitPrice
        itemId={rowData.itemId}
        skuReference={rowData?.skuReferenceCode}
        currency={currency}
      />
    )
  }

  const addToCartCellRenderer = ({ rowData }) => {
    return (
      <button
        className={styles.wishlistAddItem}
        onClick={() => addProductsToCart(rowData, wishlist || {})}
      >
        Add
      </button>
    )
  }

  const removeCellRenderer = (rowData) => {
    return (
      <button
        className={styles.wishlistDeleteItem}
        onClick={async () => {
          deleteItemsWishlist({
            row: rowData,
            wishlist,
            selectedWishlist,
            updateWishlist,
          })
        }}
      >
        <IconDelete />
      </button>
    )
  }

  const priceCellRenderer = ({ rowData }) => {
    return (
      <ProductPriceTotal
        itemId={rowData.itemId}
        productQuantity={rowData?.quantity}
        currency={currency}
      />
    )
  }

  const notesCellRenderer = ({ rowData }) => {
    return (
      <Notes
        wishlist={selectedWishlist !== null ? wishlist : wishlists[0]}
        updateWishlist={updateWishlist}
        skuReference={rowData?.skuReferenceCode}
        currentNotes={rowData?.notes}
        productName={rowData?.name || ''}
        productImage={rowData?.image || ''}
        partNumber={rowData?.skuReferenceCode || ''}
        currency={currency}
        itemId={rowData?.itemId}
        quantity={rowData?.quantity}
      />
    )
  }

  const skuNameCellRenderer = ({ rowData }) => {
    const productUrl = getProductPath(rowData)

    return <SkuName itemId={rowData.itemId} productUrl={productUrl} />
  }

  const jsonschema: IJsonSchema = {
    properties: {
      image: {
        title: 'Image',
        // width: undefined,
        active: true,
        cellRenderer: imageCellRenderer,
      },
      skuName: {
        title: 'Name',
        // width: undefined,
        active: true,
        cellRenderer: skuNameCellRenderer,
      },
      department: {
        sortable: true,
        title: 'Department',
        // width: undefined,
        active: true,
        cellRenderer: departmentCellRenderer,
      },
      skuReferenceCode: {
        title: 'Part #',
        // width: undefined,
        active: true,
        cellRenderer: skuReferenceCodeCellRenderer,
      },
      // description: {
      //   sortable: true,
      //   title: 'Description',
      //   width: 220,
      //   name: '',
      //   cellRenderer: nameCellRenderer,
      // },
      quantity: {
        title: 'Qty',
        // width: undefined,
        cellRenderer: qtyCellRenderer,
      },
      unitValue: {
        title: 'Unit Value',
        // width: undefined,
        cellRenderer: unitValueCellRenderer,
      },
      totalValue: {
        title: 'Price',
        // width: undefined,
        cellRenderer: priceCellRenderer,
      },
      notes: {
        title: 'Notes',
        // width: undefined,
        cellRenderer: notesCellRenderer,
      },
      add: {
        title: 'Add',
        // width: undefined,
        cellRenderer: addToCartCellRenderer,
      },
      remove: {
        title: 'Remove',
        // width: undefined,
        cellRenderer: removeCellRenderer,
      },
    },
  }

  if (!wishlistColumns?.publicSettingsForApp?.message) return jsonschema
  const wishlistColumnsSettings: AdminSettings = JSON.parse(
    wishlistColumns.publicSettingsForApp.message
  )

  jsonschema.properties.image.title = wishlistColumnsSettings.imageName
  jsonschema.properties.image.width = wishlistColumnsSettings.imageRowWidth
  jsonschema.properties.skuName.title = wishlistColumnsSettings.skuNameTitle
  jsonschema.properties.skuName.width =
    wishlistColumnsSettings.skuNameRowWidthAccount
  jsonschema.properties.department.title =
    wishlistColumnsSettings.departmentTitle
  jsonschema.properties.department.width =
    wishlistColumnsSettings.departmentRowWidth
  jsonschema.properties.skuReferenceCode.title =
    wishlistColumnsSettings.skuReferenceCodeTitle
  jsonschema.properties.skuReferenceCode.width =
    wishlistColumnsSettings.skuReferenceCodeRowWidth
  jsonschema.properties.quantity.title = wishlistColumnsSettings.quantityTitle
  jsonschema.properties.quantity.width =
    wishlistColumnsSettings.quantityRowWidth
  jsonschema.properties.unitValue.title = wishlistColumnsSettings.unitValueTitle
  jsonschema.properties.unitValue.width =
    wishlistColumnsSettings.unitValueRowWidth
  jsonschema.properties.totalValue.title =
    wishlistColumnsSettings.totalValueTitle
  jsonschema.properties.totalValue.width =
    wishlistColumnsSettings.totalValueRowWidth
  jsonschema.properties.add.title = wishlistColumnsSettings.addTitle
  jsonschema.properties.add.width = wishlistColumnsSettings.addRowWidth
  jsonschema.properties.remove.title = wishlistColumnsSettings.removeTitle

  for (const [key, value] of Object.entries(wishlistColumnsSettings)) {
    if (!value) {
      delete jsonschema.properties[key]
    }
  }

  return jsonschema
}

```


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

[User] Show me the implementation of wish-list-v2/react/utils/tableRowsSchema.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
const tableRowsSchema = {
  items: [
    {
      image: '',
      department: '',
      skuReferenceCode: '',
      name: '',
      qty: '',
      unitValue: '',
      totalValue: '',
    },
  ],
}

const tableLength = 5

export const initialJsonState = {
  slicedData: tableRowsSchema.items.slice(0, tableLength),
  searchValue: '',
  emptyStateLabel: 'Nothing to show.',
  filterStatements: ['Ascending', 'Descending'],
}

```


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

[User] Show me the implementation of wish-list-v2/react/utils/stringUtils.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const removePrefixRegex = (str, prefix) => {
  return str.replace(new RegExp(`^${prefix}`), '')
}

```


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

[User] Show me the implementation of wish-list-v2/react/utils/handleDataLayerEvent.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
const handleDataLayerEvent = (eventName: string, eventData: unknown[]) => {
  if (typeof window !== 'undefined') {
    ;(window.dataLayer ?? []).push({
      event: eventName,
      items: eventData,
    })
  }
}

export default handleDataLayerEvent

```


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

[User] Show me the implementation of wish-list-v2/react/components/WishlistDesktop.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useContext } from 'react'
import { ToastContext, ModalDialog } from 'vtex.styleguide'

import EditableWishlistTitle from './WishlistName/WishlistName'
import ModalCreateList from './ModalCreateList'
import WishlistPrivacyOptions from './WishlistPrivacyOptions'
import styles from '../styles.css'

const WishlistDesktop = ({
  selectedWishlist,
  wishlists,
  wishlist,
  fetchData,
  handleSelectWishlist,
  emailIDInfo,
  buttonModalTable,
  isModalAccountTable,
  handleSubmitDataTable,
  createWishlist,
  setFieldValidationTable,
  nameListAccountTable,
  setNameListAccountTable,
  setIsModalAccountTable,
  deleteWishlist,
  buttonCloseModalTable,
  handleNameListTable,
  fieldValidationTable,
  isDeleting,
}) => {
  const [isCreateLoading, setIsCreateLoading] = useState(false)
  const [isDeleteLoading, setIsDeleteLoading] = useState(false)
  const [isModalOpen, setIsModalOpen] = useState(false)
  const { showToast } = useContext<any>(ToastContext)

  const onCreateList = async (event) => {
    setIsCreateLoading(true)
    try {
      await handleSubmitDataTable({
        event,
        createWishlist,
        setFieldValidationTable,
        nameListAccountTable,
        setNameListAccountTable,
        setIsModalAccountTable,
      })
      showToast('You created a new Wishlist')
      setIsCreateLoading(false)
    } catch (error) {
      showToast({
        message:
          error?.message?.replace('GraphQL error: ', '') ??
          `An error occurred. Make sure there isn't a wishlist with the same name.`,
        status: 'ERROR',
      })

      console.error(error)
      await fetchData()
      setIsCreateLoading(false)
    }
  }

  const onDeleteList = async () => {
    setIsDeleteLoading(true)
    try {
      await deleteWishlist()
      setIsDeleteLoading(false)
      if (wishlists.length === 1) {
        window.location.reload()
      }
      closeModal()
    } catch (error) {
      console.error(error)
      await fetchData()
      setIsDeleteLoading(false)
      closeModal()
    }
  }

  const closeModal = () => {
    setIsModalOpen(false)
  }

  const openModal = () => {
    setIsModalOpen(true)
  }

  return (
    <div id="wish-list-desktop">
      <ModalDialog
        centered
        loading={isDeleteLoading}
        confirmation={{
          onClick: onDeleteList,
          label: 'Yes',
          isDangerous: true,
          testId: 'deleteConfirmBtn',
        }}
        cancelation={{
          onClick: closeModal,
          label: 'Cancel',
        }}
        isOpen={isModalOpen}
        onClose={closeModal}
      >
        <div className="">
          <p className="f3 f3-ns fw3 gray">
            Are you sure you want to delete your wishlist{' '}
            {emailIDInfo.find((list) => list.value === selectedWishlist)?.label}{' '}
            ?
          </p>
          <p>This action is irreversible.</p>
        </div>
      </ModalDialog>

      <EditableWishlistTitle
        initialTitle={selectedWishlist !== null ? wishlist.wishlistType : ''}
        wishlistId={
          selectedWishlist !== null ? selectedWishlist : wishlists[0].id
        }
        wishlist={selectedWishlist !== null ? wishlist : wishlists[0]}
        fetchData={fetchData}
      />

      <div className={styles.wishlistOptionsContainer}>
        <div className={styles.wishlistSelector}>
          <p className={styles.wishlistSelectListOneText}>Favorites List</p>
          <select
            className={styles.wishlistSelectListOne}
            id="selectListTable"
            onChange={(e) => {
              handleSelectWishlist(e.target.value)
            }}
            size={1}
            value={selectedWishlist}
          >
            <option value="" disabled selected>
              Select an option
            </option>
            {emailIDInfo.map((newDates) => (
              <option
                className={styles.wishlistSelectListOneOption}
                value={newDates.value}
                key={newDates.value}
                id={newDates.value}
              >
                {newDates.label}
              </option>
            ))}
          </select>
        </div>
        <section className={`${styles.wishlistCreationOptions} relative`}>
          <button
            className={`${styles.wishlistCreateNew} ${styles.wishlistCreateNewHelper}`}
            onClick={buttonModalTable}
          >
            Create New List
          </button>
          {isModalAccountTable && (
            <ModalCreateList
              buttonCloseModal={buttonCloseModalTable}
              handleNameList={handleNameListTable}
              fieldValidation={fieldValidationTable}
              handleSubmitData={onCreateList}
              isButtonLoading={isCreateLoading}
              blockClass="vtex-create-wishlist-desktop"
            />
          )}
          <WishlistPrivacyOptions
            selectedWishlist={
              selectedWishlist !== null ? selectedWishlist : wishlists[0].id
            }
            wishlists={wishlists}
            buttonLabel="Share This List"
          />
          <button
            className={styles.wishlistDeleteWishList}
            onClick={openModal}
            disabled={isDeleteLoading}
          >
            {isDeleting ? `Deleting...` : `Delete Selected List`}
          </button>
        </section>
      </div>
    </div>
  )
}

export default WishlistDesktop

```


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

[User] Show me the implementation of wish-list-v2/react/components/MyWishLists.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
// Hooks
import React, { useEffect, useState } from 'react'
import { Spinner, Button } from 'vtex.styleguide'
import { useMutation } from 'react-apollo'

import useCreateListAccount from '../hooks/useCreateListAccount'
// Global Store
import useStoreGlobal from '../globalStore/globalStore'
// Components
import Wishlist from './Wishlist'
import ModalCreateList from './ModalCreateList'
// Helpers
import useQueryWishlists from '../hooks/actions/useQueryWishlists'
// Styles
import styles from '../styles.css'
// GQL
import CREATE_WISHLIST from '../mutation/createWishList.gql'

const MyWishLists = () => {
  const [isLoading, setIsLoading] = useState(false)
  const [isLoadingPage, setIsLoadingPage] = useState(false)
  const [errorMessage, setErrorMessage] = useState<string | null>(null)
  const { setSelectedWishlist, selectedWishlist } = useStoreGlobal()
  const setWishlists = useStoreGlobal((state) => state.setWishlists)
  const wishlists = useStoreGlobal((state) => state.wishlists)

  const { data, loading, refetch, error } = useQueryWishlists()

  const [createNewListMutaion] = useMutation(CREATE_WISHLIST, {})

  const {
    isModalAccount,
    nameListAccount,
    fieldValidation,
    setNameListAccount,
    setFieldValidation,
    setIsModalAccount,
    buttonModal,
    buttonCloseModal,
    handleNameList,
  } = useCreateListAccount()

  useEffect(() => {
    if (data?.getWishlistsByEmail) {
      if (data.getWishlistsByEmail.length > 0) {
        setWishlists(data.getWishlistsByEmail)
        if (!selectedWishlist) {
          setSelectedWishlist(data.getWishlistsByEmail[0].id)
        }
      } else {
        setWishlists([])
      }
    }

    if (error) {
      setErrorMessage(error.message)
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data, error])

  useEffect(() => {
    wishlists && setIsLoadingPage(loading)
  }, [loading, wishlists])

  // Create list post
  const handleSubmitData = (event: { preventDefault: () => void }) => {
    event.preventDefault()

    if (nameListAccount.trim() === '') {
      setFieldValidation('The field cannot be empty')
    } else {
      setIsLoading(true)
      createNewListMutaion({
        variables: {
          wishList: {
            wishlistType: nameListAccount,
            products: [],
            isPublic: false,
          },
        },
      })
        .then(refetch)
        .then(() => {
          setNameListAccount('')
          setFieldValidation('')
          setIsModalAccount(false)
          setIsLoading(false)
        })
        .catch((errorSubmit) => {
          console.error(errorSubmit)
          setNameListAccount('')
          setFieldValidation('')
          setIsModalAccount(false)
          setIsLoading(false)
        })
    }
  }

  const handleCloseButton = (event: { preventDefault: () => void }) => {
    event.preventDefault()
    buttonCloseModal()
  }

  if (errorMessage)
    return (
      <p className={styles.errorMessage}>
        Your wishlist failed to load, please refresh the page.
      </p>
    )

  if (isLoadingPage) return <Spinner />

  if (wishlists.length === 0) {
    return (
      <section className={styles.wishlistCreateWishlistUI}>
        <Button href="/account">RETURN</Button>
        <h1 className={styles.wishlistCreateWishlistPageTitle}>
          Create your wishlist!
        </h1>
        <button className={styles.wishlistCreateNew} onClick={buttonModal}>
          New Wishlist
        </button>
        {isModalAccount && (
          <ModalCreateList
            buttonCloseModal={handleCloseButton}
            handleNameList={handleNameList}
            fieldValidation={fieldValidation}
            handleSubmitData={handleSubmitData}
            blockClass="vtex-create-wishlist-main"
            isButtonLoading={isLoading}
          />
        )}
      </section>
    )
  }

  return <Wishlist wishlists={wishlists} fetchData={refetch} />
}

export default MyWishLists

```


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

[User] Show me the implementation of wish-list-v2/react/components/ProductDescription.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Spinner } from 'vtex.styleguide'

import useQueryProductByIdentifier from '../hooks/actions/useQueryProductByIdentifier'
import styles from './unitPrice.css'

interface Props {
  itemId: number
  productUrl: string
}

const ProductDescription = ({ itemId, productUrl }: Props) => {
  const {
    getProperty,
    error: productError,
    loading,
  } = useQueryProductByIdentifier('sku', itemId)

  const Wrapper = ({ children }) => {
    return <div className={`${styles.descriptionContainer}`}>{children}</div>
  }

  return productError ? (
    <Wrapper>
      <span>Error</span>
    </Wrapper>
  ) : loading ? (
    <Wrapper>
      <Spinner size={20} />
    </Wrapper>
  ) : (
    <Wrapper>
      <a
        href={productUrl || ''}
        className={styles.wishlistProductTexts}
        target="_blank"
        rel="noreferrer"
      >
        {getProperty('productDescription')}
      </a>
    </Wrapper>
  )
}

export default ProductDescription

```


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

[User] Show me the implementation of wish-list-v2/react/components/UnitPrice.jsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```jsx
import React from 'react'
import { Spinner } from 'vtex.styleguide'

import useQueryGetProductPrice from '../hooks/actions/useQueryGetProductPrice'
import styles from './unitPrice.css'

const UnitPrice = ({ currency = '$', itemId }) => {
  const { price, error: productError, loading } = useQueryGetProductPrice(
    'sku',
    itemId,
    1
  )

  const Wrapper = ({ children }) => {
    return <div className={`${styles.unitPriceContainer}`}>{children}</div>
  }

  return productError ? (
    <Wrapper>
      <span>Error</span>
    </Wrapper>
  ) : loading ? (
    <Wrapper>
      <Spinner size={20} />
    </Wrapper>
  ) : (
    <Wrapper>
      {`${currency} ${price ? parseFloat(price).toFixed(2) : null}`}
    </Wrapper>
  )
}

export default UnitPrice

```


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

[User] Show me the implementation of wish-list-v2/react/components/SkuName.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Spinner } from 'vtex.styleguide'

import useQueryProductByIdentifier from '../hooks/actions/useQueryProductByIdentifier'
import styles from './unitPrice.css'

interface Props {
  itemId: number
  productUrl: string
}

const SkuName = ({ itemId, productUrl }: Props) => {
  const {
    getProperty,
    error: productError,
    loading,
  } = useQueryProductByIdentifier('sku', itemId)

  const Wrapper = ({ children }) => {
    return <div className={`${styles.skuNameContainer}`}>{children}</div>
  }

  return productError ? (
    <Wrapper>
      <span>Error</span>
    </Wrapper>
  ) : loading ? (
    <Wrapper>
      <Spinner size={20} />
    </Wrapper>
  ) : (
    <Wrapper>
      <a
        href={productUrl || ''}
        className={styles.wishlistProductTexts}
        target="_blank"
        rel="noreferrer"
      >
        {getProperty('productNameWithSkuName')}
      </a>
    </Wrapper>
  )
}

export default SkuName

```