[System] You are an expert VTEX IO developer. You specialize 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/Wishlist.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
// Hooks
import React, { useCallback, useContext, useEffect, useState } from 'react'
import { useRuntime } from 'vtex.render-runtime'
import { Table, ToastContext } from 'vtex.styleguide'
// Components
import { useQuery } from 'react-apollo'

import useCreateListAccount from '../hooks/useCreateListAccount'
import AutocompleteBlock from './SearchSKU/AutocompleteBlock'
// Helpers & Utils
import useStoreGlobal from '../globalStore/globalStore'
import useCreateWishlist from '../hooks/actions/useMutationCreateWishlist'
import useDeleteWishlist from '../hooks/actions/useMutationDeleteWishlist'
import useUpdateWishlist from '../hooks/actions/useMutationUpdateWishlist'
import useQueryWishlistById from '../hooks/actions/useQueryWishlistById'
import useAddToCart from '../hooks/useAddToCart'
import useBulkAction from '../hooks/useBulkAction'
import AppSettings from '../queries/AppSettings.graphql'
import { JsonSchema } from '../utils/jsonSchema'
import { deleteItemsWishlist, extractProductData, getEmailID } from './helpers'
// Table config
import { initialJsonState } from '../utils/tableRowsSchema'
import {
  handleFiltersChange,
  handleNextClick,
  handlePrevClick,
  handleSubmitDataTable,
  SelectorObject,
} from './helpers/tableConfig'
import {
  handleInputSearchChange,
  handleInputSearchClear,
  handleInputSearchSubmit,
} from './helpers/tableSearch'
import WishlistDesktop from './WishlistDesktop'
import WishlistMobile from './WishlistMobile'
// Styles
import { ProductsProvider } from '../context/ProductsContext'
import styles from '../styles.css'

interface TablePaginationWrapperProps {
  tableSchema: any
  toolbar: any
  bulkActions: any
  pagination: any
  filters: any
  items: any
}

const TablePaginationWrapper = React.memo<TablePaginationWrapperProps>(
  ({
    tableSchema,
    toolbar,
    bulkActions,
    pagination,
    filters,
    items,
  }: TablePaginationWrapperProps) => {
    return (
      <Table
        fullWidth
        density="medium"
        updateTableKey={`vtex-table=${Math.floor(Math.random() * 1000)}`}
        schema={tableSchema}
        items={items}
        toolbar={toolbar}
        bulkActions={bulkActions}
        pagination={pagination}
        filters={filters}
      />
    )
  },
  (prevProps, nextProps) => {
    return prevProps.items.length === nextProps.items.length
  }
)

TablePaginationWrapper.displayName = 'TablePaginationWrapper'

