[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 list-wallet/react/provider/providerStore.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React, { useEffect, useState } from 'react'
import { useLazyQuery, useMutation, useQuery } from 'react-apollo'
import { useIntl } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'

import { provider, historyMessages } from '../utils/definedMessages'
import updateGiftCard from '../queries/updateGiftCard.gql'
import getValueTotalList from '../queries/getValueTotalList.gql'
import getRouteRedemptionCode from '../queries/getRouteRedemptionCode.gql'
import getValueGiftCard from '../queries/getValueGiftCard.gql'
import getValueAlreadyInGiftCard from '../queries/getValueAlreadyInGiftCard.gql'
import getRouteHistory from '../queries/getRouteHistory.gql'
import { ShowAlertOptions } from '../utils/showAlertOptions'
import { ContextStore } from '../hooks/useStore'

const ProviderStore: FC = (props) => {
  const intl = useIntl()
  const { culture } = useRuntime()
  const [rescue, setRescue] = useState(0)
  const [button, setButton] = useState(false)
  const [addValueGiftCard, setAddValueGiftCard] = useState<string>()
  const [validation, setValidation] = useState('')
  const [valueGiftCard, setValueGiftCard] = useState(0)
  const [code, setCode] = useState(intl.formatMessage(provider.withoutCode))
  const [showAlert, setShowAlert] = useState(ShowAlertOptions.notShow)
  const [credit, setCredit] = useState(0)
  const [history, setHistory] = useState<TableHistory[]>([])
  const [loading, setLoading] = useState(false)
  const [loadingCode, setLoadingCode] = useState(false)
  const [isGiftCardFieldInvalid, setIsGiftCardFieldInvalid] = useState(false)
  const [loadingGiftCard, setLoadingGiftCard] = useState(false)
  const [loadingRedemptionCode, setLoadingRedemptionCode] = useState(false)
  const [loadingCredit, setLoadingCredit] = useState(false)
  const [loadingHistory, setLoadingHistory] = useState(false)
  const [filterHistory, setFilterHistory] = useState<FilterHistory>()

  const [updateGiftCardMutation] = useMutation(updateGiftCard)
  const { data: dataValueTotalList } = useQuery(getValueTotalList)

  const {
    data: dataRedemptionCode,
    refetch: refetchGetRedemptionCode,
    loading: loadingRedemptionCodeRoute,
  } = useQuery(getRouteRedemptionCode, {
    fetchPolicy: 'cache-and-network',
  })

  const {
    data: dataGetValueGiftCard,
    refetch: refetchGetValueGiftCard,
    loading: loadingValueGiftCard,
  } = useQuery(getValueGiftCard, {
    fetchPolicy: 'cache-and-network',
  })

  const {
    data: dataGetValueAlreadyInGiftCard,
    refetch: refetchValueAlreadyInGiftCard,
    loading: loadingValueAlreadyInGiftCard,
  } = useQuery(getValueAlreadyInGiftCard, {
    fetchPolicy: 'cache-and-network',
  })

  const [
    searchHistory,
    {
      data: dataGetRouteHistory,
      refetch: refetchGetRouteHistory,
      loading: loadingGetRouteHistory,
    },
  ] = useLazyQuery(getRouteHistory, {
    fetchPolicy: 'cache-and-network',
  })

  useEffect(() => {
    setLoadingGiftCard(loadingValueGiftCard)
  }, [loadingValueGiftCard])

  useEffect(() => {
    setLoadingCredit(loadingValueAlreadyInGiftCard)
  }, [loadingValueAlreadyInGiftCard])

  useEffect(() => {
    setLoadingRedemptionCode(loadingRedemptionCodeRoute)
  }, [loadingRedemptionCodeRoute])

  useEffect(() => {
    setLoadingHistory(loadingHistory)
  }, [loadingHistory])

  useEffect(() => {
    searchHistory({ variables: { filters: filterHistory } })
  }, [filterHistory])

  useEffect(() => {
    const giftCard = dataGetValueAlreadyInGiftCard?.getValueAlreadyInGiftCard
    let list = dataValueTotalList?.getValueTotalList

    if (giftCard !== undefined && list !== undefined) {
      list /= 100
      setCredit(Number((list - giftCard).toFixed(2)))
    }
  }, [dataGetValueAlreadyInGiftCard, dataGetValueGiftCard, dataValueTotalList])

  useEffect(() => {
    const redemptionCode = dataRedemptionCode?.getRouteRedemptionCode

    if (redemptionCode !== 'failed' && redemptionCode !== undefined) {
      setCode(redemptionCode)
    }
  }, [dataRedemptionCode])

  useEffect(() => {
    const value = dataGetValueGiftCard?.getValueGiftCard

    if (value !== undefined) {
      setValueGiftCard(value)
    }
  }, [dataGetValueGiftCard])

  useEffect(() => {
    const getHistory = dataGetRouteHistory?.getRouteHistory

    if (
      getHistory === undefined ||
      (getHistory.length === 1 && getHistory[0].value === null)
    ) {
      return
    }

    let tableHistory: TableHistory[] = []
    const options = {
      timeZone: 'UTC',
      year: 'numeric' as const,
      month: 'short' as const,
      day: 'numeric' as const,
    }

    tableHistory = getHistory.map(
      (item: { value: number; dateAndTime: string }) => {
        return {
          value:
            (culture.customCurrencySymbol as string) +
            Math.abs(item.value / 100).toLocaleString(culture.locale, {
              minimumFractionDigits: 2,
            }),
          description:
            item.value > 0
              ? intl.formatMessage(historyMessages.creditDescription)
              : intl.formatMessage(historyMessages.debitDescription),
          dateAndTime: new Date(item.dateAndTime).toLocaleString(
            culture.locale,
            options
          ),
          status: item.value > 0,
        }
      }
    )
    setHistory(tableHistory.reverse())
  }, [dataGetRouteHistory, loadingGetRouteHistory])

  const handleCloseAlert = () => {
    setShowAlert(ShowAlertOptions.notShow)
  }

  function validationValue() {
    if (addValueGiftCard === undefined) {
      setValidation(intl.formatMessage(provider.missingValue))
      setIsGiftCardFieldInvalid(true)

      return false
    }

    if (parseFloat(addValueGiftCard) <= 0) {
      setValidation(intl.formatMessage(provider.negativeValue))
      setIsGiftCardFieldInvalid(true)

      return false
    }

    if (parseFloat(addValueGiftCard) > credit) {
      setValidation(
        intl.formatMessage(provider.biggerThanCouldBe) +
          credit.toLocaleString(culture.locale, { minimumFractionDigits: 2 })
      )
      setIsGiftCardFieldInvalid(true)

      return false
    }

    setIsGiftCardFieldInvalid(false)

    return true
  }

  async function updateGiftCardFunction() {
    setLoading(true)
    setShowAlert(ShowAlertOptions.notShow)
    const valid = validationValue()

    if (valid) {
      const { data } = await updateGiftCardMutation({
        variables: {
          value: parseFloat(addValueGiftCard as string),
        },
      })

      if (data.updateGiftCard === 'success') {
        if (code === intl.formatMessage(provider.withoutCode)) {
          const interval = setInterval(async () => {
            const updateGetRedemptionCode = await refetchGetRedemptionCode()
            const updateGetValueGiftCard = await refetchGetValueGiftCard()
            const updateValueAlreadyInGiftCard =
              await refetchValueAlreadyInGiftCard()

            if (
              updateGetRedemptionCode?.data?.getRouteRedemptionCode !==
                'failed' &&
              updateGetValueGiftCard?.data?.getValueGiftCard > 0 &&
              updateValueAlreadyInGiftCard?.data?.getValueAlreadyInGiftCard > 0
            ) {
              clearInterval(interval)

              setRescue(parseFloat(addValueGiftCard as string))
              setShowAlert(ShowAlertOptions.alertSave)
              setAddValueGiftCard('0')
              setLoading(false)
            }
          }, 2000)

          return
        }

        refetchGetValueGiftCard()
        refetchValueAlreadyInGiftCard()
        setRescue(parseFloat(addValueGiftCard as string))
        setShowAlert(ShowAlertOptions.alertSave)
        setAddValueGiftCard('0')
        refetchGetRouteHistory()
      } else {
        setShowAlert(ShowAlertOptions.alertError)
      }

      setLoading(false)

      return
    }

    setLoading(false)
  }

  function copyCode() {
    setLoadingCode(true)
    setShowAlert(ShowAlertOptions.notShow)

    if (code === intl.formatMessage(provider.withoutCode)) {
      setShowAlert(ShowAlertOptions.alertWithoutCode)
      setLoadingCode(false)

      return
    }

    if (!navigator.clipboard) {
      setShowAlert(ShowAlertOptions.alertCopyError)
      setLoadingCode(false)

      return
    }

    navigator.clipboard.writeText(code)
    setShowAlert(ShowAlertOptions.alertCopySuccess)
    setLoadingCode(false)
  }

  return (
    <ContextStore.Provider
      value={{
        button,
        setButton,
        valueGiftCard,
        code,
        addValueGiftCard,
        setAddValueGiftCard,
        updateGiftCardFunction,
        validation,
        setValidation,
        showAlert,
        setShowAlert,
        handleCloseAlert,
        credit,
        history,
        copyCode,
        loading,
        loadingCode,
        rescue,
        isGiftCardFieldInvalid,
        setIsGiftCardFieldInvalid,
        loadingGiftCard,
        loadingCredit,
        loadingRedemptionCode,
        loadingHistory,
        loadingGetRouteHistory,
        setFilterHistory,
      }}
    >
      {props.children}
    </ContextStore.Provider>
  )
}

export default ProviderStore

```


[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 list-wallet/react/utils/definedMessages.ts from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { defineMessages } from 'react-intl'

export const input = defineMessages({
  valueTooltip: { id: 'input.value.tooltip' },
  valueLabel: { id: 'input.value.label' },
  valueButton: { id: 'input.value.button' },
  codePlaceholder: { id: 'input.code.placeholder' },
  codeLabel: { id: 'input.code.label' },
  codeButton: { id: 'input.code.button' },
  tooltip: { id: 'input.tooltip' },
  loading: { id: 'input.code.loading' },
})

export const historyMessages = defineMessages({
  openHistory: { id: 'history.open.button' },
  emptyHistoryTitle: { id: 'history.empty.title' },
  emptyHistoryMessage: { id: 'history.empty.message' },
  creditDescription: { id: 'history.credit.description' },
  debitDescription: { id: 'history.debit.description' },
  dateTitle: { id: 'history.date.title' },
  descriptionTitle: { id: 'history.description.title' },
  valueTitle: { id: 'history.value.title' },
  statusTitle: { id: 'history.status.title' },
  creditStatus: { id: 'history.credit.status' },
  debitStatus: { id: 'history.debit.status' },
  paginationOf: { id: 'history.pagination.of' },
  filterClear: { id: 'history.filter.clear' },
  filterAll: { id: 'history.filter.all' },
  filterIs: { id: 'history.filter.is' },
  filterBetween: { id: 'history.filter.between' },
  filterAnd: { id: 'history.filter.and' },
  filterDate: { id: 'history.filter.date' },
  filterStatus: { id: 'history.filter.status' },
  filterStatusCredit: { id: 'history.filter.status.credit' },
  filterStatusDebit: { id: 'history.filter.status.debit' },
})

export const titles = defineMessages({
  valueGiftCard: { id: 'titles.value.gift.card' },
  redemption: { id: 'titles.redemption' },
  credit: { id: 'titles.credit' },
})

export const collapsible = defineMessages({
  title: { id: 'collapsible.title' },
})

export const provider = defineMessages({
  withoutCode: { id: 'provider.without.code' },
  negativeValue: { id: 'provider.value.negative' },
  biggerThanCouldBe: { id: 'provider.value.bigger.than.could.be' },
  missingValue: { id: 'provider.missing.value' },
})

export const toast = defineMessages({
  rescueValue: { id: 'toast.rescue.value' },
  rescueSucess: { id: 'toast.rescue.sucess' },
  rescueError: { id: 'toast.rescue.error' },
  code: { id: 'toast.code' },
  copy: { id: 'toast.copy' },
  copyError: { id: 'toast.copy.error' },
  withoutCode: { id: 'toast.without.code' },
})

```


[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 list-wallet/react/utils/showAlertOptions.ts from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const enum ShowAlertOptions {
  notShow = 0,
  alertSave = 1,
  alertError = 2,
  alertCopySuccess = 3,
  alertCopyError = 4,
  alertWithoutCode = 5,
}

```


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

[User] Show me the implementation of list-wallet/react/Components/inputButtonArea.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React from 'react'
import { useIntl } from 'react-intl'
import IntlCurrencyInput from 'react-intl-currency-input'
import { Tooltip, IconInfo, Button, Input } from 'vtex.styleguide'
import { useRuntime } from 'vtex.render-runtime'

import { useStore } from '../hooks/useStore'
import '../styles.global.css'
import { input } from '../utils/definedMessages'
import ValidationArea from './validationsArea'

const InputButtonArea: FC = () => {
  const intl = useIntl()

  const { culture } = useRuntime()
  const {
    code,
    updateGiftCardFunction,
    setAddValueGiftCard,
    copyCode,
    setValidation,
    loading,
    loadingCode,
    addValueGiftCard,
    isGiftCardFieldInvalid,
    setIsGiftCardFieldInvalid,
    loadingRedemptionCode,
  } = useStore()

  function submitFunctionValueButton(e: React.MouseEvent<HTMLButtonElement>) {
    e.preventDefault()
    updateGiftCardFunction()
  }

  function submitFunctionCodeButton(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault()
    copyCode()
  }

  const currencyConfig = {
    locale: culture.locale,
    formats: {
      number: {
        currency: {
          style: 'currency',
          currency: culture.currency,
          minimumFractionDigits: 2,
          maximumFractionDigits: 2,
        },
      },
    },
  }

  const handleBlur = (
    event: React.FormEvent<HTMLFormElement>,
    value: string
  ) => {
    event.preventDefault()
    setAddValueGiftCard(value)
  }

  const handleFocus = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault()
    setValidation('')
    if (isGiftCardFieldInvalid) setIsGiftCardFieldInvalid(false)
  }

  return (
    <>
      <div className="mb3 width-input mt5 inputs t-body mw9 rescue">
        <div>
          {intl.formatMessage(input.valueLabel)}
          <Tooltip label={intl.formatMessage(input.valueTooltip)}>
            <span className="c-on-base pointer ml2 mt2">
              <IconInfo />
            </span>
          </Tooltip>
        </div>
        <div className="w-100">
          <div className="desktop-or-mobile rescue">
            <div className="lh-copy w-100">
              <label className="vtex-input w-100">
                <div
                  className={`vtex-input-prefix__group flex flex-row items-stretch overflow-hidden br2 bw1 b--solid b--muted-4 hover-b--muted-3 h-large ${
                    isGiftCardFieldInvalid ? 'border-red' : ''
                  }`}
                >
                  <IntlCurrencyInput
                    defaultValue={parseFloat(addValueGiftCard as string)}
                    currency="currency"
                    config={currencyConfig}
                    onFocus={handleFocus}
                    onBlur={handleBlur}
                    className="vtex-styleguide-9-x-input ma0 border-box vtex-styleguide-9-x-hideDecorators vtex-styleguide-9-x-noAppearance br2 bl-0 br--right   w-100 bn outline-0 bg-base c-on-base b--muted-4 hover-b--muted-3 t-body pr5 "
                    disabled={loading}
                    data-testid="intl-currency-input"
                  />
                </div>
              </label>
            </div>
            <div className="ml2 mt2">
              <Button
                onClick={submitFunctionValueButton}
                isLoading={loading}
                testId="button-input-currency"
              >
                {intl.formatMessage(input.valueButton)}
              </Button>
            </div>
          </div>
          <ValidationArea />
        </div>
      </div>
      <div className="mb3 mt7 width-input inputs t-body mw9 rescue">
        <div>
          {intl.formatMessage(input.codeLabel)}
          <Tooltip label={intl.formatMessage(input.tooltip)}>
            <span className="c-on-base pointer ml2 mt2">
              <IconInfo />
            </span>
          </Tooltip>
        </div>
        <div className="w-100">
          <div className="desktop-or-mobile rescue">
            <div className="lh-copy w-100">
              <Input
                value={
                  loadingRedemptionCode
                    ? intl.formatMessage(input.loading)
                    : code
                }
                placeholder={intl.formatMessage(input.codePlaceholder)}
                readOnly={true}
                size="large"
                testId="input-test-id"
              />
            </div>
            <div className="ml2 mt2">
              <Button
                onClick={submitFunctionCodeButton}
                isLoading={loadingCode}
                testId="button-input"
              >
                {intl.formatMessage(input.codeButton)}
              </Button>
            </div>
          </div>
        </div>
      </div>
    </>
  )
}

export default InputButtonArea

```


[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 list-wallet/react/Components/validationsArea.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React from 'react'

import { useStore } from '../hooks/useStore'

const ValidationArea: FC = () => {
  const { validation } = useStore()

  return (
    <div>
      <p className="mt2" style={{ color: 'red', fontSize: '12px' }}>
        {validation}
      </p>
    </div>
  )
}

export default ValidationArea

```


[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 list-wallet/react/Components/titlesArea.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React from 'react'
import { useIntl } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'
import { Divider, Spinner } from 'vtex.styleguide'

import { useStore } from '../hooks/useStore'
import '../styles.global.css'
import { titles } from '../utils/definedMessages'
import History from './history'

const TitlesArea: FC = () => {
  const { culture } = useRuntime()

  const intl = useIntl()

  const { valueGiftCard, credit, loadingGiftCard, loadingCredit } = useStore()

  return (
    <div className="mt5 mb6">
      <div className="text-align-center">
        <div className="mb5 t-heading-4">
          {intl.formatMessage(titles.credit)}
          <b className="money">
            {`${culture.customCurrencySymbol} `}
            {loadingCredit ? (
              <Spinner color="currentColor" size={20} />
            ) : (
              credit.toLocaleString(culture.locale, {
                minimumFractionDigits: 2,
              })
            )}
          </b>
          <History />
        </div>
        <div className="mb5 t-heading-4">
          {intl.formatMessage(titles.valueGiftCard)}
          <b className="money">
            {`${culture.customCurrencySymbol} `}
            {loadingGiftCard ? (
              <Spinner color="currentColor" size={20} />
            ) : (
              valueGiftCard.toLocaleString(culture.locale, {
                minimumFractionDigits: 2,
              })
            )}
          </b>
        </div>
        <div className="width-divider center">
          <Divider />
        </div>
        <div className="mt5 t-heading-4">
          {intl.formatMessage(titles.redemption)}
        </div>
      </div>
    </div>
  )
}

export default TitlesArea

```


[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 list-wallet/react/Components/toastArea.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React, { useEffect } from 'react'
import { useIntl } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'

import success from '../assets/toast-success.svg'
import error from '../assets/toast-error.svg'
import { useStore } from '../hooks/useStore'
import '../styles.global.css'
import { ShowAlertOptions } from '../utils/showAlertOptions'
import { toast } from '../utils/definedMessages'

interface Props {
  duration?: number
}

const ToastArea: FC<Props> = ({ duration = 3000 }) => {
  const intl = useIntl()

  const { culture } = useRuntime()

  const { showAlert, setShowAlert, rescue, code } = useStore()

  interface AlertInfo {
    className: string
    imageSrc: string
    message: React.ReactFragment
  }

  const dictionary: { [key: number]: AlertInfo } = {
    1: {
      className: 'notification bg-color-sucess toast bottom-left',
      imageSrc: success,
      message: (
        <>
          <p className="notification-title">
            {`${
              intl.formatMessage(toast.rescueValue) +
              (culture.customCurrencySymbol as string)
            } ${rescue.toLocaleString(culture.locale, {
              minimumFractionDigits: 2,
            })}`}
          </p>
          <p className="notification-message">
            {intl.formatMessage(toast.rescueSucess)}
          </p>
        </>
      ),
    },
    2: {
      className: 'notification bg-color-error toast bottom-left',
      imageSrc: error,
      message: (
        <p className="notification-middle">
          {intl.formatMessage(toast.rescueError)}
        </p>
      ),
    },
    3: {
      className: 'notification bg-color-sucess toast bottom-left',
      imageSrc: success,
      message: (
        <>
          <p className="notification-title">
            {intl.formatMessage(toast.code) + code}
          </p>
          <p className="notification-message">
            {intl.formatMessage(toast.copy)}
          </p>
        </>
      ),
    },
    4: {
      className: 'notification bg-color-error toast bottom-left',
      imageSrc: error,
      message: (
        <p className="notification-middle">
          {intl.formatMessage(toast.copyError)}
        </p>
      ),
    },
    5: {
      className: 'notification bg-color-error toast bottom-left',
      imageSrc: error,
      message: (
        <p className="notification-middle">
          {intl.formatMessage(toast.withoutCode)}
        </p>
      ),
    },
  }

  const alertInfo = dictionary[showAlert]

  function changeValueShowAlert() {
    if (showAlert !== ShowAlertOptions.notShow) {
      setShowAlert(ShowAlertOptions.notShow)
    }
  }

  useEffect(() => {
    const interval = setInterval(changeValueShowAlert, duration)

    return () => {
      clearInterval(interval)
    }
  }, [showAlert])

  if (showAlert !== ShowAlertOptions.notShow) {
    return (
      <div className={`notification-container bottom-left`}>
        <div className={alertInfo.className}>
          <div className="notification-image">
            <img src={alertInfo.imageSrc} alt="" />
          </div>
          <div>{alertInfo.message}</div>
        </div>
      </div>
    )
  }

  return null
}

export default ToastArea

```


[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 list-wallet/react/Components/historyTable.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React, { useState, useEffect } from 'react'
import { useIntl } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'
import { Table, Tag, DatePicker, Dropdown } from 'vtex.styleguide'

import { useStore } from '../hooks/useStore'
import { historyMessages } from '../utils/definedMessages'

const TABLE_LENGTH = 5
const INITIAL_PAGE = 1
const ITEM_FROM = 1
const ITEM_TO = 5

const HistoryTable: FC = () => {
  const { culture } = useRuntime()

  const intl = useIntl()
  const { history, setFilterHistory, loadingGetRouteHistory } = useStore()

  const [tableOrder, setTableOrder] = useState({
    orderedItems: history,
    dataSort: {
      sortedBy: 'dateAndTime',
      sortOrder: 'DESC',
    },
  })

  const options = [
    { value: 'all', label: intl.formatMessage(historyMessages.filterAll) },
    {
      value: 'deposits',
      label: intl.formatMessage(historyMessages.filterStatusCredit),
    },
    {
      value: 'withdrawals',
      label: intl.formatMessage(historyMessages.filterStatusDebit),
    },
  ]

  const [tablePage, setTablePage] = useState({
    tableLength: TABLE_LENGTH,
    currentPage: INITIAL_PAGE,
    slicedData: tableOrder.orderedItems.slice(0, 5),
    currentItemFrom: ITEM_FROM,
    currentItemTo: ITEM_TO,
    itemsLength: tableOrder.orderedItems.length,
    filterStatements: [],
  })

  useEffect(() => {
    setTablePage({
      tableLength: TABLE_LENGTH,
      currentPage: INITIAL_PAGE,
      slicedData: tableOrder.orderedItems.slice(0, 5),
      currentItemFrom: ITEM_FROM,
      currentItemTo: ITEM_TO,
      itemsLength: tableOrder.orderedItems.length,
      filterStatements: tablePage.filterStatements,
    })
  }, [tableOrder])

  useEffect(() => {
    setTableOrder({
      orderedItems: history,
      dataSort: {
        sortedBy: 'dateAndTime',
        sortOrder: 'DESC',
      },
    })
  }, [history])

  const handleSort = ({
    sortOrder,
    sortedBy,
  }: {
    sortOrder: string
    sortedBy: string
  }) => {
    if (sortedBy === 'dateAndTime') {
      const orderedItems = tableOrder.orderedItems.reverse()

      setTableOrder({
        orderedItems,
        dataSort: {
          sortedBy,
          sortOrder,
        },
      })
    }
  }

  const goToPage = (
    currentPage: number,
    currentItemFrom: number,
    currentItemTo: number,
    slicedData: TableHistory[]
  ) => {
    setTablePage({
      tableLength: tablePage.tableLength,
      currentPage,
      slicedData,
      currentItemFrom,
      currentItemTo,
      itemsLength: tablePage.itemsLength,
      filterStatements: tablePage.filterStatements,
    })
  }

  const handleNextClick = () => {
    const newPage = tablePage.currentPage + 1
    const itemFrom = tablePage.currentItemTo + 1
    const itemTo = tablePage.tableLength * newPage
    const data = tableOrder.orderedItems.slice(itemFrom - 1, itemTo)

    goToPage(newPage, itemFrom, itemTo, data)
  }

  const handlePrevClick = () => {
    if (tablePage.currentPage === 0) return
    const newPage = tablePage.currentPage - 1
    const itemFrom = tablePage.currentItemFrom - tablePage.tableLength
    const itemTo = tablePage.currentItemFrom - 1
    const data = tableOrder.orderedItems.slice(itemFrom - 1, itemTo)

    goToPage(newPage, itemFrom, itemTo, data)
  }

  const DatePickerObject = ({
    value,
    onChange,
  }: {
    value: any
    onChange: any
  }) => {
    return (
      <div className="w-100">
        <DatePicker
          value={value || new Date()}
          onChange={(date: any) => {
            onChange(date)
          }}
          locale={culture.locale}
          positionFixed
        />
      </div>
    )
  }

  const DatePickerRangeObject = ({
    value,
    onChange,
  }: {
    value: any
    onChange: any
  }) => {
    return (
      <div className="flex flex-column w-100">
        <DatePicker
          value={value?.from || new Date(Date.now() - 86400000)}
          onChange={(date: any) => {
            const dateFrom = { from: date, to: value?.to }

            onChange(dateFrom)
          }}
          locale={culture.locale}
          maxDate={value?.to || new Date()}
          positionFixed
        />
        <br />
        <DatePicker
          value={value?.to || new Date()}
          onChange={(date: any) => {
            const dateTo = { from: value?.from, to: date }

            onChange(dateTo)
          }}
          locale={culture.locale}
          minDate={value?.from || new Date(Date.now() - 86400000)}
          maxDate={new Date()}
          positionFixed
        />
        <br />
      </div>
    )
  }

  const StatusSelectorObject = ({
    value,
    onChange,
  }: {
    value: any
    onChange: any
  }) => {
    return (
      <div>
        <Dropdown
          label={intl.formatMessage(historyMessages.filterStatus)}
          size="small"
          options={options}
          value={value}
          onChange={(_: any, v: any) => {
            onChange(v)
          }}
        />
      </div>
    )
  }

  const handleFiltersChange = async (statements: any) => {
    if (statements.length === 0) {
      setFilterHistory(undefined)
    } else {
      let status
      let dateAndTime

      await statements.forEach((filters: any) => {
        if (filters.subject === 'status') {
          if (filters.object === 'deposits') {
            status = true
          } else if (filters.object === 'withdrawals') {
            status = false
          }
        }

        if (filters.subject === 'date' && filters.verb === '=') {
          const start = new Date(
            new Date(filters.object).setHours(0, 0, 0, 0)
          ).toISOString()

          const end = new Date(
            new Date(filters.object).setHours(23, 59, 59, 9)
          ).toISOString()

          dateAndTime = { startDate: start, endDate: end }
        } else if (filters.subject === 'date' && filters.verb === 'between') {
          const start = new Date(
            new Date(filters.object?.from ?? Date.now() - 86400000).setHours(
              0,
              0,
              0,
              0
            )
          ).toISOString()

          const end = new Date(
            new Date(filters.object?.to ?? Date.now()).setHours(23, 59, 59, 9)
          ).toISOString()

          dateAndTime = { startDate: start, endDate: end }
        }
      })

      setFilterHistory({ status, dateAndTime })
    }

    setTablePage({
      tableLength: TABLE_LENGTH,
      currentPage: INITIAL_PAGE,
      slicedData: tableOrder.orderedItems.slice(0, 5),
      currentItemFrom: ITEM_FROM,
      currentItemTo: ITEM_TO,
      itemsLength: tableOrder.orderedItems.length,
      filterStatements: statements,
    })
  }

  const defaultSchema = {
    properties: {
      dateAndTime: {
        title: intl.formatMessage(historyMessages.dateTitle),
        minWidth: 80,
        width: 180,
        sortable: true,
      },
      description: {
        title: intl.formatMessage(historyMessages.descriptionTitle),
        width: 300,
        minWidth: 280,
      },
      value: {
        title: intl.formatMessage(historyMessages.valueTitle),
        width: 100,
      },
      status: {
        title: intl.formatMessage(historyMessages.statusTitle),
        minWidth: 80,
        width: 170,
        cellRenderer: ({ cellData }: { cellData: boolean }) => {
          return (
            <Tag type={cellData ? 'success' : 'error'}>
              <span className="nowrap">
                {cellData
                  ? intl.formatMessage(historyMessages.creditStatus)
                  : intl.formatMessage(historyMessages.debitStatus)}
              </span>
            </Tag>
          )
        },
      },
    },
  }

  return (
    <div className="mb5 mt5">
      <Table
        fullWidth
        schema={defaultSchema}
        items={tablePage.slicedData}
        density="low"
        loading={loadingGetRouteHistory}
        emptyStateLabel={intl.formatMessage(historyMessages.emptyHistoryTitle)}
        emptyStateChildren={
          <p>{intl.formatMessage(historyMessages.emptyHistoryMessage)}</p>
        }
        onSort={handleSort}
        sort={{
          sortedBy: tableOrder.dataSort.sortedBy,
          sortOrder: tableOrder.dataSort.sortOrder,
        }}
        pagination={{
          onNextClick: handleNextClick,
          onPrevClick: handlePrevClick,
          currentItemFrom: tablePage.currentItemFrom,
          currentItemTo: tablePage.currentItemTo,
          textOf: intl.formatMessage(historyMessages.paginationOf),
          totalItems: tablePage.itemsLength,
        }}
        filters={{
          alwaysVisibleFilters: ['date', 'status'],
          statements: tablePage.filterStatements,
          onChangeStatements: handleFiltersChange,
          clearAllFiltersButtonLabel: intl.formatMessage(
            historyMessages.filterClear
          ),
          collapseLeft: true,
          options: {
            date: {
              label: intl.formatMessage(historyMessages.filterDate),
              renderFilterLabel: (st: {
                object: { from: any; to: any } | any
                verb: string
              }) => {
                if (!st || !st.object) {
                  return intl.formatMessage(historyMessages.filterAll)
                }

                return `${
                  st.verb === 'between'
                    ? `${intl.formatMessage(
                        historyMessages.filterBetween
                      )} ${new Date(
                        st.object.from
                      ).toLocaleDateString()} ${intl.formatMessage(
                        historyMessages.filterAnd
                      )} ${new Date(st.object.to).toLocaleDateString()}`
                    : `${intl.formatMessage(
                        historyMessages.filterIs
                      )} ${new Date(st.object).toLocaleDateString()}`
                }`
              },
              verbs: [
                {
                  label: intl.formatMessage(historyMessages.filterIs),
                  value: '=',
                  object: (props: any) => <DatePickerObject {...props} />,
                },
                {
                  label: intl.formatMessage(historyMessages.filterBetween),
                  value: 'between',
                  object: (props: any) => <DatePickerRangeObject {...props} />,
                },
              ],
            },
            status: {
              label: intl.formatMessage(historyMessages.filterStatus),
              renderFilterLabel: (st: any) => {
                if (!st || !st.object) {
                  return intl.formatMessage(historyMessages.filterAll)
                }

                const retorno = options.find(
                  (filter) => filter.value === st.object
                )

                return retorno?.label
              },
              verbs: [
                {
                  value: 'includes',
                  object: (props: any) => <StatusSelectorObject {...props} />,
                },
              ],
            },
          },
        }}
      />
    </div>
  )
}

export default HistoryTable

```


[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 list-wallet/react/Components/history.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React, { useState } from 'react'
import { useIntl } from 'react-intl'
import { Spinner, Button, Modal } from 'vtex.styleguide'

import { useStore } from '../hooks/useStore'
import HistoryTable from './historyTable'
import { historyMessages } from '../utils/definedMessages'

const History: FC = () => {
  const intl = useIntl()
  const [modalOpen, setModalOpen] = useState(false)
  const { loadingHistory, setFilterHistory } = useStore()

  const handleToggle = () => {
    setFilterHistory(undefined)
    setModalOpen(!modalOpen)
  }

  return (
    <span className="ml3 history">
      {loadingHistory ? (
        <Spinner color="currentColor" size={20} />
      ) : (
        <Button
          variation="tertiary"
          size="small"
          onClick={() => handleToggle()}
        >
          {intl.formatMessage(historyMessages.openHistory)}
        </Button>
      )}
      <Modal
        centered
        isOpen={modalOpen}
        onClose={handleToggle}
        title={intl.formatMessage(historyMessages.openHistory)}
      >
        <HistoryTable />
      </Modal>
    </span>
  )
}

export default History

```


[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 list-wallet/react/Components/collapsibleArea.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FC } from 'react'
import React from 'react'
import { useIntl } from 'react-intl'
import { Collapsible } from 'vtex.styleguide'

import { useStore } from '../hooks/useStore'
import '../styles.global.css'
import { collapsible } from '../utils/definedMessages'
import InputButtonArea from './inputButtonArea'
import TitlesArea from './titlesArea'
import ToastArea from './toastArea'

const CollapsibleArea: FC = () => {
  const { setButton, button } = useStore()

  const intl = useIntl()

  return (
    <div className="w-80 center">
      <div className="mb5 mt5">
        <Collapsible
          header={
            <h1 className="t-heading-2">
              {intl.formatMessage(collapsible.title)}
            </h1>
          }
          onClick={() => setButton(!button)}
          isOpen={button}
          align="right"
          arrowAlign="center"
        >
          <div style={{ position: 'relative' }}>
            <TitlesArea />
            <InputButtonArea />
          </div>
        </Collapsible>
        <ToastArea />
      </div>
    </div>
  )
}

export default CollapsibleArea

```


[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 list-wallet/react/__tests__/toastArea.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { wait } from '@apollo/react-testing'
import { render } from '@vtex/test-tools/react'
import React from 'react'

import ToastArea from '../Components/toastArea'
import { ContextStore } from '../hooks/useStore'
import { ShowAlertOptions } from '../utils/showAlertOptions'
// eslint-disable-next-line jest/no-mocks-import
import { values } from '../__mocks__/values'

describe('Toast Area', () => {
  it('should render success Alert if showAlert = 0', async () => {
    const showAlert = { showAlert: ShowAlertOptions.notShow }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea />
      </ContextStore.Provider>
    )

    expect(container.firstChild).toBeNull()
  })

  it('should render success Alert if showAlert = 1', async () => {
    const showAlert = { showAlert: ShowAlertOptions.alertSave }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea />
      </ContextStore.Provider>
    )

    expect(container?.firstChild?.firstChild).toHaveClass('bg-color-sucess')
  })

  it('should render error Alert if showAlert = 2', async () => {
    const showAlert = { showAlert: ShowAlertOptions.alertError }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea />
      </ContextStore.Provider>
    )

    expect(container?.firstChild?.firstChild).toHaveClass('bg-color-error')
  })

  it('should render success Alert if showAlert = 3', async () => {
    const showAlert = { showAlert: ShowAlertOptions.alertCopySuccess }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea />
      </ContextStore.Provider>
    )

    expect(container?.firstChild?.firstChild).toHaveClass('bg-color-sucess')
  })

  it('should render error Alert if showAlert = 4', async () => {
    const showAlert = { showAlert: ShowAlertOptions.alertCopyError }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea />
      </ContextStore.Provider>
    )

    expect(container?.firstChild?.firstChild).toHaveClass('bg-color-error')
  })

  it('should render error Alert if showAlert = 5', async () => {
    const showAlert = { showAlert: ShowAlertOptions.alertWithoutCode }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea />
      </ContextStore.Provider>
    )

    expect(container?.firstChild?.firstChild).toHaveClass('bg-color-error')
  })

  it('should set ShowAlertOptions to notShow when finalize the timer', async () => {
    const showAlert = { showAlert: ShowAlertOptions.alertCopyError }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...showAlert }}>
        <ToastArea duration={1} />
      </ContextStore.Provider>
    )

    expect(container?.firstChild?.firstChild).toHaveClass('bg-color-error')

    await wait(1)

    expect(values.setShowAlert).toHaveBeenCalled()
  })
})

