[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 checkout-payment/messages/pt.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Você selecionou",
  "store/checkout-payment.installmentsButton": "Escolher parcelamento",
  "store/checkout-payment.creditCardExtraDataMessage": "Para sua segurança, preencha os seguintes dados:",
  "store/checkout-payment.documentLabel": "Documento do titular do cartão",
  "store/checkout-payment.requiredField": "Campo obrigatório.",
  "store/checkout-payment.invalidDigits": "Dígitos inválidos",
  "store/checkout-payment.creditCardLabel": "Cartão de Crédito",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Ver opções de parcelamento",
  "store/checkout-payment.installmentsOptionsTitle": "Opções de parcelamento",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {sem juros} true {com juros de {interestRate}% ao mês}}",
  "store/checkout-payment.installmentsTitle": "Parcelamento",
  "store/checkout-payment.installmentOptionLabel": "Escolha um parcelamento",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Alterar parcelamento",
  "store/checkout-payment.interestFree": "Sem juros",
  "store/checkout-payment.newCreditCardLabel": "Novo Cartão de Crédito",
  "store/checkout-payment.incompleteCardLabel": "Cartão Incompleto",
  "store/checkout-payment.choosePaymentMethodLabel": "Escolha um método de pagamento",
  "store/checkout-payment.paymentSummaryCardMessage": "Cartão de crédito terminando em {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- sem juros}}",
  "store/checkout-payment.boletoGenerationMessage": "Gerado após a compra",
  "store/checkout-payment.boletoNotice": "A estimativa de entrega está sujeita à confirmação do pagamento. Isso pode levar em até 1 dia útil.",
  "store/checkout-payment.reviewPurchaseLabel": "Revisar compra",
  "store/checkout-payment.billingAddressLabel": "Endereço de fatura",
  "store/checkout-payment.newAddressLabel": "+ Novo endereço",
  "store/checkout-payment.cardFormTitle": "Contêiner para o formulário de cartão de crédito",
  "store/checkout-payment.freePurchase": "Sua compra é grátis",
  "store/checkout-payment.informBillingAddress": "Por favor informe o endereço de faturamento"
}

```


[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 checkout-payment/messages/en.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "You selected",
  "store/checkout-payment.installmentsButton": "Choose a payment option",
  "store/checkout-payment.creditCardExtraDataMessage": "For your safety, fill the following information:",
  "store/checkout-payment.documentLabel": "Cardholder document",
  "store/checkout-payment.requiredField": "This field is required.",
  "store/checkout-payment.invalidDigits": "Invalid Digits",
  "store/checkout-payment.creditCardLabel": "Credit Card",
  "store/checkout-payment.viewInstallmentOptionsLabel": "View installment options",
  "store/checkout-payment.installmentsOptionsTitle": "Installments options",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {without interest} true {with interest of {interestRate}% monthly}}",
  "store/checkout-payment.installmentsTitle": "Installments",
  "store/checkout-payment.installmentOptionLabel": "Choose an installment option",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Change installments",
  "store/checkout-payment.interestFree": "Interest-free",
  "store/checkout-payment.newCreditCardLabel": "New Credit Card",
  "store/checkout-payment.incompleteCardLabel": "Incomplete Card",
  "store/checkout-payment.choosePaymentMethodLabel": "Choose a payment method",
  "store/checkout-payment.paymentSummaryCardMessage": "Credit card ending with {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Generated after purchase",
  "store/checkout-payment.boletoNotice": "The delivery estimate is subject to payment being confirmed. This can take up to 1 business day.",
  "store/checkout-payment.reviewPurchaseLabel": "Review purchase",
  "store/checkout-payment.billingAddressLabel": "Billing address",
  "store/checkout-payment.newAddressLabel": "+ New address",
  "store/checkout-payment.cardFormTitle": "Container for credit card form",
  "store/checkout-payment.freePurchase": "Your purchase is free",
  "store/checkout-payment.informBillingAddress": "Please inform your billing address"
}

```


[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 checkout-payment/messages/fr.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Vous avez sélectionné",
  "store/checkout-payment.installmentsButton": "Choisissez un mode de paiement",
  "store/checkout-payment.creditCardExtraDataMessage": "Pour votre sécurité, remplissez les informations suivantes :",
  "store/checkout-payment.documentLabel": "Document du titulaire de la carte",
  "store/checkout-payment.requiredField": "Ce champ est obligatoire.",
  "store/checkout-payment.invalidDigits": "Chiffres non valables",
  "store/checkout-payment.creditCardLabel": "Carte de crédit",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Afficher les options d’installation",
  "store/checkout-payment.installmentsOptionsTitle": "Options d’installation",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {without interest} true {avec intérêts de {interestRate}% mois}}",
  "store/checkout-payment.installmentsTitle": "Versements",
  "store/checkout-payment.installmentOptionLabel": "Choisissez une option d’installation",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Changer les installations",
  "store/checkout-payment.interestFree": "Sans intérêts",
  "store/checkout-payment.newCreditCardLabel": "Nouvelle carte de crédit",
  "store/checkout-payment.incompleteCardLabel": "Carte incomplète",
  "store/checkout-payment.choosePaymentMethodLabel": "Choisissez un mode de paiement",
  "store/checkout-payment.paymentSummaryCardMessage": "Carte de crédit se terminant par {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Généré après l’achat",
  "store/checkout-payment.boletoNotice": "L’estimation de la livraison est soumise à la confirmation du paiement. Cela peut prendre jusqu’à un jour ouvrable.",
  "store/checkout-payment.reviewPurchaseLabel": "Revoir l’achat",
  "store/checkout-payment.billingAddressLabel": "Adresse de facturation",
  "store/checkout-payment.newAddressLabel": "+ Nouvelle adresse",
  "store/checkout-payment.cardFormTitle": "Contenu pour le formulaire de carte de crédit",
  "store/checkout-payment.freePurchase": "Votre achat est gratuit",
  "store/checkout-payment.informBillingAddress": "Veuillez renseigner votre adresse de facturation"
}

```


[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 checkout-payment/messages/ro.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Ai selectat",
  "store/checkout-payment.installmentsButton": "Alege o metodă de plată",
  "store/checkout-payment.creditCardExtraDataMessage": "Pentru siguranța ta, completează următoarele informații:",
  "store/checkout-payment.documentLabel": "Document titular card",
  "store/checkout-payment.requiredField": "Acest câmp este obligatoriu.",
  "store/checkout-payment.invalidDigits": "Cifre invalide",
  "store/checkout-payment.creditCardLabel": "Card de credit",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Vezi opțiunile de rate",
  "store/checkout-payment.installmentsOptionsTitle": "Opțiuni rate",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {without interest} true {cu dobândă de {interestRate}% lunar}}",
  "store/checkout-payment.installmentsTitle": "Rate",
  "store/checkout-payment.installmentOptionLabel": "Alege o opțiune de rate",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Modifică ratele",
  "store/checkout-payment.interestFree": "Fără dobândă",
  "store/checkout-payment.newCreditCardLabel": "Card de credit nou",
  "store/checkout-payment.incompleteCardLabel": "Card incomplet",
  "store/checkout-payment.choosePaymentMethodLabel": "Alege o metodă de plată",
  "store/checkout-payment.paymentSummaryCardMessage": "Card de credit care se termină cu {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Generat după achiziție",
  "store/checkout-payment.boletoNotice": "Estimatul livrării depinde de confirmarea plății. Aceasta poate dura până la o zi lucrătoare.",
  "store/checkout-payment.reviewPurchaseLabel": "Revizuiește achiziția",
  "store/checkout-payment.billingAddressLabel": "Adresa de facturare",
  "store/checkout-payment.newAddressLabel": "+ Adresă nouă",
  "store/checkout-payment.cardFormTitle": "Container pentru formularul cardului de credit",
  "store/checkout-payment.freePurchase": "Achiziția ta este gratuită",
  "store/checkout-payment.informBillingAddress": "Te rugăm să ne comunici adresa ta de facturare"
}

```