function Wishlist({ wishlists, fetchData }) {
  const { deviceInfo } = useRuntime()
  const emailIDInfo = getEmailID(wishlists)
  const { selectedWishlist, setSelectedWishlist } = useStoreGlobal()
  const { showToast } = useContext<any>(ToastContext)
  const [filterState, setfilterState] = useState<any>([])

  const { data: wishlistColumns } = useQuery(AppSettings, {
    variables: {
      // eslint-disable-next-line no-undef
      version: process.env.VTEX_APP_VERSION,
    },
    ssr: false,
  })

  const handleSelectWishlist = useCallback(
    (id) => {
      setSelectedWishlist(id)
    },
    [setSelectedWishlist]
  )

  const initialProducts =
    wishlists.length > 0
      ? extractProductData({ items: wishlists[0]?.products })
      : []

  const [allProducts, setAllProducts] = useState(initialProducts)
  const [displayedProducts, setDisplayedProducts] = useState(initialProducts)

  const [, setIsLoadingSKU] = useState(false)
  const [searchValue, setSearchValue] = useState('')
  const [updatedSelectedRows, setUpdatedSelectedRows] = useState([])
  const [wishlist, setWishlist] = useState<any>([])
  const [initialState, setInitialState] = useState(initialJsonState)
  const { refetch } = useQueryWishlistById(selectedWishlist, (data) => {
    if (!data || !data.getWishlist) return

    setWishlist(data.getWishlist)
    const products = extractProductData({
      items: data.getWishlist.products,
    })

    const sortedProducts = products.sort((a, b) =>
      a.department.localeCompare(b.department)
    )

    setAllProducts(sortedProducts)
    setDisplayedProducts(sortedProducts)
  })

  const updateData = () =>
    refetch().then(({ data }) => {
      if (!data || !data.getWishlist) return

      setWishlist(data.getWishlist)

      const products = extractProductData({
        items: data.getWishlist.products,
      })

      const sortedProducts = (products || []).sort((a, b) =>
        a.department.localeCompare(b.department)
      )

      setAllProducts(sortedProducts)
      setDisplayedProducts(sortedProducts)
    })

  const { createWishlist } = useCreateWishlist(async (data) => {
    await fetchData()
    if (data.createWishlist) {
      setSelectedWishlist(data.createWishlist.DocumentId)
    }
  })

  const { updateWishlist } = useUpdateWishlist(async () => {
    await updateData()
  })

  const { deleteWishlist, loading: isDeleting } = useDeleteWishlist(
    selectedWishlist,
    async () => {
      setSelectedWishlist(null)
      await fetchData()
      setSelectedWishlist(
        (wishlists ?? []).length > 0 ? wishlists[0]?.id : null
      )
    }
  )

  // Pagination Logic
  const [currentPage, setCurrentPage] = useState(1)
  const [itemsPerPage, setItemsPerPage] = useState(30)
  const [totalItems, setTotalItems] = useState(0)
  const [paginatedData, setPaginatedData] = useState([])
  const addProductsToCart = useAddToCart()
  const handleBulkAction = useBulkAction({
    wishlist,
    selectedWishlist,
    setUpdatedSelectedRows,
    updateWishlist,
  })

  const tableSchema = JsonSchema({
    addProductsToCart,
    deleteItemsWishlist,
    selectedWishlist,
    wishlist,
    wishlists,
    updateWishlist,
    wishlistColumns,
  })

  const {
    fieldValidationTable,
    isModalAccountTable,
    setFieldValidationTable,
    nameListAccountTable,
    setNameListAccountTable,
    setIsModalAccountTable,
    buttonCloseModalTable,
    buttonModalTable,
    handleNameListTable,
  } = useCreateListAccount()

  useEffect(() => {
    const updateStylesForMobile = () => {
      const targetElement = document.querySelector(
        'body > div.render-container.render-route-store-account > div > div.vtex-store__template.bg-base > div > div:nth-child(3) > div > div > div > div > div > div:nth-child(7) > div > div:nth-child(3) > div.whitebird-my-wishlists-0-x-componentContainer.w-two-thirds-l.w-100-ns.fr-l > div > div'
      ) as HTMLDivElement

      if (window.innerWidth <= 768) {
        if (targetElement) {
          targetElement.classList.remove('pa7')
          targetElement.style.setProperty('padding-left', '0rem', 'important')
        }
      } else if (targetElement) {
        targetElement.classList.add('pa7')
      }
    }

    updateStylesForMobile()
    window.addEventListener('resize', updateStylesForMobile)

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

  useEffect(() => {
    const button = document.querySelector(
      '#toggleFieldsBtn > button'
    ) as HTMLButtonElement

    button.style.minHeight = '28.10px'
    button.style.minWidth = 'min-content'

    button.addEventListener('mouseenter', () => {
      button.style.backgroundColor = '#f2f4f5'
    })

    button.addEventListener('mouseleave', () => {
      button.style.backgroundColor = ''
      button.style.color = ''
    })

    const svgContainer = button.querySelector('.vtex-button__label')

    if (!svgContainer) {
      return
    }

    const svg = svgContainer.querySelector('svg')

    if (svg) {
      svg.style.display = 'none'
    }

    let editViewText = svgContainer.querySelector(
      '.edit-view-text'
    ) as HTMLSpanElement

    if (editViewText) {
      return
    }

    editViewText = document.createElement('span')
    editViewText.classList.add('edit-view-text')
    editViewText.textContent = 'Edit View'

    if (window.innerWidth <= 768) {
      button.style.minHeight = '28.09px !important'
      editViewText.textContent = 'Edit'
      editViewText.style.cssText += 'font-weight: 500; font-size: 13px'
      editViewText.style.cssText += 'top: initial'
    }

    svgContainer.appendChild(editViewText)
  }, [])

  useEffect(() => {
    const button = document.querySelector(
      '#toggleFieldsBtn'
    ) as HTMLButtonElement

    if (window.innerWidth <= 768) {
      button.style.minHeight = '28px !important'
    }

    if (!button) return

    const handleButtonClick = () => {
      setTimeout(() => {
        const elementToStyle = document.querySelector(
          '#toggleFieldsBtn > div'
        ) as HTMLDivElement

        if (elementToStyle) {
          if (window.innerWidth <= 1046) {
            elementToStyle.style.setProperty('position', 'fixed', 'important')
            elementToStyle.style.setProperty('top', '50%', 'important')
            elementToStyle.style.setProperty('left', '50%', 'important')
            elementToStyle.style.setProperty(
              'transform',
              'translate(-50%, -50%)',
              'important'
            )
            elementToStyle.style.setProperty('z-index', '1000', 'important')
          }
        }
      }, 0)
    }

    button.addEventListener('click', handleButtonClick)

    return () => {
      button.removeEventListener('click', handleButtonClick)
    }
  }, [])

  useEffect(() => {
    setSelectedWishlist(selectedWishlist)
    handleSelectWishlist(selectedWishlist)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedWishlist])

  // Logic to get paginated data
  useEffect(() => {
    const startIndex = (currentPage - 1) * itemsPerPage
    const endIndex = startIndex + itemsPerPage
    const data = displayedProducts || []
    const slicedData = data.slice(startIndex, endIndex)

    setPaginatedData(slicedData)
  }, [currentPage, itemsPerPage, displayedProducts])

  // Logic to update the total number of items
  useEffect(() => {
    const data = displayedProducts || []

    setTotalItems(data.length)
  }, [displayedProducts])

  // Handlers to change page and rows per page
  const handleRowsChange = (e, value) => {
    e.preventDefault()
    setItemsPerPage(parseInt(value, 10))
    setCurrentPage(1) // Return to the first page when the number of rows per page changes
  }

  const handleButtonCloseModalTable = (event: {
    preventDefault: () => void
  }) => {
    event.preventDefault()
    buttonCloseModalTable()
  }

  const onAddToWishlist = async (product: any) => {
    setIsLoadingSKU(true)
    const { product: productData } = product.data || {}

    const item =
      productData.items.find(
        (itm: { itemId: string }) => itm.itemId === product?.value
      ) || {}

    const unitMultiplierProperty = productData.properties.find(
      (prop: { name: string }) => prop.name === 'UnitMultiplier'
    )

    const unitMultiplierValue = unitMultiplierProperty
      ? parseInt(unitMultiplierProperty.values[0], 10)
      : 1

    const hasBundle = unitMultiplierValue > 1

    const newProduct = {
      ID: Number(item.itemId),
      Image: item?.images?.[0]?.imageUrl,
      // unitValue: productData.priceRange.sellingPrice.highPrice,
      linkProduct: productData?.link,
      nameProduct: productData?.productName,
      quantityProduct: 1,
      skuCodeReference: item?.referenceId?.[0]?.Value,
      department: productData?.categoryTree?.[0]?.name,
      bundle: hasBundle ? unitMultiplierValue : item.unitMultiplier,
    }

    if (newProduct.bundle > 1) {
      newProduct.quantityProduct *= newProduct.bundle
    }

    try {
      if (
        wishlist.products.some((p: { ID: number }) => p.ID === newProduct.ID)
      ) {
        showToast('You have already added this product to the list')

        return false
      }

      await updateWishlist({
        variables: {
          wishlist: {
            id: selectedWishlist,
            products: [...wishlist.products, newProduct],
          },
        },
      })
      showToast('Successfully added to the Favorites List')

      return true
    } catch (error) {
      console.error('Error adding to the list:', error)

      return false
    } finally {
      setIsLoadingSKU(false)
    }
  }

  const tableFilterOptions = {
    department: {
      label: 'Department',
      renderFilterLabel: () => {
        if (!filterState.department || !filterState.department.object) {
          return 'All'
        }

        const keys = filterState.department.object
          ? Object.keys(filterState.department.object)
          : []

        const isAllTrue = !keys.some(
          (key) => !filterState.department.object[key]
        )

        const isAllFalse = !keys.some(
          (key) => filterState.department.object[key]
        )

        const trueKeys = keys.filter(
          (key) => filterState.department.object[key]
        )

        let trueKeysLabel = ''

        trueKeys.forEach((key, index) => {
          trueKeysLabel += `${key}${index === trueKeys.length - 1 ? '' : ', '}`
        })

        return `${isAllTrue ? 'All' : isAllFalse ? 'None' : `${trueKeysLabel}`}`
      },
      verbs: [
        {
          label: 'Sort',
          value: 'Sort',
          object: (e: React.ChangeEvent<HTMLSelectElement>) => {
            return SelectorObject(e, filterState?.department?.object)
          },
        },
      ],
    },
    name: {
      label: 'Description',
      renderFilterLabel: () => {
        if (!filterState.name || !filterState.name.object) {
          return 'All'
        }

        const keys = filterState.name.object
          ? Object.keys(filterState.name.object)
          : []

        const isAllTrue = !keys.some((key) => !filterState.name.object[key])

        const isAllFalse = !keys.some((key) => filterState.name.object[key])

        const trueKeys = keys.filter((key) => filterState.name.object[key])

        let trueKeysLabel = ''

        trueKeys.forEach((key, index) => {
          trueKeysLabel += `${key}${index === trueKeys.length - 1 ? '' : ', '}`
        })

        return `${isAllTrue ? 'All' : isAllFalse ? 'None' : `${trueKeysLabel}`}`
      },
      verbs: [
        {
          label: 'Sort',
          value: 'Sort',
          object: (e: React.ChangeEvent<HTMLSelectElement>) =>
            SelectorObject(e, filterState?.name?.object),
        },
      ],
    },
  }

  const bulkActionsrowsSelected = (qty: number) => (
    <React.Fragment>Selected rows: {qty}</React.Fragment>
  )

  const bulkActionsAllRowsSelected = (qty: number) => (
    <React.Fragment>All rows selected {qty}</React.Fragment>
  )

  const toolbar = {
    inputSearch: {
      label: 'Search This List',
      value: searchValue,
      onChange: (e: React.ChangeEvent<HTMLInputElement>) =>
        handleInputSearchChange({
          e,
          allProducts,
          setSearchValue,
          setDisplayedProducts,
        }),
      onClear: () => handleInputSearchClear(setDisplayedProducts, allProducts),
      onSubmit: (e) =>
        handleInputSearchSubmit({
          e,
          allProducts,
          searchValue,
          setDisplayedProducts,
        }),
    },
    fields: {
      label: 'Toggle visible fields',
      showAllLabel: 'Show All',
      hideAllLabel: 'Hide All',
    },
  }

  const bulkActions = {
    selectedRows: updatedSelectedRows,
    texts: {
      secondaryActionsLabel: 'Actions',
      rowsSelected: bulkActionsrowsSelected,
      selectAll: 'Select all',
      allRowsSelected: bulkActionsAllRowsSelected,
    },
    totalItems: '',
    onChange: (params) => {
      setUpdatedSelectedRows(params.selectedRows)
    },
    others: [
      {
        label: 'Add to cart',
        handleCallback: (params) => {
          handleBulkAction(params.selectedRows, 'addToCart')
        },
      },
      {
        label: 'Remove item(s)',
        isDangerous: true,
        handleCallback: (params) =>
          handleBulkAction(params.selectedRows, 'deleteRowsWishlist'),
      },
    ],
  }

  const pagination = {
    onNextClick: () =>
      handleNextClick({
        currentPage,
        setCurrentPage,
        totalItems,
        itemsPerPage,
      }),
    onPrevClick: () => handlePrevClick(currentPage, setCurrentPage),
    currentItemFrom: (currentPage - 1) * itemsPerPage + 1,
    currentItemTo: Math.min(currentPage * itemsPerPage, totalItems),
    onRowsChange: handleRowsChange,
    textShowRows: 'Show rows',
    textOf: 'of',
    totalItems,
    rowsOptions: [30, 40, 50, 60],
  }

  const filters = {
    alwaysVisibleFilters: ['department', 'name'],
    statements: initialState.filterStatements,
    onChangeStatements: (e: React.ChangeEvent<HTMLInputElement>) => {
      handleFiltersChange({
        statements: initialState.filterStatements,
        initialState,
        setInitialState,
        paginatedData,
        setPaginatedData,
        setDisplayedProducts,
        onChangeStatements: e[2],
        setfilterState,
        filterState,
      })
    },
    clearAllFiltersButtonLabel: 'Clear Filters',
    collapseLeft: true,
    options: tableFilterOptions,
  }

  return (
    <>
      {deviceInfo.type === 'phone' ? (
        <WishlistMobile
          selectedWishlist={selectedWishlist}
          wishlists={wishlists}
          wishlist={wishlist}
          fetchData={fetchData}
          handleSelectWishlist={handleSelectWishlist}
          emailIDInfo={emailIDInfo}
          buttonModalTable={buttonModalTable}
          isModalAccountTable={isModalAccountTable}
          handleSubmitDataTable={handleSubmitDataTable}
          createWishlist={createWishlist}
          setFieldValidationTable={setFieldValidationTable}
          nameListAccountTable={nameListAccountTable}
          setNameListAccountTable={setNameListAccountTable}
          setIsModalAccountTable={setIsModalAccountTable}
          deleteWishlist={deleteWishlist}
          buttonCloseModalTable={buttonCloseModalTable}
          handleNameListTable={handleNameListTable}
          fieldValidationTable={fieldValidationTable}
          isDeleting={isDeleting}
        />
      ) : (
        <WishlistDesktop
          selectedWishlist={selectedWishlist}
          wishlists={wishlists}
          wishlist={wishlist}
          fetchData={fetchData}
          handleSelectWishlist={handleSelectWishlist}
          emailIDInfo={emailIDInfo}
          buttonModalTable={buttonModalTable}
          isModalAccountTable={isModalAccountTable}
          handleSubmitDataTable={handleSubmitDataTable}
          createWishlist={createWishlist}
          setFieldValidationTable={setFieldValidationTable}
          nameListAccountTable={nameListAccountTable}
          setNameListAccountTable={setNameListAccountTable}
          setIsModalAccountTable={setIsModalAccountTable}
          deleteWishlist={deleteWishlist}
          buttonCloseModalTable={handleButtonCloseModalTable}
          handleNameListTable={handleNameListTable}
          fieldValidationTable={fieldValidationTable}
          isDeleting={isDeleting}
        />
      )}

      <AutocompleteBlock
        text="Add SKU"
        description="Search and add to your list"
        componentOnly={false}
        onAddToWishlist={onAddToWishlist}
      />
      <section className={styles.wishlistSearchContainer}>
        <ProductsProvider items={paginatedData}>
          <TablePaginationWrapper
            tableSchema={tableSchema}
            pagination={pagination}
            bulkActions={bulkActions}
            toolbar={toolbar}
            filters={filters}
            items={paginatedData}
          />
        </ProductsProvider>
      </section>
    </>
  )
}

export default 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/react/components/productPriceTotal.css from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```css
.productPriceContainer {
    width: 100%;
    min-width: 100%;
    display: flex;
    align-items: center;
    justify-content: flex-end;
}

```


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

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

[Assistant]
Here's the implementation:

```css
.notesContainer {
  width: 100%;
  min-width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.addNotesIcons {
  display: flex;
  width: 100%;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

.notesButtonContainer {
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  padding-top: 1rem;
}

.notesSubmitButtonContainer {

}

.notesSubmitButton {
  font-size: 1rem;
  margin: 0;
  overflow: visible;
  text-transform: capitalize;
  border-radius: 50px;
  border-color: #000000;
  cursor: pointer;
  color: #FFFFFF;
  background-color: #002266;
  width: 80px;
  height: 34px;
  padding: 10px;
  font-weight: 400;
  line-height: 19.36px;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}

.notesSubmitDisabledButton {
  opacity: 0.5;
}

.notesModalContainer {
  display: flex;
  flex-direction: column;
  row-gap: 1rem;
}

.notesModalTitle {
  padding-top: 1rem;
}

.notesModalBottomRow {

}

.notesCancelButton {
  font-size: 1rem;
  margin: 0;
  overflow: visible;
  text-transform: capitalize;
  border-radius: 50px;
  border-color: #000000;
  font-weight: 400;
  cursor: pointer;
  color: #000000;
  width: 80px;
  height: 34px;
  padding: 10px;
  font-weight: 400;
  line-height: 19.36px;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
}

.productSummary {
  display: flex;
  flex-direction: row;
  gap: 1rem;
  padding-top: 2rem;
  padding-bottom: 1rem;
  padding-left: 2rem;
  border-bottom: 1px solid #9C9C9C;
}

.productSummaryImageContainer {

}

.productSummaryImage {
  object-fit: contain;
}

.productSummaryInfo {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.productSummaryInfoName {
  font-size: 20px;
  font-weight: 700;
  line-height: 24.2px;
  text-align: left;
  color: #7A8094;
}

.productSummaryInfoDetails {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  gap: 2rem;
}

.productSummaryInfoDetailsPartNumber {
  font-size: 17px;
  font-weight: 400;
  line-height: 20.57px;
  text-align: left;
  color: #7A8094;
}

.productSummaryInfoDetailsPrice {
  font-size: 17px;
  font-weight: 400;
  line-height: 20.57px;
  text-align: left;
  color: #7A8094;
}

:global(.vtex-modal__modal) :global(.vtex-styleguide-9-x-shadowTransition) {
  background: #002266;
  border-radius: 5px 5px 0 0;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

:global(.vtex-modal__modal) :global(.vtex-styleguide-9-x-shadowTransition)>span {
  font-size: 24px;
  font-weight: 700;
  line-height: 29.05px;
  text-align: center;
  color: #ffffff
}

:global(.vtex-modal__close-icon) {
  padding-top: unset;
  padding-bottom: unset;
  padding-left: unset;
  padding-right: 1rem;
  height: 100%;
}

:global(.vtex-modal__close-icon) :global(.vtex__icon-close)  {
  color: #ffffff
}

.noteSubTitle {
  font-size: 16px;
  font-weight: 700;
  line-height: 19.36px;
  text-align: left;
  color: #7A8094;
  height: 50px;
}

```


[System] You are an expert VTEX IO developer. You specialize 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/Notes.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

import { NoteIcon } from './Icons'
import styles from './notes.css'
import useQueryGetProductPrice from '../hooks/actions/useQueryGetProductPrice'

const Notes = ({
  wishlist: initialWishlist,
  updateWishlist,
  skuReference,
  currentNotes,
  productName,
  productImage,
  partNumber,
  currency,
  itemId,
  quantity,
}) => {
  const [show, setShow] = useState(false)
  const [notes, setNotes] = useState('')

  const { price } = useQueryGetProductPrice(
    'sku',
    itemId,
    quantity ? parseInt(quantity, 10) : 1
  )

  const wishlistRef = useRef(initialWishlist)

  const { showToast } = useContext<any>(ToastContext)

  useEffect(() => {
    wishlistRef.current = initialWishlist
  }, [initialWishlist])

  useEffect(() => {
    setNotes(currentNotes)
  }, [currentNotes])

  const handleNotesSubmit = async () => {
    try {
      const updatedProducts = wishlistRef.current.products?.map(
        (product: { skuCodeReference: any }) => ({
          ...product,
          ...(product.skuCodeReference === skuReference ? { notes } : {}),
        })
      )

      await updateWishlist({
        variables: {
          wishlist: {
            id: wishlistRef.current.id,
            products: updatedProducts,
          },
        },
      })

      showToast('Notes saved successfully!')
      setShow(false)
    } catch (error) {
      showToast('Error saving notes!')
      console.error('Notes submit error: ', error)
    }
  }

  const formattedValue = `${currency} ${price.toFixed(2)}`

  return (
    <div className={`${styles.notesContainer}`}>
      <div
        className={`${styles.addNotesIcons}`}
        onClick={() => setShow(!show)}
        aria-hidden="true"
      >
        <NoteIcon />
      </div>

      <Modal
        isOpen={show}
        onClose={() => setShow(false)}
        title="Add a Note"
        className="w-100 hhh"
      >
        <div className={`${styles.notesModalContainer}`}>
          <div className={`${styles.productSummary}`}>
            <div className={`${styles.productSummaryImageContainer}`}>
              <img
                className={`${styles.productSummaryImage}`}
                src={productImage}
                alt={productName}
                width="74px"
                height="64px"
              />
            </div>
            <div className={`${styles.productSummaryInfo}`}>
              <div className={`${styles.productSummaryInfoName}`}>
                <span>{productName}</span>
              </div>
              <div className={`${styles.productSummaryInfoDetails}`}>
                <div
                  className={`${styles.productSummaryInfoDetailsPartNumber}`}
                >
                  <span>Part #: {partNumber}</span>
                </div>
                <div className={`${styles.productSummaryInfoDetailsPrice}`}>
                  <span>Price: {formattedValue}</span>
                </div>
              </div>
            </div>
          </div>
          <div>
            <span
              className={`${styles.notesModalTitle} f3 db lh-copy measure flex items-center`}
            >
              Note
            </span>
          </div>
          <textarea
            className="w-100 pa4"
            id="wish-list-notes"
            name="wish-list-notes"
            rows={8}
            onChange={(e) => setNotes(e.target.value)}
            value={notes}
          />
          <div className={`${styles.notesButtonContainer}`}>
            <div className={`${styles.notesCancelButtonContainer}`}>
              <button
                className={`${styles.notesCancelButton}`}
                onClick={() => setShow(false)}
              >
                Cancel
              </button>
            </div>
            <div className={`${styles.notesSubmitButtonContainer}`}>
              <button
                className={`${styles.notesSubmitButton}`}
                onClick={() => handleNotesSubmit()}
              >
                Save
              </button>
            </div>
          </div>
        </div>
      </Modal>
    </div>
  )
}

export default 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/components/WishlistMobile.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

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

const WishlistMobile = ({
  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: React.FormEvent) => {
    setIsCreateLoading(true)
    try {
      await handleSubmitDataTable({
        event,
        createWishlist,
        setFieldValidationTable,
        nameListAccountTable,
        setNameListAccountTable,
        setIsModalAccountTable,
      })
      showToast('You created a new Wishlist')
      setIsCreateLoading(false)
    } catch (error) {
      showToast(error)
      console.error(error)
      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-mobile">
      {/* Mobile Design */}

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

      <div className={styles.wishlistOptionsContainer}>
        <div className={styles.wishlistSelector}>
        <div className={styles.wishlistSelectListTitle}>
        <Button href="/account" >RETURN</Button>
          <p className={styles.wishlistSelectListOneText}>Favorites List</p>
          </div>

          <div className={`${styles.createListandAndSelectFav}`}>
            <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>
            <section className="relative">
              <button
                className={`${styles.wishlistCreateNew} ${styles.wishlistCreateNewHelper}`}
                onClick={buttonModalTable}
              >
                New
              </button>
              {isModalAccountTable && (
                <ModalCreateList
                  buttonCloseModal={buttonCloseModalTable}
                  handleNameList={handleNameListTable}
                  fieldValidation={fieldValidationTable}
                  handleSubmitData={onCreateList}
                  isButtonLoading={isCreateLoading}
                  blockClass="vtex-create-wishlist-mobile"
                />
              )}
            </section>
          </div>
        </div>
      </div>

      <div className={`${styles.nameAndOptionsMobile}`}>
        <EditableWishlistTitle
          initialTitle={selectedWishlist !== null ? wishlist.wishlistType : ''}
          wishlistId={
            selectedWishlist !== null ? selectedWishlist : wishlists[0].id
          }
          wishlist={selectedWishlist !== null ? wishlist : wishlists[0]}
          fetchData={fetchData}
        />
        <div className={`${styles.optionsMobile}`}>
          <WishlistPrivacyOptions
            selectedWishlist={
              selectedWishlist !== null ? selectedWishlist : wishlists[0].id
            }
            wishlists={wishlists}
            buttonLabel="Share"
          />
          <button
            className={styles.wishlistDeleteWishList}
            onClick={openModal}
          >
            {isDeleting ? `Deleting...` : `Delete`}
          </button>
        </div>
      </div>
    </div>
  )
}

export default WishlistMobile

```


[System] You are an expert VTEX IO developer. You specialize 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/Icons.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

export const NoteIcon = () => {
  return (
    <svg
      width="20px"
      height="20px"
      viewBox="0 0 24 24"
      fill="none"
      xmlns="https://www.w3.org/2000/svg"
    >
      <path
        d="M20 8.25V18C20 21 18.21 22 16 22H8C5.79 22 4 21 4 18V8.25C4 5 5.79 4.25 8 4.25C8 4.87 8.24997 5.43 8.65997 5.84C9.06997 6.25 9.63 6.5 10.25 6.5H13.75C14.99 6.5 16 5.49 16 4.25C18.21 4.25 20 5 20 8.25Z"
        stroke="#292D32"
        strokeWidth="1.5"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="M16 4.25C16 5.49 14.99 6.5 13.75 6.5H10.25C9.63 6.5 9.06997 6.25 8.65997 5.84C8.24997 5.43 8 4.87 8 4.25C8 3.01 9.01 2 10.25 2H13.75C14.37 2 14.93 2.25 15.34 2.66C15.75 3.07 16 3.63 16 4.25Z"
        stroke="#292D32"
        strokeWidth="1.5"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="M8 13H12"
        stroke="#292D32"
        strokeWidth="1.5"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="M8 17H16"
        stroke="#292D32"
        strokeWidth="1.5"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  )
}

export const SearchIcon = () => {
  return (
    <svg
      width="25"
      height="24"
      viewBox="0 0 25 24"
      fill="none"
      xmlns="https://www.w3.org/2000/svg"
      xmlnsXlink="https://www.w3.org/1999/xlink"
    >
      <rect width="25" height="24" fill="url(#pattern0_904_1396)" />
      <defs>
        <pattern
          id="pattern0_904_1396"
          patternContentUnits="objectBoundingBox"
          width="1"
          height="1"
        >
          <use
            xlinkHref="#image0_904_1396"
            transform="matrix(0.0344828 0 0 0.0359195 0 -0.164511)"
          />
        </pattern>
        <image
          id="image0_904_1396"
          width="29"
          height="37"
          xlinkHref="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAlAB0DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9Sv7Pi/vT/wDf+T/4qj+z4v70/wD3/k/+KrD+I3xF0D4T+CtU8V+J79dN0TTY/MnnYFjyQqqqjlmZiFAHUkV4H/w118QF0f8A4So/s8+LB4C2+f8A2n/aFt/aHkdfN/s//WY2/N97Hv3rpp4erWXNBaeqXy13ZlKpCDsz6Y/s+L+9P/3/AJP/AIqj7BF/fm/7/v8A41i/Dz4g6D8VPBeleKvDN+upaJqUXm29woIPUhlYHlWVgVKnkEEV0dYSi4txlo0aJpq6Pmn9vixmX4T+FtfkspdS0Hwx4v0vXNds4kMhm0+J2EwKfxKC6kjoApJ4Fe0P8XPBUfgL/hNm8U6WPCfk+eNX+1L5BXbnAbP3sfw/ezxjPFdXNDHcwyQzRrLFIpR43UFWUjBBB6givDG/YZ+A7+IjrZ+Gmkm9LlzHul+zZJz/AMe+/wArHtsxXZCpSnTjTq3XK3tZ7+rX36+hhKM4ycoW17nIf8E79Tsdd+Efi/V9JlhXQ9U8aatfaZYRupaxtXdPLhdAf3Z4LbT2cHoRX1LXz1+zx+xroP7NvxI8ZeI/DWv6k2i69Gsdv4dk/wCPezAbcSW3EykHIRiAVVmBLE5r6FpY2dOpXlOk7p/1b5DoRlGmozVmgoooriNwooooA//Z"
        />
      </defs>
    </svg>
  )
}

```


[System] You are an expert VTEX IO developer. You specialize 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.css from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```css
.unitPriceContainer {
  width: 100%;
  min-width: 100%;
  display: flex;
  align-items: center;
}

.skuNameContainer {
  text-wrap: wrap;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

.descriptionContainer {}

.wishlistProductTexts,
.wishlistProductTexts a {
  font-weight: 400;
  color: #000000;
  text-decoration: 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/components/WishlistShare.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useQuery } from 'react-apollo'
import { useRuntime } from 'vtex.render-runtime'
import { Spinner } from 'vtex.styleguide'

import GET_WISHLIST_BY_ID from '../graphql/queries/getWishlistById.gql'
import { WishlistMD } from '../interfaces'
import AppSettings from '../queries/AppSettings.graphql'
import styles from '../styles.css'
import TableShare from './TableShare'

export default function WishlistShare() {
  const { query } = useRuntime()
  const { id } = query

  const { data, loading } = useQuery(GET_WISHLIST_BY_ID, {
    variables: { id },
    ssr: false,
    fetchPolicy: 'network-only',
  })

  const { data: wishlistColumns } = useQuery(AppSettings, {
    variables: {
      // eslint-disable-next-line no-undef
      version: process.env.VTEX_APP_VERSION,
    },
    ssr: false,
  })

  if (loading) {
    return (
      <div
        style={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          height: '60vh',
        }}
      >
        <Spinner color="black" size={20} />
      </div>
    )
  }

  const wishlistMD: WishlistMD = data?.getWishlist || {
    products: [],
    email: '',
  }

  const { defaultTitleText } = JSON.parse(
    wishlistColumns.publicSettingsForApp.message
  )

  return (
    <div className={`${styles.wishlistShare}`}>
      <h2 className="flex justify-center mt6">
        {`${wishlistMD.email}'s ${defaultTitleText ?? 'Favorites List'}`}
      </h2>
      {wishlistMD.products && (
        <TableShare
          wishlistMD={wishlistMD}
          columns={wishlistColumns}
          queryId={id}
        />
      )}
    </div>
  )
}

```


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

[User] Show me the implementation of wish-list-v2/react/components/ProductPriceTotal.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 './productPriceTotal.css'

const ProductPriceTotal = ({ productQuantity = 0, currency = '$', itemId }) => {
  const { price, error: productError, loading } = useQueryGetProductPrice(
    'sku',
    itemId,
    productQuantity
  )

  const handlePrice = () =>
    price ? `${currency} ${parseFloat(price).toFixed(2)}` : null

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

  return productError ? (
    <Wrapper>
      <span>Error</span>
    </Wrapper>
  ) : loading ? (
    <Wrapper>
      <Spinner size={20} />
    </Wrapper>
  ) : (
    <Wrapper>{handlePrice()}</Wrapper>
  )
}

export default ProductPriceTotal

```


[System] You are an expert VTEX IO developer. You specialize 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/graphql/query.getMdHaveWishlist.gql from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getMdHaveWishlist ($acronym: String, $fields: [String], $pageSize: Int) {
  documents(acronym: $acronym, fields: $fields, pageSize: $pageSize)
  @context(provider: "vtex.store-graphql") {
    id
    fields {
      key
      value
    }
  }
}
```


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

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

[Assistant]
Here's the implementation:

```graphql
query TEST($ac: String, $fields: [String], $id: String, $account: String) {
  document(acronym: $ac, fields: $fields, id: $id, account: $account)
    @context(provider: "vtex.store-graphql") {
    fields {
      value
      key
    }
  }
}

```


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

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

[Assistant]
Here's the implementation:

```typescript
import { useContext } from 'react'
import { ToastContext } from 'vtex.styleguide'
import { useOrderItems } from 'vtex.order-items/OrderItems'
import { useOrderForm } from 'vtex.order-manager/OrderForm'

import { extractProductData } from '../components/helpers'
import handleDataLayerEvent from '../utils/handleDataLayerEvent'
import { WishlistMD } from '../interfaces'

const useAddToCart = () => {
  const { addItems } = useOrderItems()
  const { showToast } = useContext<any>(ToastContext)
  const { orderForm } = useOrderForm()

  // hook used to add several products from the wishlist table to the cart
  const addProductsToCart = (
    props: { name: string; itemId: number; quantity?: number },
    wishlist: WishlistMD
  ) => {
    const productsByOrders = orderForm.items
    const findProductQuantity = productsByOrders?.find(
      (item: { id: string }) => Number(item.id) === props.itemId
    )

    const quantityAlreadyAdd = findProductQuantity?.quantity
      ? findProductQuantity?.quantity
      : 0

    const dataExtract = extractProductData({
      items: wishlist?.products?.map((product) => {
        return {
          ...product,
          quantity: Number(product.quantityProduct),
          name: product.nameProduct,
        }
      }),
    })

    const productInfo = dataExtract.find(
      (item: { id: string }) => props.itemId === Number(item.id)
    )

    const quantityToAdd = props.quantity ?? Number(productInfo.quantity)
    const items = [
      {
        id: productInfo.id,
        seller: 1,
        quantity: quantityToAdd + Number(quantityAlreadyAdd ?? 0),
        name: productInfo.name,
      },
    ]

    if (items.length === 0) return

    addItems(items)
      .then(() => {
        handleDataLayerEvent('addToCart', [productInfo])
        showToast('Item added to the cart')
      })
      .catch((error) => {
        console.error(error)
      })
  }

  return addProductsToCart
}

export default useAddToCart

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useBundleMinQuantity.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
const useBundleMinQuantity = (productContextValue: {
  properties: any[]
}): number => {
  const unitMultiplier = productContextValue?.properties?.find(
    (property) => property.name === 'UnitMultiplier'
  )?.values?.[0]

  return Number(unitMultiplier) || 1
}

export default useBundleMinQuantity

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useAddSharedListPage.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
import React, { useEffect, useState } from 'react'
import { useOrderForm } from 'vtex.order-manager/OrderForm'
import { useRuntime } from 'vtex.render-runtime'

import useCreateListAccount from './useCreateListAccount'
import { useUserEmail } from './useUserEmail'
import useStoreGlobal from '../globalStore/globalStore'
import useMutationCreateWishlist from './actions/useMutationCreateWishlist'
import useQueryWishlists from './actions/useQueryWishlists'
import { WishlistProduct } from '../interfaces'

interface UseAddSharedListPageProps {
  queryId: string
  products: WishlistProduct[]
  updatedProducts: any
}

export default function useAddSharedListPage({
  queryId,
  products,
}: UseAddSharedListPageProps) {
  // ORDER FORM
  const { orderForm } = useOrderForm()

  // RUNTIME
  const { navigate } = useRuntime()

  // PATH VALIDATION
  const pathname = encodeURIComponent(
    `${window.location.pathname}?id=${queryId}`
  )

  const loginUrl = `/login?returnUrl=${pathname}`

  // STATES
  const [isLoading, setIsLoading] = useState(true)
  const [isListNameInputVisible, setIsListNameInputVisible] = useState<boolean>(
    false
  )

  isLoading

  const { updatedProducts } = useStoreGlobal.getState()

  const { createWishlist } = useMutationCreateWishlist(() => {})
  const { data: wishlistsByEmail, refetch } = useQueryWishlists()

  // CREATE WISH LIST
  const {
    fieldValidationTable,
    nameListAccountTable,
    setFieldValidationTable,
    setNameListAccountTable,
    setIsModalAccountTable,
    handleNameListTable,
  } = useCreateListAccount()

  const setWishlists = useStoreGlobal((state) => state.setWishlists)

  // USER EMAIL
  const userEmail = useUserEmail()
  const fetchData = async () => {
    setIsLoading(true)
    refetch()
    const data = wishlistsByEmail

    setWishlists(data || [])
    setIsLoading(false)
  }

  // EFFECTS
  useEffect(() => {
    fetchData()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [userEmail])

  // DATA
  const isUserLoggedOut = orderForm.loggedIn === false

  // METHODS
  const navigateToLoginPage = () => {
    navigate({
      to: loginUrl,
    })
  }

  const handleInputListNameVisualization = () => {
    setIsListNameInputVisible((state) => !state)
  }

  const createNewList = async (event: React.FormEvent) => {
    event.preventDefault()

    if (nameListAccountTable.trim() === '') {
      setFieldValidationTable('The field cannot be empty')
    } else {
      const listProducts: any[] = []

      if (
        Object.keys(updatedProducts).length > 0 &&
        updatedProducts.filter((item) => item.ID).length
      ) {
        Object.values(updatedProducts).forEach((prod: any) => {
          const newProduct: any = {
            ID: prod.ID,
            Image: prod.Image,
            bundle: prod.bundle,
            unitValue: prod.unitValue,
            linkProduct: prod.linkProduct,
            nameProduct: prod.nameProduct,
            quantityProduct: prod.quantityProduct,
            skuCodeReference: prod.skuCodeReference,
            department: prod.department,
          }

          listProducts.push(newProduct)
        })
      } else {
        products.forEach((prod: any) => {
          const newProduct = {
            ID: prod.id || prod.ID,
            Image: prod.image || prod.Image,
            bundle: prod.bundle,
            unitValue: prod.unitValue,
            linkProduct: prod.linkProduct,
            nameProduct: prod.name || prod.nameProduct,
            quantityProduct: prod.qty || prod.quantityProduct,
            skuCodeReference: prod.skuReferenceCode || prod.skuCodeReference,
            department: prod.department,
          }

          listProducts.push(newProduct)
        })
      }

      await createWishlist({
        variables: {
          wishlist: {
            wishlistType: nameListAccountTable,
            isPublic: false,
            products: listProducts,
          },
        },
      })
      setNameListAccountTable('')
      setFieldValidationTable('')
      setNameListAccountTable(false)
      setIsModalAccountTable(false)
      setIsListNameInputVisible(false)
      navigate({ to: '/account#/my-wishlists' })
    }
  }

  // RETURN
  return {
    isUserLoggedOut,
    navigateToLoginPage,
    isListNameInputVisible,
    handleInputListNameVisualization,
    fieldValidationTable,
    handleNameListTable,
    createNewList,
  }
}

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useGetWishlists.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useEffect, useState, useContext } from 'react'
import useProduct from 'vtex.product-context/useProduct'
import { ToastContext } from 'vtex.styleguide'

import useBundleMinQuantity from './useBundleMinQuantity'
import useQueryWishlists from './actions/useQueryWishlists'
import useMutationCreateWishlist from './actions/useMutationCreateWishlist'

const useGetWishlist = () => {
  const [listWishlist, setListWishlist] = useState<any>([])
  const [productBundle, setProductBundle] = useState<any>(null)
  const [nameListWishlist, setNameListWishlist] = useState('')
  const [errorName, setErrorName] = useState('')
  const [isLoading, setisLoading] = useState(false)
  const [isButton, setIsButton] = useState(true)
  const [isMessage, setIsMessage] = useState(false)
  const [isShowForm2, setIsShowForm2] = useState(false)
  const [clickCreate, setClickCreate] = useState(false)
  const [isShowSelect, setIsShowSelect] = useState(false)
  const [isShowForm, setIsShowForm] = useState(false)

  const { product, selectedQuantity, selectedItem } = useProduct()
  const { showToast } = useContext<any>(ToastContext)
  const bundle = useBundleMinQuantity(product)

  const { data, refetch } = useQueryWishlists()
  const { createWishlist } = useMutationCreateWishlist(async (d) => {
    const datarefect = await refetch()

    const find = datarefect?.data?.getWishlistsByEmail?.find(
      (item: { wishlistType: string }) => item.wishlistType === nameListWishlist
    )

    if (!find) {
      const currentWhislist = datarefect?.data?.getWishlistsByEmail

      currentWhislist.push({
        id: d.createWishlist.DocumentId,
        wishlistType: nameListWishlist,
      })
      setListWishlist(currentWhislist)
    }

    setNameListWishlist('')
    setisLoading(false)
  })

  useEffect(() => {
    setProductBundle(bundle)
  }, [bundle])

  const nameProduct = product?.productName
  const linkProduct = product?.link
  const idProduct = Number(selectedItem?.itemId)
  const urlImageProduct = product?.items?.find((item: any) => item)?.images?.[0]
    ?.imageUrl

  const quantityProduct = selectedQuantity
  const price = Number(product?.priceRange?.sellingPrice?.highPrice)
  const skuCodeReference = product?.items?.[0]?.referenceId?.[0]?.Value
  const departmentArray = product?.categoryTree
  const department = departmentArray?.[0]?.name

  useEffect(() => {
    if (data?.getWishlistsByEmail) {
      setListWishlist(data.getWishlistsByEmail)
    }
  }, [data])

  const postCreateList = async () => {
    const productObj: any = {
      ID: idProduct,
      Image: urlImageProduct,
      unitValue: price,
      nameProduct,
      linkProduct,
      quantityProduct,
      skuCodeReference,
      department,
    }

    setisLoading(true)
    if (productBundle !== 1) {
      productObj.quantityProduct = selectedQuantity * productBundle
      productObj.bundle = productBundle
    }

    try {
      await createWishlist({
        variables: {
          wishlist: {
            wishlistType: nameListWishlist,
            products: [productObj],
            isPublic: false,
          },
        },
        refetchQueries: ['getWishlists'],
      })

      setisLoading(false)
      showToast('You created a new Favourite List and your product was added')
    } catch (error) {
      setisLoading(false)
      showToast(error)
    }
  }

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const valueNameList = e.target.value

    setNameListWishlist(valueNameList)
  }

  const addList = () => {
    setIsShowForm2(true)
    setClickCreate(true)
  }

  const sendData1 = (e: React.FormEvent) => {
    e.preventDefault()

    if (nameListWishlist.trim() === '') {
      setErrorName('The field cannot be empty')
    } else {
      postCreateList()

      setIsShowForm2(false)
      setClickCreate(false)

      setErrorName('')
    }
  }

  const createLengthZero = () => {
    setIsShowForm(true)
    setIsButton(false)
  }

  const sendData2 = (e: React.FormEvent) => {
    e.preventDefault()

    if (nameListWishlist.trim() === '') {
      setErrorName('The field cannot be empty')
    } else {
      postCreateList()

      setIsShowForm(false)
      setIsButton(false)
      setIsMessage(true)

      setErrorName('')
    }
  }

  useEffect(() => {
    if (isMessage === true) {
      setTimeout(() => {
        setIsMessage(false)
      }, 10000)
    }
  }, [isMessage])

  return {
    listWishlist,
    isButton,
    isMessage,
    isShowForm,
    isShowForm2,
    clickCreate,
    isShowSelect,
    nameListWishlist,
    errorName,
    isLoading,
    setIsShowSelect,
    setIsShowForm,
    handleChange,
    addList,
    sendData1,
    createLengthZero,
    sendData2,
  }
}