```


[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 list-wallet/react/__tests__/inputButtonArea.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable jest/no-mocks-import */
import { fireEvent, render } from '@vtex/test-tools/react'
import React from 'react'

import InputButtonArea from '../Components/inputButtonArea'
import { ContextStore } from '../hooks/useStore'
import { values } from '../__mocks__/values'

describe('Input Button Area', () => {
  it('should render the first InputButtonArea', async () => {
    const { getByTestId } = render(
      <ContextStore.Provider value={values}>
        <InputButtonArea />
      </ContextStore.Provider>
    )

    const input = getByTestId('intl-currency-input')

    expect(input).toContainHTML('input')
  })
  it('should render the second InputButtonArea', async () => {
    const { getByTestId } = render(
      <ContextStore.Provider value={values}>
        <InputButtonArea />
      </ContextStore.Provider>
    )

    const input = getByTestId('input-test-id')

    expect(input).toContainHTML('input')
  })

  it('should call onBlur value', async () => {
    const { getByTestId } = render(
      <ContextStore.Provider value={values}>
        <InputButtonArea />
      </ContextStore.Provider>
    )

    const inputCurrency = getByTestId('intl-currency-input') as HTMLInputElement

    fireEvent.blur(inputCurrency as HTMLInputElement)

    expect(values.setAddValueGiftCard).toHaveBeenCalled()
  })

  it('should call onFocus', async () => {
    const { getByTestId } = render(
      <ContextStore.Provider value={values}>
        <InputButtonArea />
      </ContextStore.Provider>
    )

    const inputCurrency = getByTestId('intl-currency-input') as HTMLInputElement

    fireEvent.focus(inputCurrency as HTMLInputElement)

    expect(values.setValidation).toHaveBeenCalled()
    expect(values.setIsGiftCardFieldInvalid).toHaveBeenCalled()
  })

  it('should click on first button', async () => {
    const { getByTestId } = render(
      <ContextStore.Provider value={values}>
        <InputButtonArea />
      </ContextStore.Provider>
    )

    const buttonPointer = getByTestId('button-input-currency')

    fireEvent.click(buttonPointer as HTMLButtonElement)

    expect(values.updateGiftCardFunction).toHaveBeenCalled()
  })

  it('should click on second button', async () => {
    const { getByTestId } = render(
      <ContextStore.Provider value={values}>
        <InputButtonArea />
      </ContextStore.Provider>
    )

    const buttonPointer = getByTestId('button-input')

    fireEvent.click(buttonPointer)

    expect(values.copyCode).toHaveBeenCalled()
  })
})

```