[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 checkout-payment/messages/no.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Du valgte",
  "store/checkout-payment.installmentsButton": "Velg et betalingsalternativ",
  "store/checkout-payment.creditCardExtraDataMessage": "Fyll ut følgende informasjon for din egen sikkerhet:",
  "store/checkout-payment.documentLabel": "Kortholderdokument",
  "store/checkout-payment.requiredField": "Dette feltet er obligatorisk.",
  "store/checkout-payment.invalidDigits": "Ugyldige tall",
  "store/checkout-payment.creditCardLabel": "Kredittkort",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Se avdragsalternativer",
  "store/checkout-payment.installmentsOptionsTitle": "Avdragsalternativer",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {without interest} true {med renter på {interestRate}% månedlig}}",
  "store/checkout-payment.installmentsTitle": "Avdrag",
  "store/checkout-payment.installmentOptionLabel": "Velg et avdragsalternativ",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Endre avdrag",
  "store/checkout-payment.interestFree": "Rentefri",
  "store/checkout-payment.newCreditCardLabel": "Nytt kredittkort",
  "store/checkout-payment.incompleteCardLabel": "Ufullstendig kort",
  "store/checkout-payment.choosePaymentMethodLabel": "Velg en betalingsmåte",
  "store/checkout-payment.paymentSummaryCardMessage": "Kredittkort som slutter med {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- without interest}}",
  "store/checkout-payment.boletoGenerationMessage": "Generert etter kjøp",
  "store/checkout-payment.boletoNotice": "Leveringsestimatet er betinget av at betaling er bekreftet. Dette kan ta opptil 1 virkedag.",
  "store/checkout-payment.reviewPurchaseLabel": "Gjennomgå kjøpet",
  "store/checkout-payment.billingAddressLabel": "Fakturaadresse",
  "store/checkout-payment.newAddressLabel": "+ Ny adresse",
  "store/checkout-payment.cardFormTitle": "Beholder for kredittkortskjema",
  "store/checkout-payment.freePurchase": "Kjøpet ditt er gratis",
  "store/checkout-payment.informBillingAddress": "Informer om faktureringsadressen din"
}

```


[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 checkout-payment/messages/es.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/checkout-payment.selectedPaymentLabel": "Tu seleccionaste",
  "store/checkout-payment.installmentsButton": "Elige cuota",
  "store/checkout-payment.creditCardExtraDataMessage": "Por su seguridad, complete los siguientes datos:",
  "store/checkout-payment.documentLabel": "Documento del titular de la tarjeta",
  "store/checkout-payment.requiredField": "Este campo es obligatorio.",
  "store/checkout-payment.invalidDigits": "Dígitos inválidos",
  "store/checkout-payment.creditCardLabel": "Tarjeta de Crédito",
  "store/checkout-payment.viewInstallmentOptionsLabel": "Ver opciones de pago",
  "store/checkout-payment.installmentsOptionsTitle": "Opciones de pago a plazos",
  "store/checkout-payment.installmentWithoutValue": "{count}x {hasInterestRate, select, false {sin interés} true {con interés de {interestRate}% mensual}}",
  "store/checkout-payment.installmentsTitle": "Cuotas",
  "store/checkout-payment.installmentOptionLabel": "Elige una cuota",
  "store/checkout-payment.installmentValue": "{installments}x {value}",
  "store/checkout-payment.changeInstallments": "Cambiar cuota",
  "store/checkout-payment.interestFree": "Sin interés",
  "store/checkout-payment.newCreditCardLabel": "Nueva tarjeta de credito",
  "store/checkout-payment.incompleteCardLabel": "Tarjeta Incompleta",
  "store/checkout-payment.choosePaymentMethodLabel": "Elija un método de pago",
  "store/checkout-payment.paymentSummaryCardMessage": "Tarjeta de crédito terminada en {value}",
  "store/checkout-payment.summaryInstallments": "{installmentsMessage} {hasInterestRate, select, false {- sin interés}}",
  "store/checkout-payment.boletoGenerationMessage": "Generado después de la compra",
  "store/checkout-payment.boletoNotice": "La entrega estimada está sujeta a confirmación de pago. Esto puede demorar hasta 1 día hábil.",
  "store/checkout-payment.reviewPurchaseLabel": "Revisar compra",
  "store/checkout-payment.billingAddressLabel": "Dirección de facturación",
  "store/checkout-payment.newAddressLabel": "+ Nueva dirección",
  "store/checkout-payment.cardFormTitle": "Contenedor para formulario de tarjeta de crédito",
  "store/checkout-payment.freePurchase": "Tu compra es gratis",
  "store/checkout-payment.informBillingAddress": "Ingrese su dirección de facturación"
}

```