export default useGetWishlist

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useBulkAction.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { useContext } from 'react'
import { ToastContext } from 'vtex.styleguide'
import { useOrderItems } from 'vtex.order-items/OrderItems'

import handleDataLayerEvent from '../utils/handleDataLayerEvent'
import {
  extractProductData,
  formatProductForWishlist,
} from '../components/helpers'

// wishlist button in my-account, used to add the product from the table row to the cart
const useBulkAction = ({
  wishlist,
  selectedWishlist,
  setUpdatedSelectedRows,
  updateWishlist,
}) => {
  const { addItems } = useOrderItems()
  const { showToast } = useContext(ToastContext)

  const handleBulkAction = async (selectedRows, actionId) => {
    if (actionId === 'addToCart') {
      const dataExtract = extractProductData({ items: wishlist.products })
      const itemsToAdd = selectedRows.map((row) => {
        const productDetails = dataExtract.find(
          (item) => row.name === item.name
        )

        return {
          id: Number(productDetails.id),
          seller: 1,
          quantity: productDetails.quantity,
          name: productDetails.name,
        }
      })

      if (itemsToAdd.length > 0) {
        addItems(itemsToAdd)
          .then(() => {
            handleDataLayerEvent('addToCart', selectedRows)
            showToast('Items added to the cart')
          })
          .catch((error) => {
            console.error(error)
          })
      }
    }

    if (actionId !== 'deleteRowsWishlist') {
      return
    }

    const dataExtract = extractProductData({ items: wishlist.products })
    const itemsToDelete = selectedRows.map((row) => {
      const selectedProduct = dataExtract.find((item) => {
        return row.name === item.name
      })

      return selectedProduct.id
    })

    let updatedList = dataExtract.filter(
      (item) => !itemsToDelete.includes(item.id)
    )

    updatedList = formatProductForWishlist(updatedList)
    setUpdatedSelectedRows((prevSelectedRows) =>
      prevSelectedRows.filter((row) => !selectedRows.includes(row))
    )
    updateWishlist({
      variables: {
        wishlist: {
          id: selectedWishlist,
          products: updatedList,
        },
      },
    })
  }

  return handleBulkAction
}