[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 list-wallet/react/__tests__/history.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

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

import { ContextStore } from '../hooks/useStore'
// eslint-disable-next-line jest/no-mocks-import
import { values } from '../__mocks__/values'
import History from '../Components/history'

window.matchMedia =
  window.matchMedia ||
  function () {
    return {
      matches: false,
      addListener() {},
      removeListener() {},
    }
  }

describe('Hisotry Area', () => {
  it('should render the history area', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <History />
      </ContextStore.Provider>
    )

    expect(container).not.toBeNull()
  })

  it('should render the spinner when are loading', async () => {
    const loadingHistory = { loadingHistory: true }

    const { container } = render(
      <ContextStore.Provider value={{ ...values, ...loadingHistory }}>
        <History />
      </ContextStore.Provider>
    )

    const spinner = container.querySelectorAll('svg')[0]

    expect(spinner).toHaveClass('vtex__icon-spinner')
  })

  it('should click on button and open the modal', async () => {
    const onClick = jest.fn()

    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <History />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')[0]

    button.onclick = onClick()

    fireEvent.click(button)

    expect(onClick).toHaveBeenCalled()
  })
})

```


[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 list-wallet/react/__tests__/validationsArea.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { render } from '@vtex/test-tools/react'
import React from 'react'

import { ContextStore } from '../hooks/useStore'
// eslint-disable-next-line jest/no-mocks-import
import { values } from '../__mocks__/values'
import ValidationArea from '../Components/validationsArea'

describe('Validation Area', () => {
  it('should render the validation area', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <ValidationArea />
      </ContextStore.Provider>
    )

    expect(container).not.toBeNull()
  })

  it('should contain text validations', async () => {
    const { getByText } = render(
      <ContextStore.Provider value={{ ...values }}>
        <ValidationArea />
      </ContextStore.Provider>
    )

    const validation = getByText('text validations')

    expect(validation).not.toBeNull()
  })
})

```