[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 checkout-payment/docs/README.md from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```markdown
First of all (even before the block's name), its README.md should contain the following sentence at the very beginning:

`=� Use this project, [contribute](https://github.com/{OrganizationName/{AppName}) to it or open issues to help evolve it using [Store Discussion](https://github.com/vtex-apps/store-discussion).`

# BLOCK NAME

Under the block's name, you should explain the topic, giving a **brief description** of the **block's functionality** in a store.

Next, **add media** (either an image of a GIF) with the rendered block, so that users can better understand how the block works in practice.

![Media Placeholder](https://user-images.githubusercontent.com/52087100/71204177-42ca4f80-227e-11ea-89e6-e92e65370c69.png)

## Configuration

In this section, you first must **add the primary instructions** that will allow users to use the block in their store, such as adding the block's app as a dependency in the `manifest.json` and declaring the block itself in a given template.

Next, add the **block's props table**:

| Prop name    | Type            | Description    | Default value                                                                                |
| ------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `XXXXX`      | `XXXXXX`       | XXXXXXXX         | `XXXXXX`        |

Remember to also **showcase any necessary disclaimer** related to the block in this section, such as the different behavior it may display during its configuration.

## Modus Operandi *(not mandatory)*

There are scenarios in which a block can behave differently in a store, according to how it was added to the catalog, for example. It's crucial to go through these **behavioral changes** in this section, allowing users to fully understand the **practical application** of the block in their store.

If you feel compelled to give further details about the block, such as it's **relationship with the VTEX admin**, don't hesitate to use this section.

## Customization

The first thing that should be present in this section is the sentence below, showing users the recipe pertaining to CSS customization in blocks:

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

Thereafter, you should add a single column table with the available CSS handles for that block:

| CSS Handles |
| ----------- |
| `paymentListContainer` |
| `savedCreditCardOption` |
| `newCreditCardOption` |
| `bankInvoiceOption` |
| `creditCardContainer` |
| `extraDataContainer` |
| `selectedPaymentLabel` |
| `creditCardExtraDataMessage` |
| `documentFieldSectionContainer` |
| `documentFieldContainer` |
| `billingAddressSectionContainer` |
| `billingAddressFormContainer` |
| `reviewPurchaseButtonContainer` |
| `reviewPurchaseButtonLabel` |

If there are none, add the following sentence instead:

`The component still doesn't have CSS Handles for its specific customization.`

---

Check out some documentation models that are already live:
- [Breadcrumb](https://github.com/vtex-apps/breadcrumb)
- [Image](https://vtex.io/docs/components/general/vtex.store-components/image)

**Upcoming documentation:**

 - [Checkout payment](https://github.com/vtex-apps/checkout-payment/pull/1)
```


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

[User] Show me the implementation of checkout-payment/react/CreditCard.css from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```css
.iframe {
  /* Using min-width to set the width of the iFrame, works around an issue in iOS that can
  prevent the iFrame from sizing correctly. style={{ minWidth: '100%', minHeight: '200px' }} */
  min-width: 100%;
}

.newCard {
  min-height: 306px;
}

.savedCard {
  min-height: 177px;
}

```


[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 checkout-payment/react/PaymentList.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactNode } from 'react'
import { useIntl, defineMessages } from 'react-intl'
import { GroupOption, ListGroup } from 'vtex.checkout-components'
import { useCssHandles } from 'vtex.css-handles'
import { AvailableAccount, PaymentSystem } from 'vtex.checkout-graphql'
import { PaymentFlag } from 'vtex.payment-flags'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'

import Header from './components/Header'
import CardLabel from './components/CardLabel'
import { slugify } from './utils/text'

const CSS_HANDLES = [
  'paymentListContainer',
  'savedCreditCardOption',
  'newCreditCardOption',
  'bankInvoiceOption',
  'customPaymentOption',
] as const

const CASH_PAYMENT_SYSTEM_ID = '47'

const messages = defineMessages({
  choosePaymentMethod: {
    id: 'store/checkout-payment.choosePaymentMethodLabel',
  },
  creditCardLabel: {
    id: 'store/checkout-payment.creditCardLabel',
  },
  newCreditCardLabel: {
    id: 'store/checkout-payment.newCreditCardLabel',
  },
})

const PaymentItem: React.FC<{
  paymentSystem?: string
  label: ReactNode
  'data-testid'?: string
}> = ({
  paymentSystem = '',
  label,
  'data-testid': testId = typeof label === 'string' ? label : undefined,
}) => {
  return (
    <div className="flex items-center c-muted-1" data-testid={slugify(testId)}>
      <div className="h2">
        <PaymentFlag paymentSystemId={paymentSystem} />
      </div>
      <span className="ml5">{label}</span>
    </div>
  )
}

interface Props {
  onNewCreditCard: () => void
  onSavedCreditCard: (payment: AvailableAccount) => void
  onBankInvoiceSelect: (payment: PaymentSystem) => void
  onCustomPaymentSelect: (payment: PaymentSystem) => void
}

const PaymentList: React.FC<Props> = ({
  onNewCreditCard,
  onSavedCreditCard,
  onBankInvoiceSelect,
  onCustomPaymentSelect,
}) => {
  const intl = useIntl()

  const { availableAccounts, paymentSystems } = useOrderPayment()

  const { handles } = useCssHandles(CSS_HANDLES)

  const bankInvoicePayments = paymentSystems.filter(
    ({ groupName }) => groupName === 'bankInvoicePaymentGroup'
  )

  const customPayments = paymentSystems.filter(({ isCustom }) => isCustom)

  return (
    <div className={handles.paymentListContainer}>
      <Header>{intl.formatMessage(messages.choosePaymentMethod)}</Header>

      <ListGroup>
        {availableAccounts.map((payment: AvailableAccount) => {
          const lastDigits = payment.cardNumber.replace(/[^\d]/g, '')
          const label = intl.formatMessage(messages.creditCardLabel)
          const paymentLabel = (
            <CardLabel label={label} lastDigits={lastDigits} />
          )
          return (
            <GroupOption
              onClick={() => onSavedCreditCard(payment)}
              key={payment.accountId}
              caretAlign="center"
              className={handles.savedCreditCardOption}
            >
              <PaymentItem
                paymentSystem={payment.paymentSystem}
                label={paymentLabel}
                data-testid={label}
              />
            </GroupOption>
          )
        })}
        <GroupOption
          onClick={onNewCreditCard}
          caretAlign="center"
          className={handles.newCreditCardOption}
        >
          <PaymentItem
            label={intl.formatMessage(messages.newCreditCardLabel)}
          />
        </GroupOption>
        {bankInvoicePayments.map(paymentSystem => (
          <GroupOption
            caretAlign="center"
            key={paymentSystem.id}
            onClick={() => onBankInvoiceSelect(paymentSystem)}
            className={handles.bankInvoiceOption}
          >
            <PaymentItem
              label={paymentSystem.name}
              paymentSystem={paymentSystem.id}
            />
          </GroupOption>
        ))}
        {customPayments.map(paymentSystem => (
          <GroupOption
            caretAlign="center"
            key={paymentSystem.id}
            onClick={() => onCustomPaymentSelect(paymentSystem)}
            className={handles.customPaymentOption}
          >
            <PaymentItem
              label={paymentSystem.name}
              paymentSystem={CASH_PAYMENT_SYSTEM_ID}
            />
          </GroupOption>
        ))}
      </ListGroup>
    </div>
  )
}

export default PaymentList

```


[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 checkout-payment/react/Payment.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useRef, useCallback, useEffect } from 'react'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'
import { Router, routes } from 'vtex.checkout-container'
import { AvailableAccount, PaymentSystem, Address } from 'vtex.checkout-graphql'
import { useCssHandles } from 'vtex.css-handles'

import CreditCard, { CreditCardRef } from './CreditCard'
import PaymentList from './PaymentList'
import { PaymentStage } from './enums/PaymentEnums'
import InstallmentsModal from './components/InstallmentsModal'
import ExtraData from './components/ExtraData'

const { useHistory } = Router

const CSS_HANDLES = ['creditCardContainer'] as const

const Payment: React.FC = () => {
  const [cardType, setCardType] = useState<CardType>('new')
  const {
    setPaymentField,
    setCardLastDigits,
    value,
    referenceValue,
    setCardFormFilled,
    isFreePurchase,
  } = useOrderPayment()
  const [stage, setStage] = useState<PaymentStage>(
    isFreePurchase ? PaymentStage.FREE_PURCHASE : PaymentStage.PAYMENT_LIST
  )
  const creditCardRef = useRef<CreditCardRef>(null)
  const history = useHistory()

  const [installmentsModalOpen, setInstallmentsModalOpen] = useState(false)

  useEffect(() => {
    if (isFreePurchase) {
      history.push(routes.REVIEW)
    }
  }, [history, isFreePurchase])

  const { handles } = useCssHandles(CSS_HANDLES)

  const handleCardFormCompleted = () => {
    setCardFormFilled(true)
    if (cardType === 'new') {
      setInstallmentsModalOpen(true)
    } else {
      history.push(routes.REVIEW)
    }
  }

  const handleDeselectPayment = () => {
    creditCardRef?.current?.resetCardFormData()

    setCardFormFilled(false)
    setStage(PaymentStage.CARD_FORM)
  }

  const handleChangePaymentMethod = () => {
    setStage(PaymentStage.PAYMENT_LIST)
  }

  const handleNewCreditCard = () => {
    setCardType('new')
    handleDeselectPayment()
  }

  const handleSavedCreditCard = async (payment: AvailableAccount) => {
    setCardLastDigits(payment.cardNumber.slice(-4))
    setCardType('saved')
    await setPaymentField({
      paymentSystem: payment.paymentSystem,
      accountId: payment.accountId,
      bin: payment.bin,
    })
    handleDeselectPayment()
    setInstallmentsModalOpen(true)
  }

  const handleInstallmentSelected = async (installment: number) => {
    setInstallmentsModalOpen(false)
    await setPaymentField({
      installments: installment,
    })
    if (cardType === 'saved') {
      history.push(routes.REVIEW)
    } else {
      setStage(PaymentStage.EXTRA_DATA)
    }
  }

  const handleBankInvoiceSelect = async (payment: PaymentSystem) => {
    await setPaymentField({
      paymentSystem: payment.id,
      installments: 1,
      installmentsInterestRate: 0,
      value,
      referenceValue,
    })
    history.push(routes.REVIEW)
  }

  const handleCustomPaymentSelect = async (payment: PaymentSystem) => {
    await setPaymentField({
      paymentSystem: payment.id,
      installments: 1,
      installmentsInterestRate: 0,
      value,
      referenceValue,
    })
    history.push(routes.REVIEW)
  }

  const handleExtraDataSubmit = () => {
    history.push(routes.REVIEW)
  }

  const handleBillingAddressChange = useCallback(
    (address: string | Address) => {
      creditCardRef.current?.updateAddress(address)
    },
    []
  )

  const handleDocumentChange = (doc: string) => {
    creditCardRef.current?.updateDocument(doc)
  }

  return (
    <>
      <div
        className={`${handles.creditCardContainer} ${
          stage === PaymentStage.CARD_FORM ? '' : 'dn'
        }`}
      >
        <CreditCard
          ref={creditCardRef}
          onCardFormCompleted={handleCardFormCompleted}
          onChangePaymentMethod={handleChangePaymentMethod}
          onChangeInstallments={() => setInstallmentsModalOpen(true)}
          cardType={cardType}
          key={cardType}
        />
      </div>
      {stage === PaymentStage.PAYMENT_LIST ? (
        <PaymentList
          onNewCreditCard={handleNewCreditCard}
          onSavedCreditCard={handleSavedCreditCard}
          onBankInvoiceSelect={handleBankInvoiceSelect}
          onCustomPaymentSelect={handleCustomPaymentSelect}
        />
      ) : stage === PaymentStage.EXTRA_DATA ? (
        <ExtraData
          onDeselectPayment={handleChangePaymentMethod}
          cardType={cardType}
          onSubmit={handleExtraDataSubmit}
          onChangeInstallments={() => setInstallmentsModalOpen(true)}
          onBillingAddressChange={handleBillingAddressChange}
          onDocumentChange={handleDocumentChange}
        />
      ) : null}
      <InstallmentsModal
        isOpen={installmentsModalOpen}
        onInstallmentSelected={handleInstallmentSelected}
        onClose={() => setInstallmentsModalOpen(false)}
      />
    </>
  )
}

export default Payment

```


[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 checkout-payment/react/CreditCard.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import classNames from 'classnames'
import React, {
  useState,
  useRef,
  useEffect,
  useCallback,
  useMemo,
  forwardRef,
  useImperativeHandle,
} from 'react'
import { useSSR, useRuntime } from 'vtex.render-runtime'
import { Button, Spinner, ButtonPlain } from 'vtex.styleguide'
import { useIntl, defineMessages } from 'react-intl'
import { PaymentSystem, Address } from 'vtex.checkout-graphql'
import { useOrderForm } from 'vtex.order-manager/OrderForm'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'
import { Modal } from 'vtex.checkout-components'
import { PaymentFlag } from 'vtex.payment-flags'

import styles from './CreditCard.css'
import CardSummary from './CardSummary'
import SelectedCardInstallments from './components/SelectedCardInstallments'

const messages = defineMessages({
  requiredField: {
    id: 'store/checkout-payment.requiredField',
  },
  invalidDigits: {
    id: 'store/checkout-payment.invalidDigits',
  },
  doucmentLabel: {
    id: 'store/checkout-payment.documentLabel',
  },
  installmentsButton: {
    id: 'store/checkout-payment.installmentsButton',
  },
  installmentsOptionsTitle: {
    id: 'store/checkout-payment.installmentsOptionsTitle',
  },
  installmentWithoutValue: {
    id: 'store/checkout-payment.installmentWithoutValue',
  },
  selectedPaymentLabel: { id: 'store/checkout-payment.selectedPaymentLabel' },
  reviewPurchaseLabel: { id: 'store/checkout-payment.reviewPurchaseLabel' },
  viewInstallmentOptionsLabel: {
    id: 'store/checkout-payment.viewInstallmentOptionsLabel',
  },
  cardFormTitle: {
    id: 'store/checkout-payment.cardFormTitle',
  },
})

let postRobot: typeof import('post-robot') | null = null
let iFrameResize: typeof import('iframe-resizer') | null = null

if (window?.document) {
  postRobot = require('post-robot')
  iFrameResize = require('iframe-resizer').iframeResize
}

const IFRAME_APP_VERSION = '0.10.0'
const PORT = 3000

const iframeURLProd = `https://io.vtexpayments.com.br/card-form-ui/${IFRAME_APP_VERSION}/index.html`
const iframeURLDev = `https://checkoutio.vtexlocal.com.br:${PORT}/`

const { production, query } = __RUNTIME__

const LOCAL_IFRAME_DEVELOPMENT =
  !production && query.__localCardUi !== undefined

const iframeURL = LOCAL_IFRAME_DEVELOPMENT ? iframeURLDev : iframeURLProd

interface Props {
  onCardFormCompleted: () => void
  onChangePaymentMethod: () => void
  onChangeInstallments: () => void
  cardType: CardType
}

export interface CreditCardRef {
  resetCardFormData: () => void
  updateAddress: (address: string | Address) => void
  updateDocument: (document: string) => void
}

const CreditCard = forwardRef<CreditCardRef, Props>(function CreditCard(
  {
    onCardFormCompleted,
    onChangePaymentMethod,
    onChangeInstallments,
    cardType,
  },
  ref
) {
  const {
    cardLastDigits,
    payment,
    paymentSystems,
    setCardLastDigits,
    setPaymentField,
    referenceValue,
  } = useOrderPayment()
  const [iframeLoading, setIframeLoading] = useState(true)

  const [
    selectedPaymentSystem,
    setSelectedPaymentSystem,
  ] = useState<PaymentSystem | null>(null)

  const iframeRef = useRef<HTMLIFrameElement>(null)
  const {
    culture: { locale },
  } = useRuntime()
  const isSSR = useSSR()
  const intl = useIntl()
  const { orderForm } = useOrderForm()

  const creditCardPaymentSystems = useMemo(
    () =>
      paymentSystems.filter(
        (paymentSystem: PaymentSystem) =>
          paymentSystem.groupName === 'creditCardPaymentGroup'
      ),
    [paymentSystems]
  )

  const setupIframe = useCallback(async () => {
    iFrameResize?.(
      {
        heightCalculationMethod: 'documentElementOffset',
        checkOrigin: false,
        resizeFrom: 'parent',
        autoResize: true,
      },
      iframeRef.current!
    )

    const stylesheetsUrls = Array.from(
      document.head.querySelectorAll<HTMLLinkElement>('link[rel=stylesheet]')
    ).map(link => link.href)

    await postRobot.send(iframeRef.current!.contentWindow, 'setup', {
      stylesheetsUrls,
      paymentSystems: creditCardPaymentSystems,
    })
    setIframeLoading(false)
  }, [creditCardPaymentSystems])

  const showCardErrors = useCallback(async () => {
    await postRobot.send(iframeRef.current!.contentWindow, 'showCardErrors')
  }, [])

  const resetCardFormData = useCallback(async () => {
    if (iframeRef.current) {
      await postRobot.send(iframeRef.current.contentWindow, 'resetCardFormData')
    }
  }, [])

  const updateAddress = (address: string | Address) => {
    if (!iframeRef.current) {
      return
    }

    postRobot.send(iframeRef.current.contentWindow, 'updateAddress', {
      address,
    })
  }

  const updateDocument = (doc: string) => {
    if (!iframeRef.current) {
      return
    }

    postRobot.send(iframeRef.current.contentWindow, 'updateDocument', {
      document: doc,
    })
  }

  useImperativeHandle(ref, () => ({
    resetCardFormData,
    updateAddress,
    updateDocument,
  }))

  useEffect(function createPaymentSystemListener() {
    const listener = postRobot.on(
      'paymentSystem',
      ({ data }: { data: PaymentSystem }) => {
        setSelectedPaymentSystem(data)
      }
    )
    return () => listener.cancel()
  }, [])

  const [submitLoading, setSubmitLoading] = useState(false)

  const handleSubmit = async () => {
    setSubmitLoading(true)

    try {
      const { data: cardIsValid } = await postRobot.send(
        iframeRef.current!.contentWindow,
        'isCardValid'
      )

      if (!selectedPaymentSystem || !cardIsValid) {
        showCardErrors()
        return
      }

      if (cardType === 'new') {
        const { data: lastDigits } = await postRobot.send(
          iframeRef.current!.contentWindow,
          'getCardLastDigits'
        )

        setCardLastDigits(lastDigits)

        await setPaymentField({
          accountId: null,
          bin: null,
          paymentSystem: selectedPaymentSystem.id,
          referenceValue,
          installments: null,
        })
      }

      onCardFormCompleted()
    } finally {
      setSubmitLoading(false)
    }
  }

  const handleCardSummaryClick = async () => {
    resetCardFormData()
    onChangePaymentMethod()
  }

  const [
    showAvailableInstallmentOptionsModal,
    setShowAvailableInstallmentOptionsModal,
  ] = useState(false)

  const creditCardPayments = useMemo(
    () =>
      orderForm.paymentData.paymentSystems.filter(
        ({ groupName }) => groupName === 'creditCardPaymentGroup'
      ),
    [orderForm]
  )

  const creditCardInstallmentOptions = useMemo(
    () =>
      creditCardPayments
        .map(creditCardPaymentSystem => {
          const creditCardInstallments = orderForm.paymentData.installmentOptions.find(
            installmentOption =>
              creditCardPaymentSystem.id === installmentOption.paymentSystem
          )

          if (!creditCardInstallments) {
            return null
          }

          return {
            ...creditCardInstallments,
            paymentName: creditCardPaymentSystem.name,
          }
        })
        .filter(<T extends any>(value: T | null): value is T => value !== null),
    [orderForm, creditCardPayments]
  )

  if (isSSR) {
    return null
  }

  return (
    <div className="relative w-100">
      <span className="dib t-heading-6 mb5">
        {intl.formatMessage(messages.selectedPaymentLabel)}
      </span>

      {iframeLoading && (
        <div className="absolute top-0 left-0 right-0 bottom-0 bg-white-70 z-1 flex items-center justify-center">
          <Spinner />
        </div>
      )}
      <div className={cardType === 'saved' ? 'mb5' : 'mb3'}>
        <CardSummary
          paymentSystem={
            cardType === 'saved' ? payment.paymentSystem! : undefined
          }
          lastDigits={cardType === 'saved' ? cardLastDigits : undefined}
          onEdit={handleCardSummaryClick}
          description={
            cardType === 'saved' ? (
              <SelectedCardInstallments
                onChangeInstallments={onChangeInstallments}
              />
            ) : (
              <div className="pv3">
                <ButtonPlain
                  onClick={() => setShowAvailableInstallmentOptionsModal(true)}
                >
                  {intl.formatMessage(messages.viewInstallmentOptionsLabel)}
                </ButtonPlain>
              </div>
            )
          }
        />
        <Modal
          isOpen={showAvailableInstallmentOptionsModal}
          onClose={() => setShowAvailableInstallmentOptionsModal(false)}
          title={intl.formatMessage(messages.installmentsOptionsTitle)}
        >
          {creditCardInstallmentOptions.map(
            ({ paymentSystem: paymentSystemId, installments, paymentName }) => (
              <div key={paymentSystemId} className="flex mb4">
                <div className="flex w2 h2">
                  <PaymentFlag paymentSystemId={paymentSystemId} />
                </div>
                <div className="ml5">
                  <span className="t-base fw7">{paymentName}</span>
                  <ul className="list pa0 mb0 mt3">
                    {installments.map(installment => (
                      <li key={installment.count} className="lh-copy mb3">
                        {intl.formatMessage(messages.installmentWithoutValue, {
                          count: installment.count,
                          hasInterestRate: installment.hasInterestRate,
                          interestRate: installment.interestRate,
                        })}
                      </li>
                    ))}
                  </ul>
                </div>
              </div>
            )
          )}
        </Modal>
      </div>

      <iframe
        id="chk-card-form"
        className={classNames(styles.iframe, 'vw-100 w-auto-ns nl5 nh0-ns', {
          [styles.newCard]: cardType === 'new',
          [styles.savedCard]: cardType === 'saved',
        })}
        title={intl.formatMessage(messages.cardFormTitle)}
        // The scrolling attribute is set to 'no' in the iframe tag, as older versions of IE don't allow
        // this to be turned off in code and can just slightly add a bit of extra space to the bottom
        // of the content that it doesn't report when it returns the height.
        scrolling="no"
        frameBorder="0"
        src={`${iframeURL}?locale=${locale}&cardType=${cardType}`}
        onLoad={() => setupIframe()}
        ref={iframeRef}
      />

      <div className="flex mt5">
        <Button
          size="large"
          block
          onClick={handleSubmit}
          isLoading={submitLoading}
        >
          <span className="f5">
            {intl.formatMessage(
              cardType === 'saved'
                ? messages.reviewPurchaseLabel
                : messages.installmentsButton
            )}
          </span>
        </Button>
      </div>
    </div>
  )
})

export default CreditCard

```


[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 checkout-payment/react/CardSummary.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactNode } from 'react'
import { useIntl, defineMessages } from 'react-intl'
import { PaymentFlag } from 'vtex.payment-flags'
import { SelectedCard } from 'vtex.checkout-components'

import CardLabel from './components/CardLabel'

const messages = defineMessages({
  creditCardLabel: {
    id: 'store/checkout-payment.creditCardLabel',
  },
})

interface Props {
  paymentSystem?: string
  lastDigits?: string
  onEdit: () => void
  description?: ReactNode
}

const CardSummary: React.FC<Props> = ({
  paymentSystem,
  lastDigits,
  onEdit,
  description,
}) => {
  const intl = useIntl()

  return (
    <SelectedCard
      className="vw-100 w-auto-ns nl5 nl0-ns"
      onDeselect={onEdit}
      title={
        <span className="inline-flex items-center f5">
          <div className="h1 flex items-center">
            <PaymentFlag paymentSystemId={paymentSystem ?? ''} />
          </div>
          {lastDigits ? (
            <CardLabel
              className="ml3"
              label={intl.formatMessage(messages.creditCardLabel)}
              lastDigits={lastDigits}
            />
          ) : (
            <span className="ml3">
              {intl.formatMessage(messages.creditCardLabel)}
            </span>
          )}
        </span>
      }
      description={description}
    />
  )
}

export default CardSummary

```


[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 checkout-payment/react/package.json from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "test": "vtex-test-tools test",
    "lint": "tsc --noEmit && eslint --ext ts,tsx ."
  },
  "dependencies": {
    "@vtex/css-handles": "^1.0.0",
    "classnames": "^2.2.6",
    "iframe-resizer": "^4.2.10",
    "post-robot": "10.0.35",
    "ramda": "^0.26.1",
    "react": "^16.8.3",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.8.3",
    "react-iframe": "^1.8.0",
    "react-intl": "3.9.1"
  },
  "devDependencies": {
    "@types/classnames": "^2.2.7",
    "@types/iframe-resizer": "^3.5.8",
    "@types/jest": "^24.0.18",
    "@types/node": "^12.7.5",
    "@types/prop-types": "^15.7.0",
    "@types/ramda": "^0.26.5",
    "@types/react": "^16.9.56",
    "@types/react-dom": "^16.9.9",
    "@vtex/test-tools": "^3.3.2",
    "apollo-client": "^2.5.1",
    "vtex.address-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.address-context@0.6.2/public/@types/vtex.address-context",
    "vtex.checkout-components": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-components@0.5.1/public/@types/vtex.checkout-components",
    "vtex.checkout-container": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-container@0.7.0/public/@types/vtex.checkout-container",
    "vtex.checkout-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-graphql@0.56.1/public/@types/vtex.checkout-graphql",
    "vtex.checkout-shipping": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.checkout-shipping@0.6.6/public/@types/vtex.checkout-shipping",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@1.0.0/public/@types/vtex.css-handles",
    "vtex.document-field": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.document-field@0.1.1/public/@types/vtex.document-field",
    "vtex.formatted-price": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.formatted-price@0.4.0/public/@types/vtex.formatted-price",
    "vtex.order-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-manager@0.9.0/public/@types/vtex.order-manager",
    "vtex.order-payment": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.order-payment@0.8.0/public/@types/vtex.order-payment",
    "vtex.payment-flags": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.payment-flags@2.5.1/public/@types/vtex.payment-flags",
    "vtex.place-components": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.place-components@0.14.0/public/@types/vtex.place-components",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.126.11/public/@types/vtex.render-runtime",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.135.3/public/@types/vtex.styleguide"
  },
  "version": "0.16.3"
}

```


[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 checkout-payment/react/PaymentSummary.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'
import { useFormattedPrice } from 'vtex.formatted-price'
import { useIntl, defineMessages, FormattedMessage } from 'react-intl'
import { Installment, InstallmentOption } from 'vtex.checkout-graphql'
import { Alert } from 'vtex.styleguide'
import { OrderForm } from 'vtex.order-manager'
import { useCssHandles } from 'vtex.css-handles'

const { useOrderForm } = OrderForm

const CSS_HANDLES = ['customPaymentSystemName', 'summaryInstallmentsMessage']

const messages = defineMessages({
  installmentValue: {
    id: 'store/checkout-payment.installmentValue',
  },
  summaryInstallments: {
    id: 'store/checkout-payment.summaryInstallments',
  },
  paymentSummaryCardMessage: {
    id: 'store/checkout-payment.paymentSummaryCardMessage',
  },
})

const PaymentSummary: React.FC = () => {
  const {
    installmentOptions,
    paymentSystems,
    payment: { installments: installmentCount, paymentSystem: paymentSystemId },
    cardLastDigits,
    isFreePurchase,
  } = useOrderPayment()

  const { orderForm } = useOrderForm()

  const hasValidProfileData = orderForm.clientProfileData?.isValid ?? false
  const hasValidShippingData = orderForm.shipping.isValid

  const lastStepsValid = hasValidProfileData && hasValidShippingData

  const intl = useIntl()

  const { handles } = useCssHandles(CSS_HANDLES)

  const selectedPaymentSystem = paymentSystems.find(
    paymentSystem => paymentSystem.id === paymentSystemId
  )

  const selectedInstallmentOption = installmentOptions.find(
    (installmentOption: InstallmentOption) =>
      installmentOption.paymentSystem === paymentSystemId
  )

  const selectedInstallment = selectedInstallmentOption?.installments.find(
    (installment: Installment) => installment.count === installmentCount
  )

  const installmentValue = selectedInstallment?.value ?? 0

  const formattedInstallmentValue = useFormattedPrice(installmentValue / 100)

  let summary = null

  const PROMISSORY_PAYMENT_SYSTEM_REGEX = /^custom2([0][1-9]|10)/

  switch (selectedPaymentSystem?.groupName) {
    case 'creditCardPaymentGroup': {
      if (!selectedInstallment) {
        return null
      }

      const installmentsMessage = intl.formatMessage(
        messages.installmentValue,
        {
          installments: selectedInstallment.count,
          value: formattedInstallmentValue,
        }
      )

      summary = (
        <>
          <span>
            {intl.formatMessage(messages.paymentSummaryCardMessage, {
              value: cardLastDigits,
            })}
          </span>
          <span>
            {intl.formatMessage(messages.summaryInstallments, {
              installmentsMessage,
              hasInterestRate: selectedInstallment.hasInterestRate,
            })}
          </span>
        </>
      )

      break
    }
    case 'bankInvoicePaymentGroup': {
      summary = (
        <>
          <span>{selectedPaymentSystem.name}</span>
          <span>
            <FormattedMessage id="store/checkout-payment.boletoGenerationMessage" />
          </span>

          <div className="mt6">
            <Alert type="warning">
              <FormattedMessage id="store/checkout-payment.boletoNotice" />
            </Alert>
          </div>
        </>
      )
      break
    }
    default:
      if (lastStepsValid && isFreePurchase) {
        return (
          <Alert type="success">
            <FormattedMessage id="store/checkout-payment.freePurchase" />
          </Alert>
        )
      }

      if (
        selectedPaymentSystem?.groupName.match(PROMISSORY_PAYMENT_SYSTEM_REGEX)
      ) {
        const installmentsMessage = intl.formatMessage(
          messages.installmentValue,
          {
            installments: selectedInstallment?.count ?? 1,
            value: formattedInstallmentValue,
          }
        )

        summary = (
          <>
            <span className={handles.customPaymentSystemName}>
              {selectedPaymentSystem.name}
            </span>
            <span className={handles.summaryInstallmentsMessage}>
              {intl.formatMessage(messages.summaryInstallments, {
                installmentsMessage,
                hasInterestRate: !!selectedInstallment?.hasInterestRate,
              })}
            </span>
          </>
        )
      } else {
        return null
      }
  }

  return <div className="c-muted-1 flex flex-column lh-copy">{summary}</div>
}

export default PaymentSummary

```


[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 checkout-payment/react/typings/vtex.order-payment.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.order-payment/OrderPayment' {
  export * from 'vtex.order-payment/react/OrderPayment'
  export { default } from 'vtex.order-payment/react/OrderPayment'
}

```


[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 checkout-payment/react/typings/storefront.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

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

declare global {
  interface StorefrontFunctionComponent<P = {}> extends FunctionComponent<P> {
    getSchema?(props: P): object
    schema?: object
  }

  interface StorefrontComponent<P = {}, S = {}> extends Component<P, S> {
    getSchema?(props: P): object
    schema: object
  }
}

```


[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 checkout-payment/react/typings/vtex.order-manager.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.order-manager/OrderForm' {
  export * from 'vtex.order-manager/react/OrderForm'
  export { default } from 'vtex.order-manager/react/OrderForm'
}

```


[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 checkout-payment/react/typings/vtex.render-runtime.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* Typings for `render-runtime` */
declare module 'vtex.render-runtime' {
  import { Component, ComponentType, ReactElement, ReactType } from 'react'

  export interface NavigationOptions {
    page: string
    params?: any
  }

  export interface RenderContextProps {
    runtime: {
      navigate: (options: NavigationOptions) => void
    }
  }

  interface ExtensionPointProps {
    id: string
    [key: string]: any
  }

  export const ExtensionPoint: ComponentType<ExtensionPointProps>

  interface ChildBlockProps {
    id: string
  }

  export const Loading: React.FC
  export const ChildBlock: ComponentType<ChildBlockProps>
  export const useChildBlock = function({ id: string }): object {}
  export const Helmet: ReactElement
  export const Link: ReactType
  export const NoSSR: ReactElement
  export const RenderContextConsumer: ReactElement
  export const canUseDOM: boolean
  export const withRuntimeContext: <TOriginalProps extends {}>(
    Component: ComponentType<TOriginalProps & RenderContextProps>
  ) => ComponentType<TOriginalProps>
  export const useSSR: () => boolean
  export const useRuntime: () => any
}

```


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

[User] Show me the implementation of checkout-payment/react/typings/global.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { RenderContext } from 'vtex.render-runtime'

declare global {
  // eslint-disable-next-line no-redeclare
  const __RUNTIME__: RenderContext

  interface CardFormData {
    encryptedCardNumber: string
    encryptedCardHolder: string
    encryptedExpiryDate: string
    encryptedCsc: string
    lastDigits: string
    paymentSystem: string
    installment?: number
  }

  type CardType = 'new' | 'saved'
}

```


[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 checkout-payment/react/typings/css.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  const css: any
  export default css
}

```


[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 checkout-payment/react/typings/assets.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.svg' {
  const url: string

  export default url
}

```


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

[User] Show me the implementation of checkout-payment/react/typings/graphql.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

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

  const value: DocumentNode
  export default value
}

```


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

[User] Show me the implementation of checkout-payment/react/typings/vtex.styleguide.d.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.styleguide' {
  import React, { ReactNode } from 'react'

  export const Button: React.FC<{ type?: string; block?: boolean }>

  export const Spinner: React.FC

  export const Input: React.FC

  export const IconEdit: React.FC

  export const Alert: React.FC<{ type: 'success' | 'warning' | 'error' }>

  export const Dropdown: React.VFC<{
    label: string
    options: Array<{ value: string; label: string }>
    placeholder?: string
    error?: boolean
    errorMessage?: ReactNode
    value?: string
  } & React.HTMLAttributes<HTMLSelectElement>>
}

export {}

```


[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 checkout-payment/react/enums/PaymentEnums.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
export enum PaymentStage {
  EXTRA_DATA,
  CARD_FORM,
  PAYMENT_LIST,
  FREE_PURCHASE,
}

export enum PaymentType {
  CREDIT_CARD,
  DEBIT_CARD,
}

```


[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 checkout-payment/react/utils/text.ts from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const slugify = (text?: string) => {
  return text
    ?.toLowerCase()
    .replace(/\s+/g, '-')
    .replace(/[()]/g, '')
}

```


[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 checkout-payment/react/components/CardLabel.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactNode } from 'react'

interface Props extends React.HTMLAttributes<HTMLSpanElement> {
  label: ReactNode
  lastDigits: string
}

const CardLabel: React.FC<Props> = ({ label, lastDigits, ...props }) => {
  return (
    <span {...props}>
      {label} ∙∙∙∙ {lastDigits}
    </span>
  )
}

export default CardLabel

```


[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 checkout-payment/react/components/InstallmentsModal.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Installment, InstallmentOption } from 'vtex.checkout-graphql'
import { useIntl, defineMessages, FormattedMessage } from 'react-intl'
import { useFormattedPrice } from 'vtex.formatted-price'
import { ListGroup, GroupOption, Modal } from 'vtex.checkout-components'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'

const messages = defineMessages({
  installmentValue: {
    id: 'store/checkout-payment.installmentValue',
  },
  interestFree: {
    id: 'store/checkout-payment.interestFree',
  },
  installmentsTitle: {
    id: 'store/checkout-payment.installmentsTitle',
  },
  installmentOptionLabel: {
    id: 'store/checkout-payment.installmentOptionLabel',
  },
})

const InstallmentItem: React.FC<{
  installment: Installment
}> = ({ installment }) => {
  const intl = useIntl()

  const formattedPrice = useFormattedPrice(installment!.value! / 100)

  const installmentValue = intl.formatMessage(messages.installmentValue, {
    installments: installment.count,
    value: formattedPrice,
  })

  const interestRateMessage =
    installment.hasInterestRate || installment.count === 1
      ? ''
      : intl.formatMessage(messages.interestFree)

  return (
    <>
      <div className="flex-auto">{installmentValue}</div>
      <div className="flex-none c-success">{interestRateMessage}</div>
    </>
  )
}

interface Props {
  isOpen: boolean
  onInstallmentSelected: (installment: number) => void
  onClose?: () => void
}

const InstallmentsModal: React.FC<Props> = ({
  isOpen,
  onInstallmentSelected,
  onClose = () => {},
}) => {
  const { installmentOptions, payment } = useOrderPayment()

  if (!payment.paymentSystem) {
    return null
  }

  const { paymentSystem: selectedPaymentSystem } = payment

  const installmentOption = installmentOptions.find(
    ({ paymentSystem }: InstallmentOption) =>
      paymentSystem === selectedPaymentSystem
  )

  const { installments } = installmentOption!

  return (
    <Modal
      isOpen={isOpen}
      onClose={onClose}
      title={<FormattedMessage {...messages.installmentsTitle} />}
    >
      <span className="dib mt1 mb3 t-body fw6">
        <FormattedMessage {...messages.installmentOptionLabel} />
      </span>

      <ListGroup borderPosition="bottom">
        {installments.map((installment: Installment, index) => {
          return (
            <GroupOption
              key={installment.count}
              onClick={() => onInstallmentSelected(installment.count)}
              caretAlign="center"
              lean
              isLast={index === installments.length - 1}
            >
              <InstallmentItem installment={installment} />
            </GroupOption>
          )
        })}
      </ListGroup>
    </Modal>
  )
}

export default InstallmentsModal

```


[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 checkout-payment/react/components/BillingAddressForm.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import {
  LocationInput,
  AddressForm,
  useAddressForm,
} from 'vtex.place-components'
import { Utils } from 'vtex.address-context'
import { FormattedMessage } from 'react-intl'

export const createEmptyBillingAddress = () => {
  const { receiverName, ...address } = Utils.createEmptyAddress(true)

  return address
}

const BillingAddressForm: React.VFC<{
  form: ReturnType<typeof useAddressForm>
}> = ({ form }) => {
  return (
    <>
      {form.invalidFields.includes('postalCode') ? (
        <>
          <p className="t-body mt0 mb6">
            <FormattedMessage id="store/checkout-payment.informBillingAddress" />
          </p>
          <LocationInput onSuccess={address => form.setAddress(address)} />
        </>
      ) : (
        <AddressForm
          onResetAddress={() => form.setAddress(createEmptyBillingAddress())}
          form={form}
        />
      )}
    </>
  )
}

export default BillingAddressForm

```


[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 checkout-payment/react/components/ExtraData.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useMemo, useEffect } from 'react'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'
import { defineMessages, useIntl } from 'react-intl'
import { Button, Dropdown } from 'vtex.styleguide'
import { DocumentField } from 'vtex.document-field'
import { useOrderForm } from 'vtex.order-manager/OrderForm'
import { AddressContext, useAddressRules } from 'vtex.address-context'
import { Address } from 'vtex.checkout-graphql'
import { formatAddressToString, useAddressForm } from 'vtex.place-components'
import { Loading } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'

import CardSummary from '../CardSummary'
import SelectedCardInstallments from './SelectedCardInstallments'
import BillingAddressForm, {
  createEmptyBillingAddress,
} from './BillingAddressForm'

const CSS_HANDLES = [
  'extraDataContainer',
  'selectedPaymentLabel',
  'creditCardExtraDataMessage',
  'documentFieldSectionContainer',
  'documentFieldContainer',
  'billingAddressSectionContainer',
  'billingAddressFormContainer',
  'reviewPurchaseButtonContainer',
  'reviewPurchaseButtonLabel',
] as const

const { AddressContextProvider, useAddressContext } = AddressContext

const messages = defineMessages({
  selectedPaymentLabel: { id: 'store/checkout-payment.selectedPaymentLabel' },
  creditCardExtraDataMessage: {
    id: 'store/checkout-payment.creditCardExtraDataMessage',
  },
  reviewPurchaseLabel: {
    id: 'store/checkout-payment.reviewPurchaseLabel',
  },
  documentLabel: {
    id: 'store/checkout-payment.documentLabel',
  },
  requiredField: {
    id: 'store/checkout-payment.requiredField',
  },
  invalidDigits: {
    id: 'store/checkout-payment.invalidDigits',
  },
  billingAddressLabel: {
    id: 'store/checkout-payment.billingAddressLabel',
  },
  newAddressLabel: { id: 'store/checkout-payment.newAddressLabel' },
})

interface Field {
  value: string
  error: boolean
  errorMessage: string
  showError: boolean
}

const initialDocument: Field = {
  value: '',
  error: false,
  errorMessage: '',
  showError: false,
}

const NEW_ADDRESS_VALUE = 'new'

interface Props {
  onDeselectPayment: () => void
  cardType: CardType
  onSubmit: () => void
  onChangeInstallments: () => void
  onDocumentChange: (document: string) => void
  onBillingAddressChange: (address: Address | string) => void
}

const ExtraData: React.VFC<Props> = ({
  onDeselectPayment,
  cardType,
  onSubmit,
  onChangeInstallments,
  onBillingAddressChange,
  onDocumentChange,
}) => {
  const { cardLastDigits, payment, paymentSystems } = useOrderPayment()
  const intl = useIntl()
  const [userDocument, setDocument] = useState<Field>(initialDocument)
  const { handles } = useCssHandles(CSS_HANDLES)

  const documentIsRequired = useMemo(
    () =>
      paymentSystems.find(
        paymentSystem => paymentSystem.id === payment.paymentSystem
      )?.requiresDocument ?? false,
    [payment.paymentSystem, paymentSystems]
  )

  const validateDocument = () => {
    if (!documentIsRequired) {
      return true
    }

    if (!userDocument.value) {
      setDocument(prevDocument => ({
        ...prevDocument,
        showError: true,
        error: true,
        errorMessage: intl.formatMessage(messages.requiredField),
      }))
      return false
    }

    if (userDocument.error) {
      setDocument(prevDocument => ({
        ...prevDocument,
        showError: true,
        errorMessage: intl.formatMessage(messages.invalidDigits),
      }))
      return false
    }

    return true
  }

  const handleChangeDocument = (data: any) => {
    onDocumentChange(data.document)

    setDocument({
      value: data.document,
      error: !data.isValid,
      errorMessage: '',
      showError: false,
    })
  }

  const { orderForm } = useOrderForm()
  const { rules } = useAddressContext()

  const billingAddressesOptions = useMemo(
    () =>
      (
        orderForm.shipping.availableAddresses?.map(availableAddress => ({
          label: formatAddressToString(
            availableAddress!,
            rules[availableAddress!.country as string]
          ),
          value: availableAddress!.addressId!,
        })) ?? []
      ).concat([
        {
          label: intl.formatMessage(messages.newAddressLabel),
          value: NEW_ADDRESS_VALUE,
        },
      ]),
    [orderForm.shipping.availableAddresses, intl, rules]
  )

  const [selectedBillingAddressId, setSelectedBillingAddressId] = useState(
    billingAddressesOptions[0].value
  )

  const billingForm = useAddressForm()

  useEffect(() => {
    const { __typename, ...addressWithoutTypename } = billingForm.address

    if (selectedBillingAddressId !== NEW_ADDRESS_VALUE) {
      onBillingAddressChange(selectedBillingAddressId)
      return
    }

    onBillingAddressChange(addressWithoutTypename)
  }, [selectedBillingAddressId, billingForm.address, onBillingAddressChange])

  const handleSubmit: React.FormEventHandler<HTMLFormElement> = evt => {
    evt.preventDefault()

    const documentIsValid = validateDocument()

    let shouldSubmit = true

    if (cardType === 'new' && !documentIsValid) {
      shouldSubmit = false
    }

    if (
      selectedBillingAddressId === NEW_ADDRESS_VALUE &&
      !billingForm.isValid
    ) {
      billingForm.invalidFields.forEach(field => {
        billingForm.onFieldBlur(field)
      })
      shouldSubmit = false
    }

    if (!shouldSubmit) {
      return
    }

    onSubmit()
  }
  const mustShowDocumentField = cardType === 'new' && documentIsRequired

  return (
    <div className={handles.extraDataContainer}>
      <span className={`${handles.selectedPaymentLabel} dib t-heading-6 mb5`}>
        {intl.formatMessage(messages.selectedPaymentLabel)}
      </span>

      <CardSummary
        lastDigits={cardLastDigits}
        paymentSystem={payment.paymentSystem ?? undefined}
        onEdit={onDeselectPayment}
        description={
          <SelectedCardInstallments
            onChangeInstallments={onChangeInstallments}
          />
        }
      />

      <span
        className={`${handles.creditCardExtraDataMessage} dib mt5 t-body lh-copy`}
      >
        {intl.formatMessage(messages.creditCardExtraDataMessage)}
      </span>

      <form onSubmit={handleSubmit}>
        {mustShowDocumentField && (
          <div
            className={`${handles.documentFieldSectionContainer} mt6 flex items-center`}
          >
            <div
              className={`${handles.documentFieldContainer} w-100 mw-100 mw5-ns`}
            >
              <DocumentField
                label={intl.formatMessage(messages.documentLabel)}
                documentType="cpf"
                onChange={handleChangeDocument}
                onBlur={validateDocument}
                document={userDocument.value}
                error={userDocument.error && userDocument.showError}
                errorMessage={
                  userDocument.showError ? userDocument.errorMessage : ''
                }
              />
            </div>
          </div>
        )}

        <div className={`${handles.billingAddressSectionContainer} mt6`}>
          <Dropdown
            label={intl.formatMessage(messages.billingAddressLabel)}
            options={billingAddressesOptions}
            value={selectedBillingAddressId}
            onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
              const { value } = evt.target

              setSelectedBillingAddressId(value)
              onBillingAddressChange(value)
            }}
          />

          {selectedBillingAddressId === NEW_ADDRESS_VALUE && (
            <div className={`${handles.billingAddressFormContainer} mt6`}>
              <BillingAddressForm form={billingForm} />
            </div>
          )}
        </div>

        <div className={`${handles.reviewPurchaseButtonContainer} mt7`}>
          <Button size="large" block type="submit">
            <span className={`${handles.reviewPurchaseButtonLabel} f5`}>
              {intl.formatMessage(messages.reviewPurchaseLabel)}
            </span>
          </Button>
        </div>
      </form>
    </div>
  )
}

const ExtraDataWithAddress: typeof ExtraData = ({ ...props }) => {
  const addressRules = useAddressRules()

  const { orderForm } = useOrderForm()

  if (addressRules == null) {
    return <Loading />
  }

  return (
    <AddressContextProvider
      address={createEmptyBillingAddress()}
      rules={addressRules}
      countries={orderForm.shipping.countries as string[]}
    >
      <ExtraData {...props} />
    </AddressContextProvider>
  )
}

export default ExtraDataWithAddress

```


[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 checkout-payment/react/components/Header.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

const PageSubTitle: React.FC<{ noMargin?: boolean }> = props => {
  const { children, noMargin } = props

  return <div className={`fw5 ${noMargin ? 'pt5' : 'pv5 mb2'}`}>{children}</div>
}

export default PageSubTitle

```


[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 checkout-payment/react/components/SelectedCardInstallments.tsx from the checkout-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages, useIntl } from 'react-intl'
import { useOrderForm } from 'vtex.order-manager/OrderForm'
import { useFormattedPrice } from 'vtex.formatted-price'
import { ButtonPlain } from 'vtex.styleguide'
import { useOrderPayment } from 'vtex.order-payment/OrderPayment'

const messages = defineMessages({
  installmentValue: {
    id: 'store/checkout-payment.installmentValue',
  },
  changeInstallments: {
    id: 'store/checkout-payment.changeInstallments',
  },
})

interface Props {
  onChangeInstallments: () => void
}

const SelectedCardInstallments: React.FC<Props> = ({
  onChangeInstallments,
}) => {
  const intl = useIntl()
  const { payment } = useOrderPayment()
  const { orderForm } = useOrderForm()

  const installmentOptions = orderForm.paymentData.installmentOptions.find(
    installmentOption =>
      installmentOption.paymentSystem === payment.paymentSystem
  )
  const selectedInstallmentOption = installmentOptions?.installments.find(
    ({ count }) => count === payment.installments
  ) ?? {
    value: 0,
    count: 1,
    hasInterestRate: false,
    interestRate: null,
    total: 0,
    __typename: 'Installment',
  }

  const formattedInstallmentValue = useFormattedPrice(
    (selectedInstallmentOption.value ?? 0) / 100
  )

  return (
    <div className="pv3 flex items-center">
      <span className="c-muted-1">
        {intl.formatMessage(messages.installmentValue, {
          installments: selectedInstallmentOption.count,
          value: formattedInstallmentValue,
        })}
      </span>

      <div className="ml3 flex items-center">
        <ButtonPlain onClick={onChangeInstallments}>
          <span className="ttl">
            {intl.formatMessage(messages.changeInstallments)}
          </span>
        </ButtonPlain>
      </div>
    </div>
  )
}

export default SelectedCardInstallments

```