export default useBulkAction

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useGetIntelligentSearch.jsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```jsx
import axios from 'axios'
import { useState } from 'react'

const useGetIntelligentSearch = () => {
  const [searchProduct, setSearchProduct] = useState([])
  const [valueSearchSku, setValueSearchSku] = useState('')
  const [isShowProductSearch, setIsShowProductSearch] = useState(false)

  const changeValueSku = (event) => {
    const valueNameSku = event.target.value

    setValueSearchSku(valueNameSku)
  }

  const getSearchProduct = async () => {
    try {
      const axiosConfig = {
        method: 'get',
        url: `/api/io/_v/api/intelligent-search/product_search/?query=${valueSearchSku}`,
        headers: {
          Accept: 'application/json',
        },
      }

      const response = await axios(axiosConfig)
      const arrayDate = response.data.products

      setSearchProduct(arrayDate)
    } catch (error) {
      console.error(error)
    }

    setValueSearchSku('')
    setIsShowProductSearch(true)
  }

  return {
    searchProduct,
    valueSearchSku,
    isShowProductSearch,
    changeValueSku,
    getSearchProduct,
  }
}

export default useGetIntelligentSearch

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useUserEmail.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
import { useOrderForm } from 'vtex.order-manager/OrderForm'

export const useUserEmail = () => {
  const { orderForm } = useOrderForm()
  const { email } = orderForm.clientProfileData || { email: '' }

  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/react/hooks/useSelectWishlist.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import axios from 'axios'
import { useState, useEffect, useRef, useContext } from 'react'
import useProduct from 'vtex.product-context/useProduct'
import { ToastContext } from 'vtex.styleguide'

import useWishList from './useWishlists'
import useGetWishlist from './useGetWishlists'
import useBundleMinQuantity from './useBundleMinQuantity'
import useMutationUpdateWishlist from './actions/useMutationUpdateWishlist'

const useSelectWishlist = () => {
  const {
    emailInfo,
    nameProduct,
    linkProduct,
    urlImageProduct,
    quantityProduct,
    price,
    idProduct,
    skuCodeReference,
    department,
  } = useWishList()

  const { listWishlist } = useGetWishlist()

  const [textSelect, setTextSelect] = useState('')
  const [valueSelect, setValueSelect] = useState('')
  const [errorSelect, setErrorSelect] = useState('')
  const [selectSize, setSelectSize] = useState(1)
  const selectRef = useRef<HTMLSelectElement | null>(null)

  const [closeSelect, setCloseSelect] = useState(true)
  const [productBundle, setProductBundle] = useState<number>(1)

  const { product, selectedQuantity } = useProduct()
  const { showToast } = useContext<any>(ToastContext)
  const bundle = useBundleMinQuantity(product)
  const { updateWishlist } = useMutationUpdateWishlist(() => {})

  useEffect(() => {
    setProductBundle(bundle)
  }, [bundle])

  const captureValue = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const valueText = e.target.value
    const selectedOptionText = e.target.options[e.target.selectedIndex].text

    setValueSelect(valueText)
    setTextSelect(selectedOptionText)

    if (selectRef.current instanceof HTMLSelectElement) {
      selectRef.current.blur()
    }
  }

  const handleSelectFocus = () => {
    setSelectSize(3)
  }

  const handleSelectBlur = () => {
    setSelectSize(1)
  }

  const addToList = () => {
    if (textSelect.trim().length === 0) {
      setErrorSelect('Select a list to save your product')

      return
    }

    const existingWishlist = listWishlist.find(
      (typeWish: { wishlistType: string; id: string }) =>
        typeWish.wishlistType === textSelect && typeWish.id === valueSelect
    )

    const newProduct: any = {
      ID: idProduct,
      Image: urlImageProduct,
      unitValue: price,
      linkProduct,
      nameProduct,
      quantityProduct,
      skuCodeReference,
      department,
    }

    if (productBundle !== 1) {
      newProduct.quantityProduct = selectedQuantity * productBundle
      newProduct.bundle = productBundle
    }

    if (existingWishlist) {
      const productExists = existingWishlist.products.some(
        (item: { ID: string | number }) => item.ID === newProduct.ID
      )

      if (!productExists) {
        existingWishlist.products.push(newProduct)

        delete existingWishlist.email
        updateWishlist({
          variables: {
            wishlist: {
              ...existingWishlist,
            },
          },
          refetchQueries: ['getWishlists'],
        })
          .then(() => {
            showToast('Successfully added to the Favouites List')
          })
          .catch((error) => {
            console.error('PUT request failed:', error)
          })
      } else {
        showToast('You have already added this product to the list')
      }
    }

    setCloseSelect(false)
    setErrorSelect('')
  }

  const addProductToFavouriteList = (selectedProduct, selectedWishList) => {
    const existingWishlist = listWishlist.find(
      (typeWish: { email: string; id: string | number }) =>
        typeWish.email === emailInfo && typeWish.id === selectedWishList
    )

    if (selectedProduct.bundle > 1)
      selectedProduct.quantityProduct *= selectedProduct.bundle
    if (existingWishlist) {
      const productExists = existingWishlist.products.some(
        (item: { ID: any }) => item.ID === selectedProduct.ID
      )

      if (!productExists) {
        existingWishlist.products.push(selectedProduct)

        const urlPut =
          '/api/dataentities/whitebird_my_wishlists_wishlist/documents?_schema=0.0.2-mywishlists'

        axios
          .put(urlPut, existingWishlist)
          .then(() => {
            showToast('Successfully added to the Favorites List')
          })
          .catch((error) => {
            console.error('PUT request failed:', error)
          })
      } else {
        showToast('You have already added this product to the list')
      }
    }
  }

  return {
    errorSelect,
    selectSize,
    selectRef,
    valueSelect,
    textSelect,
    closeSelect,
    captureValue,
    handleSelectFocus,
    handleSelectBlur,
    addToList,
    setCloseSelect,
    addProductToFavouriteList,
  }
}

export default useSelectWishlist

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useWishlists.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useRuntime } from 'vtex.render-runtime'
import { useOrderForm } from 'vtex.order-manager/OrderForm'
import useProduct from 'vtex.product-context/useProduct'

const useWishList = () => {
  const { navigate } = useRuntime()
  const { orderForm } = useOrderForm()
  const { product, selectedQuantity, selectedItem } = useProduct()

  const emailInfo = orderForm?.clientProfileData?.email
  const isLoggedIn =
    orderForm?.loggedIn ||
    (orderForm?.userType === 'CALL_CENTER_OPERATOR' && emailInfo != null)

  const nameProduct = product?.productName
  const linkProduct = product?.link
  const idProduct = Number(selectedItem?.itemId)
  const urlImageProduct = product?.items?.[0]?.images?.[0]?.imageUrl
  const quantityProduct = selectedQuantity
  const price = Number(product?.priceRange?.sellingPrice?.highPrice)
  const skuCodeReference = product?.items?.[0]?.referenceId?.[0]?.Value
  const departmentArray = product?.categoryTree
  const department = departmentArray?.[0]?.name

  return {
    navigate,
    emailInfo,
    isLoggedIn,
    nameProduct,
    linkProduct,
    idProduct,
    urlImageProduct,
    quantityProduct,
    price,
    skuCodeReference,
    department,
  }
}

export default useWishList

```