[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 list-wallet/react/__tests__/historyTable.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { act, fireEvent, render } from '@vtex/test-tools/react'
import React from 'react'
import { wait } from '@apollo/react-testing'

import HistoryTable from '../Components/historyTable'
import { ContextStore } from '../hooks/useStore'
// eslint-disable-next-line jest/no-mocks-import
import { values } from '../__mocks__/values'

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(), // Deprecated
    removeListener: jest.fn(), // Deprecated
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
})

describe('History Table Area', () => {
  it('should render the history table', async () => {
    const { container } = render(
      <ContextStore.Provider value={values}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    expect(container.firstChild).not.toBeNull()
  })

  it('should render and click on previous page button', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    fireEvent.click(button[4])
    fireEvent.click(button[3])
    expect(container.firstChild).not.toBeNull()
  })

  it('should render and click on next page button', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    fireEvent.click(button[4])
    expect(container.firstChild).not.toBeNull()
  })

  it('should render the status area and change the status filter to deposits', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    fireEvent.click(button[1])

    const buttonApply = container.querySelectorAll('button')[2]

    const select = container.querySelectorAll('select')[0] as HTMLSelectElement

    expect(select.value).toStrictEqual('')

    select.value = select.options[2].value // <-- select a new value

    fireEvent.change(select)

    fireEvent.click(buttonApply)

    expect(select.value).toStrictEqual('deposits')
  })

  it('should render the status area and change the status filter to withdrawals', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    fireEvent.click(button[1])

    const buttonApply = container.querySelectorAll('button')[2]

    const select = container.querySelectorAll('select')[0] as HTMLSelectElement

    expect(select.value).toStrictEqual('')

    select.value = select.options[3].value // <-- select a new value

    fireEvent.change(select)

    await act(async () => {
      await wait(0)
      fireEvent.click(buttonApply)
    })

    expect(select.value).toStrictEqual('withdrawals')
  })

  it('should render the date picker area and change the date filter', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    fireEvent.click(button[0])

    const input = container.querySelectorAll('input')

    await act(async () => {
      await wait(0)
      fireEvent.change(input[1], { target: { value: '29/06/2022' } })
    })

    const buttonApply = container.querySelectorAll('button')[1]

    fireEvent.click(buttonApply)

    expect(input[1]).toHaveValue('29/06/2022')
  })

  it('should render the date picker range area and change the date filter', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    await act(async () => {
      await wait(0)
      fireEvent.click(button[0])
    })

    const div = container?.querySelectorAll(
      'div.css-1pcexqc-container.pointer.bw1.t-body'
    )[0] as any

    const reactHandlerKey = Object.keys(div).filter(function (item) {
      return item.indexOf('__reactEventHandlers') >= 0
    })

    div[reactHandlerKey[0]].children[1].props.selectProps.onMenuOpen()

    await wait(0)

    const openMenu = container.querySelectorAll('div.css-h54wua-menu')[0]

    const between = openMenu.querySelectorAll('div')[3]

    await act(async () => {
      await wait(0)
      between.click()
    })

    const input = container.querySelectorAll('input')

    await act(async () => {
      await wait(0)
      fireEvent.change(input[1], { target: { value: '29/06/2022' } })
      fireEvent.change(input[2], { target: { value: '29/07/2022' } })
    })

    const buttonApply = container.querySelectorAll('button')[1]

    await act(async () => {
      await wait(0)
      fireEvent.click(buttonApply)
    })

    expect(input[1]).toHaveValue('29/06/2022')
    expect(input[2]).toHaveValue('29/07/2022')
  })

  it('should render the date picker range area and remove the filter after', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <HistoryTable />
      </ContextStore.Provider>
    )

    const button = container.querySelectorAll('button')

    await act(async () => {
      await wait(0)
      fireEvent.click(button[0])
    })

    const div = container?.querySelectorAll(
      'div.css-1pcexqc-container.pointer.bw1.t-body'
    )[0] as any

    const reactHandlerKey = Object.keys(div).filter(function (item) {
      return item.indexOf('__reactEventHandlers') >= 0
    })

    div[reactHandlerKey[0]].children[1].props.selectProps.onMenuOpen()

    await wait(0)

    const openMenu = container.querySelectorAll('div.css-h54wua-menu')[0]

    const between = openMenu.querySelectorAll('div')[3]

    await act(async () => {
      await wait(0)
      between.click()
    })

    const input = container.querySelectorAll('input')

    await act(async () => {
      await wait(0)
      fireEvent.change(input[1], { target: { value: '29/06/2022' } })
      fireEvent.change(input[2], { target: { value: '29/07/2022' } })
    })

    const buttonApply = container.querySelectorAll('button')[1]

    await act(async () => {
      await wait(0)
      fireEvent.click(buttonApply)
    })

    await act(async () => {
      await wait(0)
      fireEvent.change(input[1], { target: { value: '' } })
      fireEvent.change(input[2], { target: { value: '29/07/2022' } })
    })

    const buttonRemoveFilter = container.querySelectorAll(
      'button.vtex-button.bw1.ba.fw5.v-mid.relative.pa0.lh-solid.br2.min-h-small.t-action--small.bg-transparent.b--transparent.c-action-primary.hover-b--transparent.hover-bg-action-secondary.hover-b--action-secondary.pointer'
    )[0] as HTMLButtonElement

    await act(async () => {
      await wait(0)
      buttonRemoveFilter.click()
    })

    const buttonRemoveFilterAfter = container.querySelectorAll(
      'button.vtex-button.bw1.ba.fw5.v-mid.relative.pa0.lh-solid.br2.min-h-small.t-action--small.bg-transparent.b--transparent.c-action-primary.hover-b--transparent.hover-bg-action-secondary.hover-b--action-secondary.pointer'
    )[0] as HTMLButtonElement

    expect(buttonRemoveFilterAfter).toBeUndefined()
  })
})