[System] You are an expert VTEX IO developer. You specialize 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/hooks/useCreateListAccount.jsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

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

const useCreateListAccount = () => {
  const [isModalAccountTable, setIsModalAccountTable] = useState(false)
  const [nameListAccountTable, setNameListAccountTable] = useState('')
  const [fieldValidationTable, setFieldValidationTable] = useState('')

  const [isModalAccount, setIsModalAccount] = useState(false)
  const [nameListAccount, setNameListAccount] = useState('')
  const [fieldValidation, setFieldValidation] = useState('')

  const buttonModalTable = () => {
    setIsModalAccountTable(true)
  }

  const buttonCloseModalTable = () => {
    setIsModalAccountTable(false)
  }

  const handleNameListTable = (event) => {
    const valueNameList = event.target.value

    setNameListAccountTable(valueNameList)
  }

  const buttonModal = () => {
    setIsModalAccount(true)
  }

  const buttonCloseModal = () => {
    setIsModalAccount(false)
  }

  const handleNameList = (event) => {
    const valueNameList = event.target.value

    setNameListAccount(valueNameList)
  }

  return {
    nameListAccountTable,
    isModalAccountTable,
    fieldValidationTable,
    isModalAccount,
    nameListAccount,
    fieldValidation,
    setNameListAccount,
    setFieldValidation,
    setIsModalAccount,
    buttonModal,
    buttonCloseModal,
    handleNameList,
    setFieldValidationTable,
    setNameListAccountTable,
    setIsModalAccountTable,
    buttonModalTable,
    buttonCloseModalTable,
    handleNameListTable,
  }
}