```


[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 list-wallet/react/__tests__/collasibleArea.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

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

import CollapsibleArea from '../Components/collapsibleArea'
import { ContextStore } from '../hooks/useStore'
// eslint-disable-next-line jest/no-mocks-import
import { values } from '../__mocks__/values'

describe('Collapsible Area', () => {
  it('should render InputArea if name is name', async () => {
    const { container } = render(
      <ContextStore.Provider value={values}>
        <CollapsibleArea />
      </ContextStore.Provider>
    )

    expect(container.firstChild).not.toBeNull()
  })

  it('should click', async () => {
    const onClick = jest.fn()

    const { container } = render(
      <ContextStore.Provider value={values}>
        <CollapsibleArea />
      </ContextStore.Provider>
    )

    const buttonPointer = container.getElementsByClassName('pointer')

    const button = buttonPointer[0] as HTMLButtonElement

    button.onclick = onClick()

    fireEvent.click(button)

    expect(onClick).toHaveBeenCalled()
  })
})

```


[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 list-wallet/react/__tests__/providerStore.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable jest/no-mocks-import */
/* eslint-disable import/order */
import { act, fireEvent, render, waitFor } from '@vtex/test-tools/react'
import React from 'react'
import { MockedProvider, wait } from '@apollo/react-testing'
import * as reactapollo from 'react-apollo'
import {
  mocks,
  mocksUpdateReturnError,
  mocksUpdate,
  mocksErrorCode,
  mocksUpdateWithoutCode,
} from '../__mocks__/mockUseQuery'
import ProviderStore from '../provider/providerStore'
import { ContextStore } from '../hooks/useStore'
import { ShowAlertOptions } from '../utils/showAlertOptions'

describe('Provider', () => {
  it('should render provider', async () => {
    const { container } = render(
      <MockedProvider mocks={mocks} addTypename={false}>
        <ProviderStore />
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
    })

    expect(container).not.toBeNull()
  })

  it('should test function handleCloseAlert', async () => {
    const TestComponent = () => {
      const { handleCloseAlert, showAlert } = React.useContext(ContextStore)

      return (
        <>
          <div data-testid="showAlert">{showAlert}</div>
          <button onClick={handleCloseAlert} data-testid="buttonShowAlert">
            SetShowAlert
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocks} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      getByTestId('buttonShowAlert').click()
    })

    const showAlertValue = getByTestId('showAlert').textContent

    expect(showAlertValue).toBe('0')
  })

  it('should test function validateIfAllFieldsIsComplete failed if I dont send a addValueGiftCard', async () => {
    const TestComponent = () => {
      const { validation, updateGiftCardFunction, isGiftCardFieldInvalid } =
        React.useContext(ContextStore)

      return (
        <>
          <div data-testid="validateText">{validation}</div>
          <div data-testid="fieldInvalid">
            {isGiftCardFieldInvalid.toString()}
          </div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocks} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('buttonUpdate'))
    })

    await wait(0)

    const validateText = getByTestId('validateText').textContent
    const invalidField = getByTestId('fieldInvalid').textContent

    expect(validateText).not.toBeNull()
    expect(invalidField).toBe('true')
  })

  it('should test function validateIfAllFieldsIsComplete failed if I send a addValueGiftCard <= 0', async () => {
    const TestComponent = () => {
      const {
        validation,
        updateGiftCardFunction,
        setAddValueGiftCard,
        isGiftCardFieldInvalid,
      } = React.useContext(ContextStore)

      return (
        <>
          <button
            data-testid="addValue"
            onClick={() => setAddValueGiftCard('-2')}
          >
            add
          </button>
          <div data-testid="fieldInvalid">
            {isGiftCardFieldInvalid.toString()}
          </div>
          <div data-testid="validateText">{validation}</div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocks} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('addValue'))
      fireEvent.click(getByTestId('buttonUpdate'))
    })

    const validateText = getByTestId('validateText').textContent
    const invalidField = getByTestId('fieldInvalid').textContent

    expect(validateText).not.toBeNull()
    expect(invalidField).toBe('true')
  })

  it('should test function validateIfAllFieldsIsComplete failed if I send a addValueGiftCard > credit', async () => {
    const TestComponent = () => {
      const {
        validation,
        updateGiftCardFunction,
        setAddValueGiftCard,
        isGiftCardFieldInvalid,
      } = React.useContext(ContextStore)

      return (
        <>
          <button
            data-testid="addValue"
            onClick={() => setAddValueGiftCard('6')}
          >
            add
          </button>
          <div data-testid="fieldInvalid">
            {isGiftCardFieldInvalid.toString()}
          </div>
          <div data-testid="validateText">{validation}</div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocks} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('addValue'))
      fireEvent.click(getByTestId('buttonUpdate'))
    })

    const validateText = getByTestId('validateText').textContent
    const invalidField = getByTestId('fieldInvalid').textContent

    expect(validateText).not.toBeNull()
    expect(invalidField).toBe('true')
  })

  it('should test function validateIfAllFieldsIsComplete sucess if I send a addValueGiftCard valid', async () => {
    jest.mock('react-apollo')
    jest
      .spyOn(reactapollo, 'useLazyQuery')
      .mockImplementation()
      .mockReturnValue([
        jest.fn(),
        {
          data: {
            getRouteHistory: [
              {
                value: 10,
                dateAndTime: '2022-09-08T00:00:00Z',
              },
            ],
          },
          refetch: jest.fn(),
        },
      ] as any)

    const TestComponents = () => {
      const {
        validation,
        updateGiftCardFunction,
        setAddValueGiftCard,
        isGiftCardFieldInvalid,
      } = React.useContext(ContextStore)

      return (
        <>
          <button
            data-testid="addValue"
            onClick={() => setAddValueGiftCard('5')}
          >
            add
          </button>
          <div data-testid="fieldInvalid">
            {isGiftCardFieldInvalid.toString()}
          </div>
          <div data-testid="validateText">{validation}</div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksUpdate} addTypename={false}>
        <ProviderStore>
          <TestComponents />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('addValue'))
      fireEvent.click(getByTestId('buttonUpdate'))
    })

    const validationValue = getByTestId('validateText').textContent
    const invalidField = getByTestId('fieldInvalid').textContent

    await act(async () => {
      await wait(0)
    })

    expect(validationValue).toStrictEqual('')
    expect(invalidField).toBe('false')
  })

  it('should test function update if I send a addValueGiftCard valid and the return of mutation is a sucess', async () => {
    const TestComponent = () => {
      const {
        showAlert,
        updateGiftCardFunction,
        setAddValueGiftCard,
        rescue,
        addValueGiftCard,
      } = React.useContext(ContextStore)

      return (
        <>
          <button
            data-testid="addValue"
            onClick={() => setAddValueGiftCard('5')}
          >
            add
          </button>
          <div data-testid="alert">{showAlert}</div>
          <div data-testid="rescue">{rescue}</div>
          <div data-testid="valueGiftCard">{addValueGiftCard}</div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksUpdate} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('addValue'))
      fireEvent.click(getByTestId('buttonUpdate'))
    })

    const alertValue = getByTestId('alert')
    const rescueValue = getByTestId('rescue')
    const valueGiftCardValue = getByTestId('valueGiftCard')

    waitFor(() => {
      expect(alertValue).toHaveTextContent(
        ShowAlertOptions.alertSave.toString()
      )
      expect(rescueValue).toHaveTextContent('5')
      expect(valueGiftCardValue).toHaveTextContent('0')
    })
  })

  it('should test function update if I send a addValueGiftCard valid and the return of mutation is a failed', async () => {
    const TestComponent = () => {
      const { showAlert, updateGiftCardFunction, setAddValueGiftCard } =
        React.useContext(ContextStore)

      return (
        <>
          <button
            data-testid="addValue"
            onClick={() => setAddValueGiftCard('5')}
          >
            add
          </button>
          <div data-testid="alert">{showAlert}</div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksUpdateReturnError} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('addValue'))
      fireEvent.click(getByTestId('buttonUpdate'))
    })

    const alertValue = getByTestId('alert')

    waitFor(() => {
      expect(alertValue).toHaveTextContent(
        ShowAlertOptions.alertError.toString()
      )
    })
  })

  it('should test function copyCode return error if a send a invalid navigator', async () => {
    const TestComponent = () => {
      const { showAlert, copyCode } = React.useContext(ContextStore)

      return (
        <>
          <button data-testid="copy" onClick={() => copyCode()}>
            copy
          </button>
          <div data-testid="alert">{showAlert}</div>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksUpdateReturnError} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('copy'))
    })

    const alertValue = getByTestId('alert')

    waitFor(() => {
      expect(alertValue).toHaveTextContent(
        ShowAlertOptions.alertCopyError.toString()
      )
    })
  })

  it('should test function copyCode return error if dont have a valid code', async () => {
    const TestComponent = () => {
      const { showAlert, copyCode } = React.useContext(ContextStore)

      return (
        <>
          <button data-testid="copy" onClick={() => copyCode()}>
            copy
          </button>
          <div data-testid="alert">{showAlert}</div>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksErrorCode} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    const alertValue = getByTestId('alert')

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('copy'))
    })

    expect(alertValue).toHaveTextContent(
      ShowAlertOptions.alertWithoutCode.toString()
    )
  })

  it('should test function copyCode return success if a send a valid navigator', async () => {
    Object.defineProperty(navigator, 'clipboard', {
      value: {
        writeText: () => {},
      },
    })

    const TestComponent = () => {
      const { showAlert, copyCode } = React.useContext(ContextStore)

      return (
        <>
          <button data-testid="copy" onClick={() => copyCode()}>
            copy
          </button>
          <div data-testid="alert">{showAlert}</div>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksUpdateReturnError} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('copy'))
    })

    const alertValue = getByTestId('alert')

    waitFor(() => {
      expect(alertValue).toHaveTextContent(
        ShowAlertOptions.alertCopySuccess.toString()
      )
    })
  })

  it('should test function update if I send a addValueGiftCard valid but the code is invalid', async () => {
    const TestComponent = () => {
      const {
        showAlert,
        updateGiftCardFunction,
        setAddValueGiftCard,
        rescue,
        addValueGiftCard,
      } = React.useContext(ContextStore)

      return (
        <>
          <button
            data-testid="addValue"
            onClick={() => setAddValueGiftCard('5')}
          >
            add
          </button>
          <div data-testid="alert">{showAlert}</div>
          <div data-testid="rescue">{rescue}</div>
          <div data-testid="valueGiftCard">{addValueGiftCard}</div>
          <button data-testid="buttonUpdate" onClick={updateGiftCardFunction}>
            update
          </button>
        </>
      )
    }

    const { getByTestId } = render(
      <MockedProvider mocks={mocksUpdateWithoutCode} addTypename={false}>
        <ProviderStore>
          <TestComponent />
        </ProviderStore>
      </MockedProvider>
    )

    await act(async () => {
      await wait(0)
      fireEvent.click(getByTestId('addValue'))
      fireEvent.click(getByTestId('buttonUpdate'))
      await wait(3000)
    })

    const alertValue = getByTestId('alert')
    const rescueValue = getByTestId('rescue')
    const valueGiftCardValue = getByTestId('valueGiftCard')

    waitFor(() => {
      expect(alertValue).toHaveTextContent(
        ShowAlertOptions.alertSave.toString()
      )
      expect(rescueValue).toHaveTextContent('5')
      expect(valueGiftCardValue).toHaveTextContent('0')
    })
  })
})

```


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

[User] Show me the implementation of list-wallet/react/__tests__/titlesArea.spec.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { render } from '@vtex/test-tools/react'
import React from 'react'

import TitlesArea from '../Components/titlesArea'
import History from '../Components/history'
import { ContextStore } from '../hooks/useStore'
// eslint-disable-next-line jest/no-mocks-import
import { values } from '../__mocks__/values'

describe('Titles Area', () => {
  it('should render a titles area', async () => {
    const { container } = render(
      <ContextStore.Provider value={{ ...values }}>
        <TitlesArea />
      </ContextStore.Provider>
    )

    expect(container.firstChild).not.toBeNull()

    expect(container.firstChild).toHaveTextContent(values.credit.toString())
  })
})

```


[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 list-wallet/react/hooks/useStore.tsx from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useContext } from 'react'
import { History } from 'vtex.gift-card-list'

import { ShowAlertOptions } from '../utils/showAlertOptions'

interface ContextStoreType {
  button: boolean
  setButton: (button: boolean) => void
  valueGiftCard: number
  code: string
  addValueGiftCard: string | undefined
  setAddValueGiftCard: (addValueGiftCard: string) => void
  updateGiftCardFunction: () => void
  validation: string
  setValidation: (validation: string) => void
  showAlert: ShowAlertOptions
  setShowAlert: (showAlert: ShowAlertOptions) => void
  handleCloseAlert: () => void
  credit: number
  history: TableHistory[]
  copyCode: () => void
  loading: boolean
  loadingCode: boolean
  rescue: number
  isGiftCardFieldInvalid: boolean
  setIsGiftCardFieldInvalid: (isGiftCardFieldInvalid: boolean) => void
  loadingGiftCard: boolean
  loadingCredit: boolean
  loadingRedemptionCode: boolean
  loadingHistory: boolean
  loadingGetRouteHistory: boolean
  setFilterHistory: (filterHistory: FilterHistory | undefined) => void
}

export const ContextStore = React.createContext<ContextStoreType>({
  button: false,
  setButton: () => {},
  valueGiftCard: 0,
  code: '',
  addValueGiftCard: '',
  setAddValueGiftCard: () => {},
  updateGiftCardFunction: () => {},
  validation: '',
  setValidation: () => {},
  showAlert: ShowAlertOptions.notShow,
  setShowAlert: () => {},
  handleCloseAlert: () => {},
  credit: 0,
  history: [],
  copyCode: () => {},
  loading: false,
  loadingCode: false,
  rescue: 0,
  isGiftCardFieldInvalid: false,
  setIsGiftCardFieldInvalid: () => {},
  loadingGiftCard: false,
  loadingCredit: false,
  loadingRedemptionCode: false,
  loadingHistory: false,
  loadingGetRouteHistory: false,
  setFilterHistory: () => {},
})

export function useStore() {
  return useContext(ContextStore)
}

```


[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 list-wallet/react/typings/@vtex/styleguide.d.ts from the list-wallet VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '@vtex/styleguide/lib/Alert'
declare module '@vtex/styleguide/lib/Collapsible'
declare module '@vtex/styleguide/lib/InputButton'
declare module '@vtex/styleguide/lib/icon/Info'
declare module '@vtex/styleguide/lib/Tooltip'
declare module '@vtex/styleguide/lib/Divider'
declare module '@vtex/styleguide/lib/Button'
declare module '@vtex/styleguide/lib/Input'
declare module '@vtex/styleguide/lib/Modal'
declare module '@vtex/styleguide/lib/Table'
declare module '@vtex/styleguide/lib/DatePicker'
declare module '@vtex/styleguide/lib/Dropdown'
declare module '@vtex/styleguide/lib/Spinner'
declare module '@vtex/styleguide/lib/Tag'

```