export default useCreateListAccount

```


[System] You are an expert VTEX IO developer. You specialize 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/globalStore/globalStore.js from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```javascript
import create from 'zustand'
import { devtools } from 'zustand/middleware'

const logMiddleware = (config) => (set, get, api) =>
  config(
    (args) => {
      set(args)
    },
    get,
    api
  )

const useStoreGlobal = create(
  devtools(
    logMiddleware((set) => ({
      selectedWishlist: null,
      isUpdatingQty: false,
      wishlists: [],
      wishlist: [],
      setSelectedWishlist: (wishlist) => {
        set({ selectedWishlist: wishlist })
      },
      setIsUpdatingQty: (updating) => set({ isUpdatingQty: updating }),
      setWishlist: (wishlistData) => set({ wishlist: wishlistData }),
      setWishlists: (wishlistsData) => {
        set({ wishlists: wishlistsData })
      },
      updatedProducts: [],
      setUpdatedProducts: (products) => set({ updatedProducts: products }),
    })),
    'Nombre-DevTools'
  )
)

export default useStoreGlobal

```


[System] You are an expert VTEX IO developer. You specialize 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/interfaces/index.ts from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface SelectWishList {
  isShowForm: boolean
  setIsShowForm: React.Dispatch<React.SetStateAction<boolean>>
  nameListWishlist: string
  handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void
  isButton: boolean
  isMessage: boolean
  isShowForm2: boolean
  handleAddList: () => void
  listTypeWishlist?: any
  emailInfo?: any
  handleSendData1: (e: React.FormEvent) => void
  handleSendData2: (e: React.FormEvent) => void
  showFormClick?: boolean
  clickCreate: boolean
  handleCloseModal?: () => void
  handleCreateLengthZero: () => void
  selectRef: any
  handleCaptureValue: (e: React.ChangeEvent<HTMLSelectElement>) => void
  selectSize: number
  handleSelectFocus: () => void
  handleSelectBlur: () => void
  handleAddToList: () => void
  closeSlect: boolean
  errorName: string
  errorSelect: string
  isLoading: boolean
}

export interface PropsModal {
  children: any
  blockClass: string
}

export interface AdminSetup {
  storeLogoUrl: string
  hasSchema: boolean
  schemaVersion: string
}

export interface AdminSettings {
  defaultTitleText: string
  imageName: string
  image: boolean
  imageRowWidth: number
  skuNameTitle: string
  skuName: boolean
  skuNameRowWidthAccount: number
  skuNameRowWidthShare: number
  departmentTitle: string
  department: boolean
  departmentRowWidth: number
  skuReferenceCodeTitle: string
  skuReferenceCode: boolean
  skuReferenceCodeRowWidth: number
  quantityTitle: string
  quantity: boolean
  quantityRowWidth: number
  unitValueTitle: string
  unitValue: boolean
  unitValueRowWidth: number
  totalValueTitle: string
  totalValue: boolean
  totalValueRowWidth: number
  notes: boolean
  addTitle: string
  add: boolean
  addRowWidth: number
  removeTitle: string
  remove: boolean
  adminSetup: AdminSetup
}

export interface PublicSettingsForApp {
  message: string
}

export interface WishlistMD {
  email: string
  wishlistType: string
  products: WishlistProduct[]
  isPublic: boolean
  fieldsConfig: any[]
}

export interface WishlistProduct {
  id: number
  image: string
  bundle: string | null
  department: string
  linkProduct: string
  nameProduct: string
  notes: string | null
  quantityProduct: number
  skuCodeReference: string
}

export interface ExtractedWishlistProductItem {
  id: number
  itemId: number
  image: string
  department: string
  skuReferenceCode: string
  name: string
  quantity: number
  linkProduct: string
  bundle: null | string
  notes: null | string
}

declare global {
  interface Window {
    dataLayer: 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/components/WishlistPrivacyOptions/index.jsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```jsx
import React, { useState } from 'react'

import copyToClipboard from '../../utils/copyToClipboard'
import styles from '../../styles.css'

export default function WishlistPrivacyOptions({
  selectedWishlist,
  wishlists,
  buttonLabel,
}) {
  const [textCopied, setTextCopied] = useState(false)

  const linkToCopy =
    typeof window !== 'undefined'
      ? `${window.location.host}/wishlist-share?id=${
          selectedWishlist || wishlists[0].id
        }`
      : ''

  return (
    <div className={`${styles.containerLinkShare} flex items-center`}>
      <button
        className={styles.wishlistCreateNew}
        onClick={() => copyToClipboard(linkToCopy, setTextCopied)}
        id="link_wishlist"
      >
        {buttonLabel}
      </button>
      {textCopied && (
        <p className={styles.popupCopy}>Link copied to clipboard!</p>
      )}
    </div>
  )
}

```


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

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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useCssHandles } from 'vtex.css-handles'
import { Button, ToastConsumer, ToastProvider } from 'vtex.styleguide'

import useGetWishlist from '../../hooks/useGetWishlists'
import useSelectWishlist from '../../hooks/useSelectWishlist'
import useWishList from '../../hooks/useWishlists'
import ModalWishList from '../modal'
import SelectWishlist from '../selectWishlists/selectWishlist'

const CSS_HANDLES = ['container', 'containerLoggedIn'] as const

const ButtonWishlist = () => {
  const { handles } = useCssHandles(CSS_HANDLES)
  const pathname = encodeURIComponent(window.location.pathname)
  const loginUrl = `/login?returnUrl=${pathname}`

  const {
    listWishlist,
    sendData1,
    sendData2,
    handleChange,
    addList,
    createLengthZero,
    isShowSelect,
    nameListWishlist,
    setIsShowSelect,
    isShowForm,
    setIsShowForm,
    isButton,
    isMessage,
    isShowForm2,
    clickCreate,
    errorName,
    isLoading,
  } = useGetWishlist()

  const { navigate, isLoggedIn, emailInfo } = useWishList()

  const {
    addToList,
    setCloseSelect,
    closeSelect,
    selectRef,
    selectSize,
    captureValue,
    handleSelectFocus,
    handleSelectBlur,
    errorSelect,
  } = useSelectWishlist()

  const handleFavoritesList = () => {
    setIsShowSelect(true)
    setCloseSelect(true)
  }

  return (
    <div className={`${handles.container}`}>
      {!isLoggedIn ? (
        <ToastProvider positioning="window">
          <ToastConsumer>
            {({ showToast }) => (
              <div className="flex">
                <div className="mr5">
                  <Button
                    size="small"
                    variation="secondary"
                    onClick={() =>
                      showToast({
                        message:
                          'You need to log in before adding it to the list',
                        action: {
                          label: 'LOG IN',
                          onClick: () =>
                            navigate({
                              to: loginUrl,
                            }),
                        },
                      })
                    }
                  >
                    Add to Favorites List
                  </Button>
                </div>
              </div>
            )}
          </ToastConsumer>
        </ToastProvider>
      ) : (
        <div className={`${handles.containerLoggedIn}`}>
          <Button
            size="small"
            variation="secondary"
            onClick={handleFavoritesList}
          >
            Add to Favorites List
          </Button>
          <div className={`${handles.containerLoggedIn} relative`}>
            <ModalWishList blockClass="vtex-select-or-create-wishlist">
              {isShowSelect && (
                <SelectWishlist
                  isButton={isButton}
                  isMessage={isMessage}
                  isShowForm={isShowForm}
                  listTypeWishlist={listWishlist}
                  setIsShowForm={setIsShowForm}
                  nameListWishlist={nameListWishlist}
                  handleChange={handleChange}
                  isShowForm2={isShowForm2}
                  emailInfo={emailInfo}
                  handleAddList={addList}
                  handleSendData1={sendData1}
                  handleSendData2={sendData2}
                  clickCreate={clickCreate}
                  handleCloseModal={() => setIsShowSelect(false)}
                  handleCreateLengthZero={createLengthZero}
                  selectRef={selectRef}
                  selectSize={selectSize}
                  handleCaptureValue={captureValue}
                  handleSelectFocus={handleSelectFocus}
                  handleSelectBlur={handleSelectBlur}
                  errorSelect={errorSelect}
                  handleAddToList={addToList}
                  closeSlect={closeSelect}
                  errorName={errorName}
                  isLoading={isLoading}
                />
              )}
            </ModalWishList>
          </div>
        </div>
      )}
    </div>
  )
}

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/components/ProductQuantity/index.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useRef, useState } from 'react'
import { useMutation } from 'react-apollo'
import { NumericStepper } from 'vtex.styleguide'

import { useProducts } from '../../context/ProductsContext'
import { useRow } from '../../context/RowContext'
import UPDATE_WISHLIST from '../../graphql/mutations/updateWishlist.gql'

export const ProductStepper = ({ wishlist: initialWishlist }) => {
  const { updateQuantity, row } = useRow()

  const [QTY, setQTY] = useState(row?.quantity ?? 0)
  const { updateQuantityBySkuReferenceCode } = useProducts()
  const wishlistRef = useRef(initialWishlist)
  const timeoutRef = useRef<number | null>(null)

  const [updateWishlist] = useMutation(UPDATE_WISHLIST)

  useEffect(() => {
    wishlistRef.current = initialWishlist
  }, [initialWishlist])

  const modifyProductQTY = (newValue: string, eventType: string) => {
    const quantity = Number(newValue)
    const roundedQuantity =
      eventType === 'change' && row.bundle
        ? Math.max(quantity - (quantity % row.bundle), row.bundle)
        : Math.max(row.bundle, quantity)

    const finalValue = roundedQuantity + (quantity - roundedQuantity)

    const updatedProducts = wishlistRef.current?.products?.map(
      (product: { skuCodeReference: string }) =>
        product.skuCodeReference === row.skuReferenceCode
          ? { ...product, quantityProduct: finalValue }
          : product
    )

    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current)
    }

    updateQuantity(finalValue)
    updateQuantityBySkuReferenceCode(row.skuReferenceCode, finalValue)
    setQTY(finalValue)
    timeoutRef.current = window.setTimeout(() => {
      updateWishlist({
        variables: {
          wishlist: {
            id: wishlistRef.current.id,
            products: updatedProducts,
            isPublic: true,
            wishlistType: wishlistRef.current.wishlistType,
          },
        },
      }).catch((error: unknown) => {
        console.error('Error updating products:', error)
      })
    }, 700)
  }

  useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current)
      }
    }
  }, [])

  return (
    <NumericStepper
      value={QTY}
      size="small"
      onChange={(e: { value: string; type: string }) => {
        modifyProductQTY(e.value, e.type)
      }}
    />
  )
}

```


[System] You are an expert VTEX IO developer. You specialize 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/SearchSKU/AutocompleteBlock.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FunctionComponent } from 'react'
import React, { useState } from 'react'
import type { WrappedComponentProps } from 'react-intl'
import { injectIntl } from 'react-intl'
import { Button, Tag, IconClear } from 'vtex.styleguide'
import PropTypes from 'prop-types'
import { useApolloClient } from 'react-apollo'
import { Item, Product } from 'vtex.product-context/react/ProductTypes'

import QuickOrderAutocomplete from './QuickOrderAutocomplete'
import productQuery from '../../queries/product.gql'
import handles from '../../styles.css'

interface SelectedProps {
  label: string
  seller?: string
  slug: string
  thumb?: string
  value: string
  data?: { product: Product }
  product?: Product
}