[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 product-summary/messages/it-IT.json from the product-summary VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/pricing.from": "Da",
  "store/pricing.to": "A",
  "store/button-label": "Compra",
  "store/sponsored-badge.label": "Sponsorizzato",
  "admin/editor.productSummary.title": "Riepilogo del prodotto",
  "admin/editor.productSummary.description": "Il riepilogo del prodotto mostra le principali informazioni sul prodotto",
  "admin/editor.productSummary.isOneClickBuy.title": "Dovrebbe reindirizzare l'utente al checkout dopo aver cliccato su \"Acquista\"",
  "admin/editor.productSummary.showBadge.title": "Mostra il badge di sconto",
  "admin/editor.productSummary.badgeText.title": "Testo badge",
  "admin/editor.productSummary.buyButtonText.title": "Personalizza il testo del pulsante \"Acquista\"",
  "admin/editor.productSummary.hideBuyButton.title": "Nasconde completamente il pulsante \"Acquista\"",
  "admin/editor.productSummary.showCollections.title": "Mostra i badge delle collezioni",
  "admin/editor.productSummary.displayBuyButton.title": "Modalità di visualizzazione del pulsante \"Acquista\"",
  "admin/editor.productSummary.displayBuyButton.option.none": "Non mostrare mai",
  "admin/editor.productSummary.displayBuyButton.option.always": "Mostra sempre",
  "admin/editor.productSummary.displayBuyButton.option.hover": "Mostra al passaggio del mouse (web)",
  "store/productSummary.quantity-error": "Non è stato possibile selezionare l'importo specificato",
  "store/productSummary.unit": "Pezzo",
  "store/productSummary.attachmentName": "{sign}{quantity}x {name}",
  "store/productSummary.missingOptionName": "Senza {name}",
  "admin/editor.productSummaryPrice.title": "Prezzo nel riepilogo del prodotto",
  "admin/editor.productSummaryPrice.description": "Componente che mostra il prezzo all'interno del riepilogo del prodotto",
  "admin/editor.productSummaryPrice.showListPrice.title": "Mostra prezzo di listino",
  "admin/editor.productSummaryPrice.showSellingPriceRange.title": "Mostra variazioni del prezzo di vendita",
  "admin/editor.productSummaryPrice.showListPriceRange.title": "Mostra variazioni del prezzo di listino",
  "admin/editor.productSummaryPrice.showInstallments.title": "Mostra rate",
  "admin/editor.productSummaryPrice.showDiscountValue.title": "Mostra sconto",
  "admin/editor.productSummaryPrice.showLabels.title": "Mostra etichette",
  "admin/editor.productSummaryPrice.labelSellingPrice.title": "Etichetta per il prezzo di vendita",
  "admin/editor.productSummaryPrice.labelListPrice.title": "Etichetta per il prezzo di listino",
  "admin/editor.productSummaryPrice.showBorders.title": "Mostra estremi",
  "admin/editor.productSummaryImage.title": "Immagine nel riepilogo del prodotto",
  "admin/editor.productSummaryImage.description": "Componente che mostra l'immagine del prodotto",
  "admin/editor.productSummaryImage.hoverImageLabel.title": "Etichetta dell'immagine secondaria",
  "admin/editor.productSummaryImage.hoverImageLabel.description": "Questa proprietà è obsoleta. Utilizza la proprietà relativa al tipo di selezione",
  "admin/editor.productSummaryImage.hoverImage.criteria.title": "Criteri per la selezione dell'immagine secondaria",
  "admin/editor.productSummaryImage.hoverImage.criteria.label": "Etichetta dell'immagine secondaria",
  "admin/editor.productSummaryImage.hoverImage.criteria.matchCriteria": "Criterio di ricerca dell'etichetta dell'immagine secondaria (exact: trova l'immagine che corrisponde esattamente al nome inserito nel campo \"Etichetta dell'immagine secondaria\" | contains: trova la prima immagine che contiene il testo inserito nel campo \"Etichetta dell'immagina secondaria\")",
  "admin/editor.productSummaryImage.hoverImage.criteria.index": "Indice dell'immagine secondaria",
  "admin/editor.productSummaryImage.fetchpriority.title": "Suggerisci la priorità di caricamento",
  "admin/editor.productSummaryImage.fetchpriority.high": "Priorità alta",
  "admin/editor.productSummaryImage.fetchpriority.low": "Priorità bassa",
  "admin/editor.productSummaryImage.fetchpriority.auto": "Lascia che il browser decida la priorità",
  "admin/editor.productSummaryImage.fetchpriority.byPosition": "Definire le priorità in base alla propria posizione",
  "admin/editor.productSummaryName.sponsoredBadge.title": "Testo del tag del prodotto sponsorizzato, se applicabile",
  "admin/editor.productSummaryBuyButton.title": "Pulsante \"Acquista\" nel riepilogo del prodotto",
  "admin/editor.productSummaryName.title": "Nome nel riepilogo del prodotto",
  "admin/editor.product-summary-specification-badges.title": "Badge per le specifiche nel riepilogo del prodotto",
  "admin/editor.productSummaryList.title": "Listino prodotti",
  "admin/editor.productSummaryList.description": "Un listino di prodotti di una collezione",
  "admin/editor.productSummaryList.category.title": "ID categoria",
  "admin/editor.productSummaryList.category.description": "Per le sottocategorie utilizza \"/\" (es.: 1/2/3)",
  "admin/editor.productSummaryList.collection.title": "Collezione",
  "admin/editor.productSummaryList.orderBy.title": "Ordinamento del listino",
  "admin/editor.productSummaryList.hideUnavailableItems": "Nascondi gli articoli non disponibili",
  "admin/editor.productSummaryList.maxItems.title": "Numero massimo di articoli",
  "admin/editor.productSummaryList.specificationFilters.title": "Filtri di specifica",
  "admin/editor.productSummaryList.specificationFilters.item.title": "Voce del filtro di specifica",
  "admin/editor.productSummaryList.specificationFilters.item.id.title": "ID del filtro di specifica",
  "admin/editor.productSummaryList.specificationFilters.item.value.title": "Valore del filtro di specifica",
  "admin/editor.productSummaryList.orderType.sales": "Saldi",
  "admin/editor.productSummaryList.orderType.priceDesc": "Prezzo decrescente",
  "admin/editor.productSummaryList.orderType.priceAsc": "Prezzo crescente",
  "admin/editor.productSummaryList.orderType.nameAsc": "Nome, crescente",
  "admin/editor.productSummaryList.orderType.nameDesc": "Nome decrescente",
  "admin/editor.productSummaryList.orderType.releaseDate": "Data di uscita",
  "admin/editor.productSummaryList.orderType.discount": "Sconto",
  "admin/editor.productSummaryList.orderType.relevance": "Rilevanza",
  "admin/editor.productSummaryList.skusFilter.title": "Filtro SKU",
  "admin/editor.productSummaryList.skusFilter.description": "Impostare il primo filtro disponibile potrebbe rendere la tua ricerca molto più veloce!",
  "admin/editor.productSummaryList.skusFilter.none": "Nessuno",
  "admin/editor.productSummaryList.skusFilter.first-available": "Il primo disponibile",
  "admin/editor.productSummaryList.skusFilter.all-available": "Tutti disponibili",
  "admin/editor.productSummaryList.installmentCriteria.title": "Rate visualizzate",
  "admin/editor.productSummaryList.installmentCriteria.description": "Scegli il tipo di rate da mostrare (ad es.: importo massimo senza interessi o con interessi).",
  "admin/editor.productSummaryList.installmentCriteria.max-without-interest": "Importo massimo senza interessi",
  "admin/editor.productSummaryList.installmentCriteria.max-with-interest": "Importo massimo",
  "admin/editor.productSummaryList.analyticsListName.title": "Nome del listino in \"Analisi\"",
  "admin/editor.productSummary.trackListName.title": "Serve a tracciare il nome del listino",
  "admin/editor.productSummary.sponsoredBadge.title": "Testo del tag prodotto sponsorizzato, se applicabile",
  "admin/editor.productSummary.sponsoredBadge.position": "Posizione del tag prodotto sponsorizzato, se applicabile",
  "admin/editor.productSummary.sponsoredBadge.position.titleTop": "Sopra il nome del prodotto",
  "admin/editor.productSummary.sponsoredBadge.position.containerTopLeft": "In cima al contenitore del prodotto",
  "admin/editor.productSummary.sponsoredBadge.position.none": "Non mostrare"
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "store/pricing.from": "ตั้งแต่",
  "store/pricing.to": "ถึง",
  "store/button-label": "ซื้อ",
  "store/sponsored-badge.label": "ได้รับการสนับสนุน",
  "admin/editor.productSummary.title": "ภาพรวมผลิตภัณฑ์",
  "admin/editor.productSummary.description": "ภาพรวมผลิตภัณฑ์แสดงข้อมูลผลิตภัณฑ์หลัก",
  "admin/editor.productSummary.isOneClickBuy.title": "ควรเปลี่ยนเส้นทางไปยังหน้าชำระเงินหลังคลิกที่ซื้อ",
  "admin/editor.productSummary.showBadge.title": "แสดงป้ายส่วนลด",
  "admin/editor.productSummary.badgeText.title": "ข้อความของป้าย",
  "admin/editor.productSummary.buyButtonText.title": "ข้อความของปุ่มซื้อที่กำหนดเอง",
  "admin/editor.productSummary.hideBuyButton.title": "ซ่อนปุ่มซื้อทั้งหมด",
  "admin/editor.productSummary.showCollections.title": "แสดงป้ายคอลเลกชัน",
  "admin/editor.productSummary.displayBuyButton.title": "โหมดแสดงปุ่มซื้อ",
  "admin/editor.productSummary.displayBuyButton.option.none": "ไม่แสดง",
  "admin/editor.productSummary.displayBuyButton.option.always": "แสดงเสมอ",
  "admin/editor.productSummary.displayBuyButton.option.hover": "แสดงเมื่อนำเมาส์ไปชี้ (เว็บ)",
  "store/productSummary.quantity-error": "เป็นไปไม่ได้ที่จะเลือกจำนวนที่ระบุ",
  "store/productSummary.unit": "หน่วย",
  "store/productSummary.attachmentName": "{sign} {quantity}x {name}",
  "store/productSummary.missingOptionName": "ไม่มี {name}",
  "admin/editor.productSummaryPrice.title": "ราคาตามภาพรวมผลิตภัณฑ์",
  "admin/editor.productSummaryPrice.description": "คอมโพเนนต์ที่แสดงราคาผลิตภัณฑ์ภายในภาพรวมผลิตภัณฑ์",
  "admin/editor.productSummaryPrice.showListPrice.title": "แสดงราคาตามบัญชีราคา",
  "admin/editor.productSummaryPrice.showSellingPriceRange.title": "แสดงช่วงราคาขาย",
  "admin/editor.productSummaryPrice.showListPriceRange.title": "แสดงช่วงราคาตามบัญชีราคา",
  "admin/editor.productSummaryPrice.showInstallments.title": "แสดงการผ่อนชำระ",
  "admin/editor.productSummaryPrice.showDiscountValue.title": "แสดงค่าส่วนลด",
  "admin/editor.productSummaryPrice.showLabels.title": "แสดงป้ายชื่อ",
  "admin/editor.productSummaryPrice.labelSellingPrice.title": "ป้ายชื่อสำหรับราคาขาย",
  "admin/editor.productSummaryPrice.labelListPrice.title": "ป้ายชื่อสำหรับราคาตามบัญชีราคา",
  "admin/editor.productSummaryPrice.showBorders.title": "แสดงเส้นขอบ",
  "admin/editor.productSummaryImage.title": "รูปภาพสำหรับภาพรวมผลิตภัณฑ์",
  "admin/editor.productSummaryImage.description": "คอมโพเนนต์ที่แสดงรูปภาพผลิตภัณฑ์",
  "admin/editor.productSummaryImage.hoverImageLabel.title": "ป้ายข้อความภาพโฮเวอร์",
  "admin/editor.productSummaryImage.hoverImageLabel.description": "คณสมบัตนี้เลิกใช้ ใช้คุณสมบัติเกณฑ์แทน",
  "admin/editor.productSummaryImage.hoverImage.criteria.title": "เกณฑ์สำหรับการเลือกภาพโฮเวอร์",
  "admin/editor.productSummaryImage.hoverImage.criteria.label": "ป้ายข้อความภาพโฮเวอร์",
  "admin/editor.productSummaryImage.hoverImage.criteria.matchCriteria": "เกณฑ์การค้นหาป้ายข้อความภาพโฮเวอร์ (ทุกประการ: หารูปภาพที่มีค่าตรงกันทุกประการกับชื่อที่กรอกไว้ในฟิลด์ \"ป้ายข้อความภาพโฮเวอร์\" | มี: หารูปภาพแรกที่มีข้อความที่กรอกไว้ในฟิลด์ \"ป้ายข้อความภาพโฮเวอร์\")",
  "admin/editor.productSummaryImage.hoverImage.criteria.index": "ดัชนีภาพโฮเวอร์",
  "admin/editor.productSummaryBuyButton.title": "ปุ่มซื้อภาพรวมผลิตภัณฑ์",
  "admin/editor.productSummaryName.title": "ชื่อภาพรวมผลิตภัณฑ์",
  "admin/editor.product-summary-specification-badges.title": "ป้ายข้อกำหนดคุณลักษณะภาพรวมผลิตภัณฑ์",
  "admin/editor.productSummaryList.title": "รายการผลิตภัณฑ์",
  "admin/editor.productSummaryList.description": "รายการผลิตภัณฑ์ที่มีคอลเลกชัน",
  "admin/editor.productSummaryList.category.title": "รหัสหมวดหมู่",
  "admin/editor.productSummaryList.category.description": "สำหรับหมวดหมู่ย่อย ใช้ \"/\" (เช่น 1/2/3)",
  "admin/editor.productSummaryList.collection.title": "คอลเลกชัน",
  "admin/editor.productSummaryList.orderBy.title": "การจัดเรียงรายการ",
  "admin/editor.productSummaryList.hideUnavailableItems": "ซ่อนสินค้าที่ไม่พร้อมจำหน่าย",
  "admin/editor.productSummaryList.maxItems.title": "จำนวนสินค้ามากที่สุดที่พร้อมจำหน่าย",
  "admin/editor.productSummaryList.specificationFilters.title": "ตัวกรองข้อกำหนดคุณลักษณะ",
  "admin/editor.productSummaryList.specificationFilters.item.title": "ไอเทมตัวกรองข้อกำหนดคุณลักษณะ",
  "admin/editor.productSummaryList.specificationFilters.item.id.title": "รหัสตัวกรองข้อกำหนดคุณลักษณะ",
  "admin/editor.productSummaryList.specificationFilters.item.value.title": "ค่าตัวกรองข้อกำหนดคุณลักษณะ",
  "admin/editor.productSummaryList.orderType.sales": "การขาย",
  "admin/editor.productSummaryList.orderType.priceDesc": "ราคา จากมากไปหาน้อย",
  "admin/editor.productSummaryList.orderType.priceAsc": "ราคา จากน้อยไปหามาก",
  "admin/editor.productSummaryList.orderType.nameAsc": "ชื่อ จากน้อยไปหามาก",
  "admin/editor.productSummaryList.orderType.nameDesc": "ชื่อ จากมากไปหาน้อย",
  "admin/editor.productSummaryList.orderType.releaseDate": "วันที่วางจำหน่าย",
  "admin/editor.productSummaryList.orderType.discount": "ส่วนลด",
  "admin/editor.productSummaryList.orderType.relevance": "ความเกี่ยวข้อง",
  "admin/editor.productSummaryList.skusFilter.title": "ตัวกรอง SKUs",
  "admin/editor.productSummaryList.skusFilter.description": "การตั้งค่าตัวกรองแรกที่มีอยู่อาจทำให้การสืบค้นของคุณเร็วขึ้นมาก",
  "admin/editor.productSummaryList.skusFilter.none": "ไม่มี",
  "admin/editor.productSummaryList.skusFilter.first-available": "แรกสุดที่มี",
  "admin/editor.productSummaryList.skusFilter.all-available": "ทั้งหมดที่มี",
  "admin/editor.productSummaryList.installmentCriteria.title": "การผ่อนชำระที่แสดง",
  "admin/editor.productSummaryList.installmentCriteria.description": "เลือกว่าจะแสดงการผ่อนชำระประเภทใด (เช่น สูงสุดปราศจากดอกเบี้ยหรือมีดอกเบี้ย)",
  "admin/editor.productSummaryList.installmentCriteria.max-without-interest": "สูงสุดปราศจากดอกเบี้ย",
  "admin/editor.productSummaryList.installmentCriteria.max-with-interest": "สูงสุด",
  "admin/editor.productSummaryList.analyticsListName.title": "ชื่อรายการใน Analytics",
  "admin/editor.productSummary.trackListName.title": "ควรติดตามชื่อรายการ",
  "admin/editor.productSummary.sponsoredBadge.title": "ข้อความของแท็กผลิตภัณฑ์ที่ได้รับการสนับสนุนหากมี",
  "admin/editor.productSummary.sponsoredBadge.position": "ตำแหน่งของแท็กผลิตภัณฑ์ที่ได้รับการสนับสนุนหากมี",
  "admin/editor.productSummary.sponsoredBadge.position.titleTop": "เหนือชื่อผลิตภัณฑ์",
  "admin/editor.productSummary.sponsoredBadge.position.containerTopLeft": "ด้านบนของภาชนะบรรจุผลิตภัณฑ์",
  "admin/editor.productSummary.sponsoredBadge.position.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 product-summary/messages/ko-KR.json from the product-summary VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/pricing.from": "에서",
  "store/pricing.to": "까지",
  "store/button-label": "구매",
  "store/sponsored-badge.label": "후원",
  "admin/editor.productSummary.title": "제품 요약",
  "admin/editor.productSummary.description": "주요 제품 정보를 보여주는 제품 요약",
  "admin/editor.productSummary.isOneClickBuy.title": "구매를 클릭한 후 체크아웃으로 리디렉션",
  "admin/editor.productSummary.showBadge.title": "할인 배지 표시",
  "admin/editor.productSummary.badgeText.title": "배지 텍스트",
  "admin/editor.productSummary.buyButtonText.title": "사용자 지정 구매 버튼의 텍스트",
  "admin/editor.productSummary.hideBuyButton.title": "구매 버튼을 완전히 숨기기",
  "admin/editor.productSummary.showCollections.title": "컬렉션 배지 표시",
  "admin/editor.productSummary.displayBuyButton.title": "구매 버튼 디스플레이 모드",
  "admin/editor.productSummary.displayBuyButton.option.none": "표시 안함",
  "admin/editor.productSummary.displayBuyButton.option.always": "항상 표시",
  "admin/editor.productSummary.displayBuyButton.option.hover": "가리키면 표시(웹)",
  "store/productSummary.quantity-error": "지정한 금액을 선택할 수 없습니다.",
  "store/productSummary.unit": "단위",
  "store/productSummary.attachmentName": "{sign} {quantity}x {name}",
  "store/productSummary.missingOptionName": "{name} 없음",
  "admin/editor.productSummaryPrice.title": "제품 요약 가격",
  "admin/editor.productSummaryPrice.description": "제품 요약 내에 제품 가격을 표시하는 구성 요소",
  "admin/editor.productSummaryPrice.showListPrice.title": "정가 표시",
  "admin/editor.productSummaryPrice.showSellingPriceRange.title": "판매가 범위 표시",
  "admin/editor.productSummaryPrice.showListPriceRange.title": "정가 범위 표시",
  "admin/editor.productSummaryPrice.showInstallments.title": "분할 표시",
  "admin/editor.productSummaryPrice.showDiscountValue.title": "할인가 표시",
  "admin/editor.productSummaryPrice.showLabels.title": "라벨 표시",
  "admin/editor.productSummaryPrice.labelSellingPrice.title": "판매 가격 라벨",
  "admin/editor.productSummaryPrice.labelListPrice.title": "정가 라벨",
  "admin/editor.productSummaryPrice.showBorders.title": "테두리 표시",
  "admin/editor.productSummaryImage.title": "제품 요약 이미지",
  "admin/editor.productSummaryImage.description": "제품 이미지를 표시하는 구성 요소",
  "admin/editor.productSummaryImage.hoverImageLabel.title": "호버 이미지 라벨",
  "admin/editor.productSummaryImage.hoverImageLabel.description": "이 속성은 사용되지 않습니다. 대신 기준 속성을 사용합니다",
  "admin/editor.productSummaryImage.hoverImage.criteria.title": "호버 이미지 선택 기준",
  "admin/editor.productSummaryImage.hoverImage.criteria.label": "호버 이미지 라벨",
  "admin/editor.productSummaryImage.hoverImage.criteria.matchCriteria": "호버 이미지 라벨 검색 조건(정확: '호버 이미지 라벨' 필드에 입력된 이름과 정확히 일치하는 이미지를 찾습니다. | 포함: '호버 이미지 라벨' 필드에 입력된 텍스트를 포함하는 첫 번째 이미지를 찾습니다.)",
  "admin/editor.productSummaryImage.hoverImage.criteria.index": "호버 이미지 인덱스",
  "admin/editor.productSummaryBuyButton.title": "제품 요약 구매 버튼",
  "admin/editor.productSummaryName.title": "제품 요약 이름",
  "admin/editor.product-summary-specification-badges.title": "제품 요약 사양 배지",
  "admin/editor.productSummaryList.title": "제품 목록",
  "admin/editor.productSummaryList.description": "컬렉션을 포함하는 제품 목록",
  "admin/editor.productSummaryList.category.title": "카테고리 ID",
  "admin/editor.productSummaryList.category.description": "하위 카테고리의 경우 \"/\" 사용 (예: 1/2/3)",
  "admin/editor.productSummaryList.collection.title": "컬렉션",
  "admin/editor.productSummaryList.orderBy.title": "목록 정렬",
  "admin/editor.productSummaryList.hideUnavailableItems": "이용할 수 없는 품목 숨기기",
  "admin/editor.productSummaryList.maxItems.title": "최대 항목",
  "admin/editor.productSummaryList.specificationFilters.title": "사양 필터",
  "admin/editor.productSummaryList.specificationFilters.item.title": "사양 필터 항목",
  "admin/editor.productSummaryList.specificationFilters.item.id.title": "사양 필터 ID",
  "admin/editor.productSummaryList.specificationFilters.item.value.title": "사양 필터 값",
  "admin/editor.productSummaryList.orderType.sales": "판매량",
  "admin/editor.productSummaryList.orderType.priceDesc": "가격, 내림차순",
  "admin/editor.productSummaryList.orderType.priceAsc": "가격, 오름차순",
  "admin/editor.productSummaryList.orderType.nameAsc": "이름, 오름차순",
  "admin/editor.productSummaryList.orderType.nameDesc": "이름, 내림차순",
  "admin/editor.productSummaryList.orderType.releaseDate": "출시일",
  "admin/editor.productSummaryList.orderType.discount": "할인",
  "admin/editor.productSummaryList.orderType.relevance": "관련",
  "admin/editor.productSummaryList.skusFilter.title": "SKU 필터",
  "admin/editor.productSummaryList.skusFilter.description": "사용 가능한 첫 번째 필터를 설정하면 문의가 훨씬 빨라집니다!",
  "admin/editor.productSummaryList.skusFilter.none": "없음",
  "admin/editor.productSummaryList.skusFilter.first-available": "첫 번째 사용 가능",
  "admin/editor.productSummaryList.skusFilter.all-available": "모두 사용 가능",
  "admin/editor.productSummaryList.installmentCriteria.title": "표시된 할부",
  "admin/editor.productSummaryList.installmentCriteria.description": "표시될 할부 유형을 선택하세요 (예: 무이자 또는 무이자 최대).",
  "admin/editor.productSummaryList.installmentCriteria.max-without-interest": "무이자 최대",
  "admin/editor.productSummaryList.installmentCriteria.max-with-interest": "최대",
  "admin/editor.productSummaryList.analyticsListName.title": "애널리틱스의 목록 이름",
  "admin/editor.productSummary.trackListName.title": "목록 이름을 추적해야 함",
  "admin/editor.productSummary.sponsoredBadge.title": "적용 가능한 경우 스폰서 제품 태그의 텍스트",
  "admin/editor.productSummary.sponsoredBadge.position": "적용 가능한 경우 스폰서 제품 태그의 위치",
  "admin/editor.productSummary.sponsoredBadge.position.titleTop": "제품 이름 위",
  "admin/editor.productSummary.sponsoredBadge.position.containerTopLeft": "제품 컨테이너 위에",
  "admin/editor.productSummary.sponsoredBadge.position.none": "표시하지 마십시오"
}

```