const AutocompleteBlock: FunctionComponent<any & WrappedComponentProps> = ({
  text,
  description,
  componentOnly,
  onAddToWishlist,
}) => {
  const client = useApolloClient()
  const [state, setState] = useState<{
    selectedItem: SelectedProps | null
    quantitySelected: number
    unitMultiplier: number
  }>({
    selectedItem: null,
    quantitySelected: 1,
    unitMultiplier: 1,
  })

  const clear = () => {
    setState({
      ...state,
      selectedItem: null,
      quantitySelected: 1,
      unitMultiplier: 1,
    })
  }

  const { selectedItem } = state

  const onSelect = async (product: any) => {
    if (!!product && product.length) {
      const query = {
        query: productQuery,
        variables: { slug: product[0].slug },
      }

      const response = await client.query(query)

      const { data } = response
      const selectedSku =
        data.product.items.length === 1 ? data.product.items[0].itemId : null

      const seller = selectedSku
        ? data.product.items[0].sellers.find(
            (item: { sellerDefault: boolean }) => {
              return item.sellerDefault === true
            }
          ).sellerId
        : null

      let multiplier = 1

      if (data.product.items.length === 1) {
        multiplier = data.product.items[0].unitMultiplier
      }

      setState({
        ...state,
        selectedItem:
          !!product && product.length
            ? { ...product[0], value: selectedSku, seller, data }
            : null,
        unitMultiplier: multiplier,
        quantitySelected: multiplier,
      })
    }

    return true
  }

  const selectSku = (value: string) => {
    const seller = selectedItem?.data?.product?.items
      .find((item: { itemId: string }) => {
        return item?.itemId === value
      })
      ?.sellers?.find((s: { sellerDefault: boolean }) => {
        return s.sellerDefault === true
      })?.sellerId

    const newSelected = {
      label: selectedItem?.label ?? '',
      slug: selectedItem?.slug ?? '',
      ...selectedItem,
      seller,
      value,
    }

    const matchedItem = selectedItem?.data?.product.items.find(
      (item: { itemId: string }) => item.itemId === value
    )

    setState({
      ...state,
      selectedItem: newSelected,
      unitMultiplier: matchedItem?.unitMultiplier ?? 1,
      quantitySelected: matchedItem?.unitMultiplier ?? 1,
    })
  }

  const thumb = (url: string) => {
    return url.replace('25-25', `50-50`)
  }

  const onAddToFavoritesList = async () => {
    const result = await onAddToWishlist(selectedItem)

    if (result) {
      clear()
    }
  }

  return (
    <div className={`${handles.addSkuContainer}`}>
      {!componentOnly && (
        <div className={`${handles.textContainer} w-third-l w-100-ns fl-l`}>
          <h2
            className={`${handles.textContainerTitle} t-heading-3 mb3 ml5 ml3-ns mt4`}
          >
            {text}
          </h2>
          <div
            className={`${handles.textContainerDescription} t-body lh-copy c-muted-1 mb7 ml3 false`}
          >
            {description}
          </div>
        </div>
      )}
      <div
        className={`${handles.componentContainer} ${!componentOnly ? '' : ''}`}
      >
        <div className="w-100">
          <div
            className={`bg-base t-body c-on-base pa7 br3 b--muted-4 ${handles.componentContainerHelper}`}
          >
            <div className={handles.quickOrderAutocomplete}>
              {!selectedItem && <QuickOrderAutocomplete onSelect={onSelect} />}
            </div>
            {!!selectedItem && (
              <div
                className={`flex flex-row ${handles.quickOrderAutocompleteItemsWrapper}`}
              >
                <div
                  className={`w-two-thirds-l w-100-ns fl-l flex ${handles.quickOrderAutocomplete}`}
                >
                  <div
                    className={`flex flex-row ${handles.quickOrderAutocompleteItems}`}
                  >
                    <div
                      className={`flex flex-column w-15 fl ${handles.productThumb}`}
                    >
                      <img
                        src={thumb(selectedItem?.thumb ?? '')}
                        width="50"
                        height="50"
                        alt=""
                      />
                    </div>
                    <div
                      className={`flex flex-row w-85 fl ${handles.productLabel}`}
                    >
                      <span className={`${handles.productTitle}`}>
                        {selectedItem.label}
                      </span>
                      <div
                        className={`flex flex-column fl h-50 ${handles.addToFavouritebutton}`}
                      >
                        <Button
                          variation="primary"
                          size="small"
                          onClick={onAddToFavoritesList}
                        >
                          Add to Favourite List
                        </Button>
                      </div>
                    </div>
                  </div>
                  {(selectedItem?.data?.product?.items ?? [])?.length > 1 && (
                    <div className={`${handles.productSku} flex flex-row`}>
                      {selectedItem.data?.product.items.map((item: Item) => {
                        return (
                          <span
                            key={item.itemId}
                            className={`${handles.skuSelection} ${item.itemId === selectedItem.value && handles.skuSelected} mr4
                            `}
                          >
                            <Tag
                              size="small"
                              bgColor={
                                item.itemId === selectedItem.value
                                  ? '#8bc34a'
                                  : '#979899'
                              }
                              onClick={() => {
                                selectSku(item.itemId)
                              }}
                            >
                              {item.name}
                            </Tag>
                          </span>
                        )
                      })}
                    </div>
                  )}
                </div>
                <div
                  className={`w-third-l w-100-ns fr-l flex-row-l ${handles.buttonClearWrapper}`}
                >
                  <div
                    className={`flex flex-column w-100 fl ${handles.buttonClear}`}
                  >
                    <Button
                      variation="tertiary"
                      size="medium"
                      onClick={() => {
                        clear()
                      }}
                    >
                      <IconClear
                        onClick={() => {
                          clear()
                        }}
                      />
                    </Button>
                  </div>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  )
}

AutocompleteBlock.propTypes = {
  componentOnly: PropTypes.bool,
  text: PropTypes.string,
  description: PropTypes.string,
  onAddToWishlist: PropTypes.func,
}

export default injectIntl(AutocompleteBlock)

```


[System] You are an expert VTEX IO developer. You specialize 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/SearchSKU/index.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import PropTypes from 'prop-types'

import styles from '../../styles.css'

interface Item {
  productId: string
  items: Array<{
    images: Array<{
      imageUrl: string
      imageText: string
    }>
    referenceId: Array<{ Value: string }>
  }>
}

const SearchSKU = ({
  valueSearchSku,
  changeValueSku,
  getSearchProduct,
  isShowProductSearch,
  searchProduct,
}) => {
  return (
    <div className={styles.wishlistSearchSKUContainer}>
      <label htmlFor="searchInputWishlist">Search SKU</label>
      <input
        id="searchInputWishlist"
        type="text"
        value={valueSearchSku}
        onChange={changeValueSku}
      />
      <button onClick={getSearchProduct}>Buscar</button>

      {isShowProductSearch && (
        <div>
          {searchProduct.map((item: Item) => (
            <div
              key={item.productId}
              id={item.productId}
              style={{ display: 'flex', flexDirection: 'row' }}
            >
              <img
                src={item.items[0].images[0].imageUrl}
                alt={item.items[0].images[0].imageText}
                width={50}
                height={50}
              />
              <p>{item.items[0].referenceId[0].Value}</p>
            </div>
          ))}
        </div>
      )}
    </div>
  )
}

SearchSKU.propTypes = {
  valueSearchSku: PropTypes.string,
  isShowProductSearch: PropTypes.bool,
  searchProduct: PropTypes.array,
  changeValueSku: PropTypes.func,
  getSearchProduct: PropTypes.func,
}

export default SearchSKU

```


[System] You are an expert VTEX IO developer. You specialize 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/SearchSKU/QuickOrderAutocomplete.tsx from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { FunctionComponent } from 'react'
import React, { useState, useRef } from 'react'
import { AutocompleteInput } from 'vtex.styleguide'
import PropTypes from 'prop-types'
import type { WrappedComponentProps } from 'react-intl'
import { injectIntl, IntlShape } from 'react-intl'
import { useApolloClient } from 'react-apollo'
import { useCssHandles } from 'vtex.css-handles'

import { SearchIcon } from '../Icons'
import autocomplete from '../../queries/autocomplete.gql'
import styles from './searchSKU.css'

const getImageSrc = (img: string) => {
  const td = img.split('/')
  const ids = td[td.indexOf('ids') + 1]

  return img.replace(ids, `${ids}-50-50`)
}

interface Item {
  items: any
}

const CustomOption = (props: any) => {
  const { roundedBottom, searchTerm, value, selected, onClick } = props
  const [highlightOption, setHighlightOption] = useState(false)
  const CSS_HANDLES = [
    'customOptionButton',
    'imageThumbContainer',
    'imageThumb',
    'searchTextPreviewWrapper',
  ] as const

  const { handles } = useCssHandles(CSS_HANDLES)
  const renderOptionHighlightedText = () => {
    const highlightableText = typeof value === 'string' ? value : value.label
    const index: number = highlightableText
      .toLowerCase()
      .indexOf(searchTerm.toLowerCase())

    if (index === -1) {
      return highlightableText
    }

    const prefix = highlightableText.substring(0, index)
    const match = highlightableText.substr(index, searchTerm.length)
    const suffix = highlightableText.substring(
      index + parseInt(match.length, 10)
    )

    return (
      <span className="truncate">
        <span className="fw7">{prefix}</span>
        {match}
        <span className="fw7">{suffix}</span>
      </span>
    )
  }

  const buttonClasses = `
    ${handles.customOptionButton}
    ${roundedBottom ? 'br2 br--bottom' : ''}
    ${highlightOption || selected ? 'bg-muted-5' : 'bg-base'}
    bn w-100 tl pointer pa4 f6
  `

  const thumb = value.thumb ? value.thumb : ''

  return (
    <button
      className={buttonClasses}
      onFocus={() => setHighlightOption(true)}
      onMouseEnter={() => setHighlightOption(true)}
      onMouseLeave={() => setHighlightOption(false)}
      onClick={onClick}
    >
      <div className="flex items-center">
        {thumb && (
          <span
            className={`${handles.imageThumbContainer} mr3 c-muted-2 flex pt1`}
          >
            <img className={`${handles.imageThumb}`} src={thumb} alt="" />
          </span>
        )}
        <div className={`${handles.searchTextPreviewWrapper}`}>
          <span className="pr2">{renderOptionHighlightedText()}</span>
          {typeof value !== 'string' && (
            <div className="t-mini c-muted-1">{value.caption}</div>
          )}
        </div>
      </div>
    </button>
  )
}

interface QuickOrderAutocompleteInt {
  onSelect: any
}
const QuickOrderAutocomplete: FunctionComponent<
  WrappedComponentProps & QuickOrderAutocompleteInt
> = ({
  onSelect,
  intl,
}: {
  onSelect: (...args: any) => void
  intl: IntlShape
}) => {
  const client = useApolloClient()
  const [optionsResult, setOptions] = useState([])
  const [term, setTerm] = useState('')
  const [loading, setLoading] = useState(false)
  const [lastSearched, setLastSearched] = useState([])
  const timeoutRef: any = useRef(null)

  const handleSearch = async ({ value }: { value: string }) => {
    if (value.length > 1) {
      const { data } = await client.query({
        query: autocomplete,
        variables: { inputValue: value },
      })

      setOptions(
        !!data &&
          !!data.productSuggestions &&
          !!data.productSuggestions.products
          ? data.productSuggestions.products
          : []
      )
    }
  }

  const renderOptionRender = (props: any) => <CustomOption {...props} />

  const options = {
    onSelect: (...args: any) => {
      onSelect(args)
    },
    loading,
    value: !term.length
      ? []
      : optionsResult
          .filter((item: Item) => {
            return !!item.items[0].images[0].imageUrl
          })
          .map((item: any) => {
            return {
              value: item.items[0].itemId,
              label: item.productName,
              slug: item.linkText,
              thumb: getImageSrc(item.items[0].images[0].imageUrl),
            }
          }),
    lastSearched: {
      value: lastSearched,
      label: 'Last searched products',
      onChange: (option: never) =>
        option && setLastSearched([...new Set([...lastSearched, option])]),
    },
    // --- This is what makes the custom option work!
    renderOption: renderOptionRender,
  }

  const input = {
    onChange: (nterm: string) => {
      if (nterm) {
        setLoading(true)
        if (timeoutRef.current) {
          clearTimeout(timeoutRef.current)
        }

        timeoutRef.current = setTimeout(() => {
          setLoading(false)
          setTerm(nterm)
          handleSearch({ value: nterm })
          timeoutRef.current = null
        }, 1000)
      } else {
        setTerm(nterm)
      }
    },
    onClear: () => setTerm(''),
    placeholder: intl.formatMessage({
      id: 'store/favorite-list.search-product-by-sku',
    }),
    value: term,
  }

  return (
    <div className={`${styles.autocompleteInputWrapper}`}>
      <AutocompleteInput input={input} options={options} />
      <SearchIcon />
    </div>
  )
}

QuickOrderAutocomplete.propTypes = {
  onSelect: PropTypes.func,
}
export default injectIntl(QuickOrderAutocomplete)

```


[System] You are an expert VTEX IO developer. You specialize 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/SearchSKU/searchSKU.css from the wish-list-v2 VTEX app.

[Assistant]
Here's the implementation:

```css
.autocompleteInputWrapper {
  display: flex;
  align-items: center;
  border-radius: 5px;
  border: 2px solid #E3E4E6;
  height: 38px;
}

.autocompleteInputWrapper label div {
  border-radius: 0 !important;
  border-top: none;
  border-bottom: none;
  border-left: none;
  height: auto;
}

.autocompleteInputWrapper label div:focus {
  outline: none;
}

.autocompleteInputWrapper :global(.vtex-styleguide-9-x-noAppearance) {
  border: none;
  border-radius: 0;
}

.autocompleteInputWrapper :global(.vtex-styleguide-9-x-noAppearance):focus {
  outline: none;
}

.autocompleteInputWrapper svg{
  padding: 0 0.5rem;
}

.imageThumb {
  width: 2.5rem;
  height: 2.5rem;
  min-width: 2.5rem;
  object-fit: none;
}

.searchTextPreviewWrapper {
  overflow: hidden;
  text-overflow: ellipsis;
}
```