[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 mycheckout-sdk/src/i18n/messages/pt.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { LOCALES } from '../locales'

export default {
  [LOCALES.PORTUGUESE]: {
    'store/checkoutless.generalMesage.appName': 'Kuikpay',
    'store/checkoutless.generalMesage.loading': 'Carregando...',
    'store/checkoutless.generalError': 'ocorreu um erro',
    'store/checkoutless.generalMessage.or': 'ou',
    'store/checkoutless.generalMessage.in': 'em',
    'store/checkoutless.register.alt.loading': 'Carregando...',
    'store/checkoutless.register.data': 'Dados',
    'store/checkoutless.register.shipping': 'Envio',
    'store/checkoutless.register.noOptions': 'Nenhum resultado encontrado',
    'store/checkoutless.register.payment': 'Forma de pagamento',
    'store/checkoutless.register.email': 'E-mail*',
    'store/checkoutless.register.emailError':
      'O email deve ser um email válido',
    'store/checkoutless.register.name': 'Nome*',
    'store/checkoutless.register.nameError': 'O nome só pode conter letras',
    'store/checkoutless.register.lastname': 'Sobrenome*',
    'store/checkoutless.register.lastnameError':
      'O sobrenome pode conter apenas letras',
    'store/checkoutless.register.neighborhoodError': 'bairro errado',
    'store/checkoutless.register.prefix': 'prefixo*',
    'store/checkoutless.register.phone': 'Telefone*',
    'store/checkoutless.register.phoneError':
      'O telefone só pode conter números e o máximo é 10 dígitos',
    'store/checkoutless.register.documentType': 'Identidade*',
    'store/checkoutless.register.document': 'Número de identificação*',
    'store/checkoutless.register.documentError':
      'Formato de identificação inválido',
    'store/checkoutless.register.habeasData':
      'Li e aceito os {terms} do site. Também aceito as {privacy} e processamento de dados pessoais',
    'store/checkoutless.register.habeasData.terms': 'Termos e Condições',
    'store/checkoutless.register.habeasData.privacy':
      'políticas de privacidade',
    'store/checkoutless.register.country': 'País*',
    'store/checkoutless.register.state': 'Estado*',
    'store/checkoutless.register.city': 'Cidade*',
    'store/checkoutless.register.neighborhood': 'Vizinhança*',
    'store/checkoutless.register.address': 'Endereço*',
    'store/checkoutless.register.addressError': 'Endereço incorreta',
    'store/checkoutless.register.complement': 'Torre, apartamento, escritório',
    'store/checkoutless.register.postalCode': 'Código postal*',
    'store/checkoutless.register.postalCodeError':
      'O código postal pode conter apenas números',
    'store/checkoutless.register.creditCard': 'Cartão de crédito',
    'store/checkoutless.register.creditCardName': 'Nome do cartão de crédito',
    'store/checkoutless.register.creditCardNumber': 'Número de cartão',
    'store/checkoutless.register.creditCardError':
      'Alguns dos campos não são válidos',
    'store/checkoutless.register.payOnReceive': 'pagar ao receber',
    'store/checkoutless.register.customerCredit':
      '{store} compra ahora y paga después',
    'store/checkoutless.register.customerCredit.study.title':
      'Estamos estudando seu perfil',
    'store/checkoutless.register.customerCredit.study.initialmessage':
      'Compra ahora y paga en {quantity} de {value}',
    'store/checkoutless.register.customerCredit.study.description':
      'Estamos validando suas informações',
    'store/checkoutless.register.customerCredit.study.approved.minmessage':
      'Tienes un cupo de {value} para tu compra',
    'store/checkoutless.register.customerCredit.study.approved.title':
      '¡Felicitaciones!',
    'store/checkoutless.register.customerCredit.study.approved.description':
      'Hemos aprobado tu cupo ORION por {value}',
    'store/checkoutless.register.customerCredit.study.approved.message':
      'Tu pago ya puede ser aplicado',
    'store/checkoutless.register.customerCredit.study.deny.title':
      "We're sorry",
    'store/checkoutless.register.customerCredit.study.deny.description':
      'Después de estudiar tu perfil tu cupo ORION no ha sido aprobado, por favor finaliza tu compra con otro medio de pago',
    'store/checkoutless.register.payOnReceiveMessage':
      'No momento da entrega da sua encomenda, o dinheiro será recolhido. Lembre-se de ter o valor exato, pois o transferidor não tem alteração.',
    'store/checkoutless.register.checkoutErrorTitle': 'Erro de pagamento',
    'store/checkoutless.register.checkoutError':
      'Seu pagamento não foi aprovado, por favor tente novamente com um método de pagamento diferente.',
    'store/checkoutless.register.processingPayment':
      'Estamos Criando Seu Pedido',
    'store/checkoutless.register.pay': 'Pagar {price}',
    'store/checkoutless.register.pay.loading': 'Estamos criando seu pedido',
    'store/checkoutless.register.pay.delivery': 'Entrega a domicilio',
    'store/checkoutless.register.pay.pickup-point': 'Recolha em',
    'store/checkoutless.register.pay.total': 'Total a pagar:',
    'store/checkoutless.register.card.name': 'Nome *',
    'store/checkoutless.register.card.nameError': 'O nome é obrigatório',
    'store/checkoutless.register.card.document': 'Número de identificação *',
    'store/checkoutless.register.card.number': 'Número de cartão *',
    'store/checkoutless.register.card.numberError': 'Número de cartão inválido',
    'store/checkoutless.register.card.franchiseError':
      'Esta franquia não está disponível para fechar esta compra. Por favor, tente outro.',
    'store/checkoutless.register.card.dues': 'Quotas *',
    'store/checkoutless.register.card.duesError': 'Probabilidades incorretas',
    'store/checkoutless.register.card.expiryDate': 'MM / YY',
    'store/checkoutless.register.card.expiryDateError': 'Data incorreta',
    'store/checkoutless.register.card.cvv': 'CVC',
    'store/checkoutless.register.card.enterAllFields':
      'Insira todos os campos obrigatórios para continuar',
    'store/checkoutless.register.notAddress':
      'Alguns produtos não estão disponíveis para retirada na loja. Podemos enviá-los para você, por favor, insira suas informações de entrega.',
    'store/checkoutless.register.step.personalData': 'Continuar Meus detalhes',
    'store/checkoutless.register.step.location': 'Continuar minha localização',
    'store/checkoutless.register.step.logistic': 'Continuar Minha Entrega',
    'store/checkoutless.register.step.payment': 'Continuar Meu Pagamento',
    'store/checkoutless.button.loading': 'Carregando',
    'store/checkoutless.button.continue': 'Prosseguir',
    'store/checkoutless.text.select': 'Selecionar',
    'store/checkoutless.button.save': 'Salve',
    'store/checkoutless.button.goShopping': 'ir às compras',
    'store/checkoutless.accessKey.message':
      'Enviamos um código de segurança de 6 dígitos para o seu celular, digite-o para continuar.',
    'store/checkoutless.accessKey.messageError':
      'O código que você digitou não está correto, digite-o novamente.',
    'store/checkoutless.accessKey.sessionExpireTitle':
      'O tempo da sua sessão expirou',
    'store/checkoutless.accessKey.sessionExpireText':
      'Por segurança, bloqueamos o código por {minutes} minuto, tente novamente para concluir seu processo.',
    'store/checkoutless.accessKey.question': 'Você não recebeu o código?',
    'store/checkoutless.accessKey.resendCode': 'Reenviar o código',
    'store/checkoutless.accessKey.newCode': 'solicite um novo código',
    'store/checkoutless.accessKey.oneMinute': 'dentro de 1 minuto',
    'store/checkoutless.accessKey.countdownSecondsMessage':
      'Você pode solicitar um novo código em',
    'store/checkoutless.accessKey.countdownSeconds': '{seconds} segundos',
    'store/checkoutless.logistics.shipping': 'Envio {selectedSla}',
    'store/checkoutless.logistics.packages': 'Você tem 2 entregas programadas',
    'store/checkoutless.logistics.sameDay': 'Mesmo dia',
    'store/checkoutless.logistics.businessDays': 'dias úteis',
    'store/checkoutless.logistics.days': 'dias',
    'store/checkoutless.logistics.minutes': 'minutos',
    'store/checkoutless.logistics.date': 'data de entrega',
    'store/checkoutless.logistics.delivery': 'Domicilio',
    'store/checkoutless.logistics.pickUp': 'Retirada',
    'store/checkoutless.logistics.pickUpInStore': 'Retirada na loja',
    'store/checkoutless.logistics.homeDelivery': 'Entrega a domicilio',
    'store/checkoutless.logistics.endingOrderPackages':
      'Compre {package} de {length}',
    'store/checkoutless.logistics.chooseStore': 'Escolha a loja',
    'store/checkoutless.logistics.chooseShipping': 'Escolha o tipo de entrega',
    'store/checkoutless.logistics.deliveryType':
      'Envio {type} (Receba {in} {days} - {price})',
    'store/checkoutless.logistics.shippingSteps': 'Pacote {step}',
    'store/checkoutless.logistics.packageSteps':
      'Entrega {step} de {totalSteps}',
    'store/checkoutless.logistics.deliveryCost': 'Custo de entrega',
    'store/checkoutless.logistics.freeDeliveryCost': 'Livre',
    'store/checkoutless.orderPlaced.thanks': 'Obrigado pela sua compra!',
    'store/checkoutless.orderPlaced.pending': 'Pagamento pendente de aprovação',
    'store/checkoutless.orderPlaced.pendingMessage':
      'Seu pagamento está sendo processado, iremos notificá-lo assim que for aprovado',
    'store/checkoutless.orderPlaced.confirmationMessage':
      'Enviamos uma cópia da sua fatura eletrônica para o seu e-mail',
    'store/checkoutless.summary.showOrder': 'Meu pedido',
    'store/checkoutless.summary.myOrder': 'Meus pedido',
    'store/checkoutless.summary.MyInfo': 'Meus dados',
    'store/checkoutless.summary.myPersonalData': 'Meus dados pessoais',
    'store/checkoutless.summary.error': 'Não há produtos.',
    'store/checkoutless.summary.hide': 'Ocultar pedido',
    'store/checkoutless.summary.unit': '{quantity} Unidade.',
    'store/checkoutless.summary.unavailable':
      'Esse produto não está disponível no momento',
    'store/checkoutless.summary.unavailableLogistic':
      'Este produto não está disponível para o seu endereço',
    'store/checkoutless.summary.subtotal': 'Subtotal',
    'store/checkoutless.summary.total': 'Total',
    'store/checkoutless.summary.shipping': 'Envio',
    'store/checkoutless.summary.taxes': 'Impostos',
    'store/checkoutless.summary.discounts': 'Descontos',
    'store/checkoutless.summary.isGift': 'A compra inclui',
    'store/checkoutless.summary.notAddress':
      'Alguns produtos não estão disponíveis para retirada na loja. podemos enviá-los para você por favor ',
    'store/checkoutless.summary.nonEditableDelivery':
      'A fim de garantir a disponibilidade de seus produtos, você não pode alterar nem seu método de entrega nem seu endereço selecionado.',
    'store/checkoutless.summary.notAddressLink':
      'insira suas informações de entrega aqui.',
    'store/checkoutless.summary.undefinedTotal': 'Calcular',
    'store/checkoutless.summary.dividedPackage':
      'Dividimos seu pacote em várias entregas',
    'store/checkoutless.summary.productsNotAvailable':
      'Alguns de seus produtos não estão disponíveis para o método de entrega selecionado',
    'store/checkoutless.summary.free': 'Grátis',
    'store/checkoutless.userInfo.unavailableProducts':
      'Os produtos não estão disponíveis para entrega neste endereço. Por favor, mude o endereço ou ',
    'store/checkoutless.userInfo.noProducts':
      'Não há produtos de feno disponíveis para selecionar os dados de entrega',
    'store/checkoutless.userInfo.unavailableLink':
      'remova os produtos do carrinho.',
    'store/checkoutless.userInfo.email': '{customText}',
    'store/checkoutless.userInfo.address': '{customText}',
    'store/checkoutless.userInfo.payment': '{customText}',
    'store/checkoutless.userInfo.addressDeleted':
      'Endereço removido com sucesso',
    'store/checkoutless.userInfo.addressEdited': 'endereço editado com sucesso',
    'store/checkoutless.userInfo.paymentDeleted':
      'Método de pagamento removido com sucesso',
    'store/checkoutless.userInfo.deleteAddressError':
      'Ocorreram problemas ao excluir o endereço, tente novamente mais tarde',
    'store/checkoutless.userInfo.deletePaymentError':
      'Ocorreram problemas ao excluir a forma de pagamento, tente novamente mais tarde',
    'store/checkoutless.userInfo.newAddress': 'Novo endereço',
    'store/checkoutless.userInfo.paymentMethod': 'Meio de pagamento',
    'store/checkoutless.userInfo.addPaymentMethod':
      'Use outro meio de pagamento',
    'store/checkoutless.userInfo.otherPaymentMethod':
      'Outros meios de pagamento',
    'store/checkoutless.userInfo.deleteLink': 'Retirar',
    'store/checkoutless.userInfo.confirmDeleteAddress':
      'Você está prestes a deletar seu endereço {customText}. ',
    'store/checkoutless.userInfo.confirmDeletePayment':
      'Você está prestes a deletar seu cartão de crédito ******** {customText}. ',
    'store/checkoutless.userInfo.myCards': 'Meio de pagamento - Mes cartes',
    'store/checkoutless.card.cardNumberError': 'Digite o número do seu cartão',
    'store/checkoutless.card.cardNumber': 'Número de cartão *',
    'store/checkoutless.card.cardExpirationMonthError': 'Escolha um mês',
    'store/checkoutless.card.cardExpirationYearError': 'Escolha um ano',
    'store/checkoutless.card.identificationTypeError':
      'Insira o seu tipo de documento',
    'store/checkoutless.card.identificationNumberError':
      'Insira o seu documento',
    'store/checkoutless.card.issuerError': 'Entre no seu banco',
    'store/checkoutless.card.cardholderNameError':
      'Insira o nome e o sobrenome',
    'store/checkoutless.card.securityCodeCVV': 'CVV *',
    'store/checkoutless.card.cvv': 'cvv',
    'store/checkoutless.card.securityCodeError': 'Digite o código de segurança',
    'store/checkoutless.card.invalidCardNumberError':
      'Por favor, insira um número de cartão válido',
    'store/checkoutless.card.invalidSecurityCodeError':
      'Verifique o código de segurança',
    'store/checkoutless.card.invalidcardholderNameError':
      'Por favor, indique um nome válido',
    'store/checkoutless.card.invalidIdentificationTypeError':
      'O tipo de documento é inválido',
    'store/checkoutless.card.invalidIdentificationNumberError':
      'O documento é inválido',
    'store/checkoutless.card.invalidCardExpirationMonthError':
      'O mês é inválido',
    'store/checkoutless.card.invalidCardExpirationYearError':
      'O ano é inválido',
    'store/checkoutless.card.defaultError': 'Revisa los datos',
    'store/checkoutless.card.invalidCardExpirationError':
      'A data de validade não é válida',
    'store/checkoutless.location.unAvailable':
      'Os dados de localização não estão disponíveis, aceite as permissões de localização e tente novamente',
    'store/checkoutless.location.notSuported':
      'Geolocalização não suportada em seu navegador, atualize-o',
    'store/checkoutless.location.denied':
      'acesso ao local negado, para usar a funcionalidade você deve alterar as permissões do navegador',
    'store/checkoutless.location.generalError':
      'Ocorreu um erro ao obter a localização do navegador, tente novamente mais tarde',
    'store/checkoutless.location.zeroResults':
      'Nenhum resultado encontrado para sua localização atual, insira o endereço manualmente',
    'store/checkoutless.location.imgText':
      'Estamos atualizando sua localização',
    'store/checkoutless.location.userLocation': 'Usar minha localização atual',
    'store/checkoutless.location.EnterCity':
      'Informe a cidade onde você receberá seu pedido',
    'store/checkoutless.card.securityCode': 'Código de segurança',
    'store/checkoutless.next': 'Prosseguir',
    'store/checkoutless.card.cvcInfo':
      'Corresponde aos 3 ou 4 dígitos localizados no verso do seu cartão.',
    'store/checkoutless.validateItems.text':
      'Os produtos a seguir não estão disponíveis para pagamento por nossa plataforma',
    'store/checkoutless.register.customerCredit.fail':
      'No cuentas con el cupo ORION suficiente para finalizar la compra',
    'store/checkoutless.validateItems.description':
      'Para continuar, você pode excluí-los ou fazer sua compra no caixa',
    'store/checkoutless.validateItems.deleteAndContinue': 'Excluir e continuar',
    'store/checkoutless.validateItems.checkout': 'Vá para o checkout',
    'store/checkoutless.multiplePackages.text':
      'Seu pedido foi dividido em várias entregas',
    'store/checkoutless.multiplePackages.description':
      'Para continuar com sua compra você deve ir ao checkout',
    'store/checkoutless.coupon': 'Código de desconto',
    'store/checkoutless.coupon.action': 'Aplicar',
    'store/checkoutless.coupon.textInput': 'Eu tenho um código de desconto',
    'store/checkoutless.coupon.error':
      'Cupom inválido, por favor insira novamente',
    'store/checkoutless.coupon.success': 'Seu cupom foi adicionado com sucesso',
    'store/checkoutless.attachment.add': 'Adicionar',
    'store/checkoutless.skuSelector.close': 'Adicionar e continuar comprando',
    'store/checkoutless.emptyCart.emptyOrder': 'Seu pedido está vazio',
    'store/checkoutless.emptyCart.message':
      'Seu pedido está vazio, continue com sua compra',
    'store/checkoutless.emptyCart.messageDeskopt':
      'Prossiga para a loja com sua compra.',
    'store/checkoutless.userInfo.close': 'Continue comprando',
    'store/quota.productdetails.quotainformation':
      'Compra ahora y paga después con {store} en {quotas} mensuales de {value}',
    'store/quota.modal.quotainformation.description':
      'Compra ahora y paga después con {store} en cuotas libres de interés.',
    'store/quota.modal.quotainformation.instruction-1':
      'Antójate y selecciona tu producto favorito.',
    'store/quota.modal.quotainformation.instruction-2':
      'Selecciona comprar ahora y pagar después con ORION.',
    'store/quota.modal.quotainformation.instruction-3':
      'Tu compra se distribuirá en cuotas de igual valor, dependiendo del monto final comprado sin intereses.',
    'store/quota.modal.quotainformation.instruction-4':
      'Tendrás multiples opciones para pagar. Tu primera cuota será cargada el día de despacho del producto y las siguientes en cuotas mensuales.',
    'store/checkoutless.security': 'Compra 100% segura',
    'store/checkoutless.user.sorry': 'SENTIMOS MUITO !',
    'store/checkoutless.user.error':
      'Ocorreu um erro ao carregar as informações, tente novamente',
    'store/checkoutless.user.error.retry': 'Tente novamente',
    'store/checkoutless.userInfo.address.alternative':
      'Esta dirección esta actualizada con la tienda',
    'store/checkoutless.user.userEditedMessageHeader':
      'Você editou seus dados com sucesso',
    'store/checkoutless.user.userEditedMessageText':
      'Agora você pode continuar com seu pagamento 100% seguro',
    'store/checkoutless.user.addressEditedMessageHeader':
      'Você editou seu endereço residencial corretamente',
    'store/checkoutless.user.addressEditedMessageText':
      'Agora você pode continuar com seu pagamento 100% seguro',
    'store/checkoutless.alert.selectionOfVariations':
      'Por favor, escolha suas preferências de produto para continuar com sua compra',
    'store/checkoutless.user.addAddresInfo': 'Digite seu endereço',
    'store/checkoutless.user.addPaymentInfo': 'Selecione o tipo de pagamento',
    'store/checkoutless.loading.almostThere':
      'Falta pouco para concluir sua compra',
    'store/checkoutless.textAlertCvv':
      'Favor inserir o código CVV para continuar com seu pagamento',
    'store/checkoutless.descriptionAlertCvv':
      'Complete seus dados de pagamento e proceda ao pagamento 100% seguro.',
  },
}

```


[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 mycheckout-sdk/src/i18n/messages/index.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import es from './es'
import en from './en'
import pt from './pt'

export default {
  ...es,
  ...en,
  ...pt,
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/utils.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { Item } from '../../interfaces'
import { getCookie, setCookie, removeAccents } from '../../utils'
import { COOKIE_NAME_GTM } from '../../utils/constants'
import type { ProductGTM, StepGTM, StepsCookieGTM } from './InterfacesGTM'

export const formatProducts = (items: Item[]): ProductGTM[] | void => {
  try {
    return items.map((item: Item) => {
      const { sellingPrice, listPrice } = item
      const price = Number.isNaN(sellingPrice) ? listPrice : sellingPrice

      return {
        name: item.name,
        id: item.id,
        price,
        brand: item.additionalInfo.brandName,
        category: item.productCategories[1],
        variant: item.refId,
        quantity: item.quantity,
      }
    })
  } catch (error) {
    console.error('Error format products', error)
  }
}

export const existStepInCookie = (step: number): boolean => {
  try {
    const cookieGtm: StepsCookieGTM = getCookie(COOKIE_NAME_GTM)
      ? JSON.parse(getCookie(COOKIE_NAME_GTM))
      : null

    return !!cookieGtm?.steps?.some((e: StepGTM) => e.step === step)
  } catch (error) {
    console.error('Error exist step in cookie:', error)

    return false
  }
}

export const changeOptionInCookieByStep = (
  step: number,
  option: string
): boolean => {
  try {
    const optionNormalize = removeAccents(option)

    if (!optionNormalize) return false
    const cookieGtm: StepsCookieGTM = getCookie(COOKIE_NAME_GTM)
      ? JSON.parse(getCookie(COOKIE_NAME_GTM))
      : null

    return !!cookieGtm?.steps?.some(
      (e: StepGTM) => e.step === step && e.option !== optionNormalize
    )
  } catch (error) {
    console.error('Error change option in cookie by step', error)

    return false
  }
}

export const updateOptionInCookieByStep = (
  step: number,
  option: string
): void => {
  try {
    const cookieGtm: StepsCookieGTM = getCookie(COOKIE_NAME_GTM)
      ? JSON.parse(getCookie(COOKIE_NAME_GTM))
      : null

    const optionNormalize = removeAccents(option)

    cookieGtm?.steps?.map((e: StepGTM, index: number) => {
      e.step === step ? (cookieGtm.steps[index].option = optionNormalize) : null
      setCookie(COOKIE_NAME_GTM, cookieGtm, 1)

      return true
    })
  } catch (error) {
    console.error('Error update option in cookie by step: ', error)
  }
}

export const setStepInCookie = (step: number, option: string = null): void => {
  try {
    let cookieGtm: StepsCookieGTM = getCookie(COOKIE_NAME_GTM)
      ? JSON.parse(getCookie(COOKIE_NAME_GTM))
      : null

    const optionNormalize = removeAccents(option)

    if (cookieGtm) {
      cookieGtm.steps.push({ step, option: optionNormalize })
    } else {
      cookieGtm = { steps: [{ step, option: optionNormalize }] }
    }

    setCookie(COOKIE_NAME_GTM, cookieGtm, 1)
  } catch (error) {
    console.error('Error set step in cookie: ', error)
  }
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/MeasurePurchaseProcess.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { Item } from '../../interfaces'
import { stepByName } from '../../utils/constants'
import { CheckoutOption } from './CheckoutOption'
import {
  changeOptionInCookieByStep,
  existStepInCookie,
  formatProducts,
  setStepInCookie,
} from './utils'

interface Props {
  stepName: string
  items?: Item[]
  option?: string
  hasGoogleAnalytics?: boolean
}
export const MeasurePurchaseProcess = ({
  stepName,
  option = null,
  items = null,
  hasGoogleAnalytics = false,
}: Props) => {
  try {
    if (hasGoogleAnalytics && window.dataLayer) {
      const step = stepByName[stepName]

      if (!existStepInCookie(step)) {
        const products = items ? formatProducts(items) : null

        const data = {
          event: 'checkout',
          eventSource: 'myCheckout',
          ecommerce: {
            checkout: {
              actionField: { step, option },
              products,
            },
          },
        }

        if (!option) delete data.ecommerce.checkout.actionField.option
        if (!items) delete data.ecommerce.checkout.products

        window.dataLayer.push({ ecommerce: null })
        window.dataLayer.push(data)
        setStepInCookie(step, option)
      } else if (changeOptionInCookieByStep(step, option)) {
        CheckoutOption({ stepName, option, hasGoogleAnalytics })
      }
    }
  } catch (e) {
    console.error('Error - Measure purchase process GTM: ', e)
  }
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/CheckoutOption.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { stepByName } from '../../utils/constants'
import { updateOptionInCookieByStep } from './utils'

interface Props {
  stepName: string
  option?: string
  hasGoogleAnalytics?: boolean
}
export const CheckoutOption = ({
  stepName,
  option,
  hasGoogleAnalytics,
}: Props) => {
  try {
    if (hasGoogleAnalytics && window.dataLayer) {
      const step = stepByName[stepName]
      const data = {
        event: 'eec.checkout_option',
        eventSource: 'myCheckout',
        ecommerce: {
          checkout_option: {
            actionField: {
              step,
              option,
            },
          },
        },
      }

      window.dataLayer.push({ ecommerce: null })
      window.dataLayer.push(data)
      updateOptionInCookieByStep(step, option)
    }
  } catch (e) {
    console.error('Error - Checkout Option GTM: ', e)
  }
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/SubmitBuy.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { Item, Totalizer } from '../../interfaces'
import { formatProducts } from './utils'

export const SubmitBuy = (
  items: Item[],
  transactionId: string,
  totalizers: Totalizer[],
  value: number,
  hasGoogleAnalytics?: boolean
) => {
  try {
    if (hasGoogleAnalytics && window.dataLayer) {
      const [shipping, tax] = totalizers.filter(
        (totalizer: Totalizer) =>
          totalizer.id === 'Shipping' || totalizer.id === 'Tax'
      )

      const products = formatProducts(items)

      window.dataLayer.push({ ecommerce: null })
      window.dataLayer.push({
        eventSource: 'myCheckout',
        ecommerce: {
          purchase: {
            actionField: {
              id: transactionId,
              revenue: value,
              tax: tax ? tax.value / 100 : 0,
              shipping: shipping ? shipping.value / 100 : 0,
            },
            products,
          },
        },
      })
    }
  } catch (e) {
    console.error('Error - Submit item removed from cart GTM: ', e)
  }
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/InterfacesGTM.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface ProductGTM {
  name: string
  id: string
  price: number
  brand: unknown
  category: string
  variant: string
  quantity: number
}

export interface StepGTM {
  step: number
  option?: string
}

export interface StepsCookieGTM {
  steps: StepGTM[]
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/SubmitItemAddedToCart.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ItemToAdd, Product, ProductItem } from '../../interfaces'
import constants from '../../utils/constants'

interface Props {
  selectedItem: ProductItem
  product: Product
  itemToAdd: ItemToAdd
  hasGoogleAnalytics?: boolean
}
export const SubmitItemAddedToCart = ({
  selectedItem,
  product,
  itemToAdd,
  hasGoogleAnalytics,
}: Props) => {
  try {
    if (hasGoogleAnalytics && window.dataLayer) {
      const { Price } = selectedItem?.sellers[0]?.commertialOffer

      window.dataLayer.push({ ecommerce: null })
      window.dataLayer.push({
        event: 'addToCart',
        eventSource: 'myCheckout',
        ecommerce: {
          currencyCode: constants.currencyCode,
          add: {
            products: [
              {
                name: selectedItem?.nameComplete,
                id: selectedItem?.itemId,
                price: Price,
                brand: product.brand,
                category: product.categories[0],
                variant: product.productReference,
                quantity: itemToAdd?.quantity,
              },
            ],
          },
        },
      })
    }
  } catch (e) {
    console.error('Error - Submit item added to cart GTM: ', e)
  }
}

```


[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 mycheckout-sdk/src/services/GoogleTagManager/index.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
export { SubmitItemAddedToCart } from './SubmitItemAddedToCart'
export { SubmitItemRemovedFromCart } from './SubmitItemRemovedFromCart'
export { SubmitBuy } from './SubmitBuy'
export { MeasurePurchaseProcess } from './MeasurePurchaseProcess'
export { CheckoutOption } from './CheckoutOption'
declare global {
  interface Window {
    dataLayer: any
  }
}

```


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

[User] Show me the implementation of mycheckout-sdk/src/services/GoogleTagManager/SubmitItemRemovedFromCart.ts from the mycheckout-sdk VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { Item } from '../../interfaces'
import constants from '../../utils/constants'

export const SubmitItemRemovedFromCart = (
  item: Item,
  hasGoogleAnalytics?: boolean
) => {
  try {
    if (hasGoogleAnalytics && window.dataLayer) {
      const { sellingPrice, listPrice } = item
      const price = Number.isNaN(sellingPrice) ? listPrice : sellingPrice

      window.dataLayer.push({ ecommerce: null })
      window.dataLayer.push({
        event: 'removeFromCart',
        eventSource: 'myCheckout',
        ecommerce: {
          currencyCode: constants.currencyCode,
          add: {
            products: [
              {
                name: item?.name,
                id: item?.id,
                price,
                brand: item.additionalInfo.brandName,
                category: item.productCategories[1],
                variant: item.refId,
                quantity: item?.quantity,
              },
            ],
          },
        },
      })
    }
  } catch (e) {
    console.error('Error - Submit item removed from cart GTM: ', e)
  }
}

```


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

[Assistant]
Here's the implementation:

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

# Affirm Payment

This is a payment authorization app for the Affirm payment method (financing with monthly payments). By installing this app, the [Affirm payment connector app](https://github.com/vtex-apps/affirm-api) will also be automatically installed as a dependency.

> ⚠ _Currently Affirm cannot be used in a marketplace scenario where the seller account processes the payment. In marketplace scenarios, the marketplace account must process the payment._

## Configuration

1. [Install this app](https://vtex.io/docs/recipes/development/installing-an-app/) in your account by running `vtex install vtex.affirm-payment`.
2. Enable Affirm as a payment method in your store admin. In the Gateway Affiliation, enter your Affirm public API key as the `Application Key` and your Affirm private API key as the `Application Token`. For initial testing, set the Test/Production toggle to `Test` and use sandbox keys.
3. Configure the app settings by clicking `Apps > My Apps` in your account's admin sidebar and then selecting `Affirm Payment`.

The available settings are:

- `Enable Katapult`: Katapult is a newer Affirm feature that offers a leasing option to shoppers who do not qualify for the normal Affirm financing. Please ask your Affirm contact to enable the feature on your Affirm account before enabling this app setting.
- `Company Name`: If you have multiple sites operating under a single Affirm account, you can override the external company/brand name that the customer sees. This affects all references to your company name in the Affirm UI. Leave blank to use your default company name stored in your Affirm account.
- `Public API Key for promotional components`: The public API key provided to you by Affirm.
- `Production Mode for promotional components`: Determines if the components from the [Affirm Components](https://github.com/vtex-apps/affirm-components) app run in Production or Sandbox mode.
- `Interval to use for the following three settings`: Determines the unit of time used by the following settings.
- `Delay to automatic payment capture`: Number of minutes/hours/days before authorized Affirm payments are automatically settled.
- `Delay to automatic payment capture after antifraud analysis`: Number of minutes/hours/days before authorized Affirm payments are automatically settled after merchant's antifraud approval.
- `Delay to cancel`: Number of minutes/hours/days before Affirm payments are automatically canceled.
  > ⚠ _`Delay to cancel` also affects the amount of time the user is given to complete the Affirm checkout modal. As such, the app will enforce a minimum `delay to cancel` time of 60 minutes. Shorter times may be inputted on the settings page, but they will be ignored. Also, times longer than 1 day should not be used._
- `Katapult public token`: The public API token for your Katapult account. This is only needed if Katapult is enabled.
- `Katapult private token`: The private API token for your Katapult account. This is only needed if Katapult is enabled.
- `Partial cancellation`: Feature flag to enable partial cancellation feature, which when enabled, ensures that the amount for partially canceled items on order is voided during settlement.

```


[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 affirm-payment/graphql/schema.graphql from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```graphql
# queries
type AffirmSettings {
  isLive: Boolean
  enableKatapult: Boolean
  companyName: String
  publicApiKey: String
}

type PaymentRequest {
  reference: String
  transactionId: String
  paymentId: String
  orderId: String
  paymentMethod: String
  merchantName: String
  value: Float
  currency: String
  installments: Int
  deviceFingerprint: String
  card: Card
  miniCart: MiniCart
  url: String
  callbackUrl: String
  returnUrl: String
  inboundRequestsUrl: String
}

type Expiration {
  month: String
  year: String
}

type Card {
  holder: String
  number: String
  csc: String
  expiration: Expiration
}

type Buyer {
  id: String
  firstName: String
  lastName: String
  document: String
  documentType: String
  email: String
  phone: String
}

type ShippingAddress {
  country: String
  street: String
  number: String
  complement: String
  neighborhood: String
  postalCode: String
  city: String
  state: String
}

type BillingAddress {
  country: String
  street: String
  number: String
  complement: String
  neighborhood: String
  postalCode: String
  city: String
  state: String
}

type Item {
  id: String
  name: String
  price: Float
  quantity: Int
  discount: Float
}

type MiniCart {
  shippingValue: Float
  taxValue: Float
  buyer: Buyer
  shippingAddress: ShippingAddress
  billingAddress: BillingAddress
  items: [Item]
}

type PaymentResponse {
  paymentId: String
  status: String
  tid: String
  authorizationId: String
  nsu: String
  acquirer: String
  paymentUrl: String
  identificationNumber: String
  identificationNumberFormatted: String
  barCodeImageType: String
  barCodeImageNumber: String
  code: String
  message: String
  delayToAutoSettle: Int
  delayToAutoSettleAfterAntiFraud: Int
  delayToCancel: Int
}

type Query {
  affirmSettings: AffirmSettings @cacheControl(scope: PUBLIC, maxAge: MEDIUM)
  orderData(qs: String): PaymentRequest
}

type Mutation {
  orderUpdate(
    inboundUrl: String
    orderId: String
    token: String
    callbackUrl: String
    orderTotal: Int
  ): PaymentResponse @cacheControl (scope: PRIVATE)
}

```


[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 affirm-payment/node/service.json from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 128,
  "ttl": 60,
  "timeout": 20,
  "minReplicas": 2,
  "maxReplicas": 4,
  "workers": 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 affirm-payment/node/typings.d.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface AffirmSettings {
  isLive: boolean
  companyName: string
  publicApiKey: string
}

interface PaymentRequestPayload {
  inboundUrl: string
  orderId: string
  token: string
  callbackUrl: string
  orderTotal: number
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "affirm-payment",
  "version": "2.3.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "graphql": "^14.2.1",
    "typescript": "3.9.7"
  },
  "devDependencies": {
    "@vtex/api": "6.45.12",
    "vtex.store": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.122.0/public/@types/vtex.store",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.145.2/public/@types/vtex.styleguide"
  }
}

```


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

[User] Show me the implementation of affirm-payment/node/global.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

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

import { Clients } from './clients'

declare global {
  type Context = ServiceContext<Clients>
}

```


[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 affirm-payment/node/index.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

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

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

export default new Service({
  clients,
  graphql: {
    resolvers: {
      Query: {
        ...queries,
      },
      Mutation: {
        ...mutations,
      },
    },
  },
})

```


[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 affirm-payment/pages/pages.json from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "extensions": {
    "checkout/transactions/affirm-payment": {
      "component": "AffirmModal"
    }
  }
}

```


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

[Assistant]
Here's the implementation:

```tsx
import AffirmModal from './components/AffirmModal'

export default AffirmModal

```


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

[Assistant]
Here's the implementation:

```json
{
  "name": "affirm-payment",
  "version": "2.3.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "VTEX",
  "license": "UNLICENSED",
  "dependencies": {
    "apollo-cache": "^1.3.4",
    "apollo-client": "2.5.1",
    "apollo-link": "^1.2.13",
    "apollo-utilities": "^1.3.3",
    "graphql": "^14.0.2",
    "react": "^16.8.6",
    "react-apollo": "2.5.5",
    "react-dom": "^16.8.5",
    "react-helmet": "^5.2.0"
  },
  "devDependencies": {
    "@types/bootstrap": "^4.3.0",
    "@types/graphql": "^14.0.5",
    "@types/jquery": "^3.3.34",
    "@types/node": "^10.14.4",
    "@types/ramda": "^0.27.0",
    "@types/react": "^16.8.8",
    "@types/react-dom": "^16.8.3",
    "@types/react-helmet": "^5.0.8",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@7.45.0/public/@types/vtex.render-runtime",
    "vtex.store": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store@2.122.0/public/@types/vtex.store",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.145.2/public/@types/vtex.styleguide"
  }
}

```


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

[User] Show me the implementation of affirm-payment/node/clients/index.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { AuthType, ClientsConfig, IOClients, LRUCache } from '@vtex/api'

import AffirmDataSource from './payments'
import AffirmProxyDataSource from './paymentsProxy'

const TIMEOUT_MS = 8000

const defaultClientOptions = {
  retries: 2,
  timeout: TIMEOUT_MS,
}

const memoryCache = new LRUCache<string, any>({ max: 5000 })
metrics.trackCache('affirm-payment', memoryCache)

export class Clients extends IOClients {
  public get payments(): AffirmDataSource {
    return this.getOrSet('payments', AffirmDataSource)
  }

  public get paymentsProxy(): AffirmProxyDataSource {
    return this.getOrSet('paymentsProxy', AffirmProxyDataSource)
  }
}

export const clients: ClientsConfig<Clients> = {
  implementation: Clients,
  options: {
    default: defaultClientOptions,
    payments: {
      authType: AuthType.bearer,
      memoryCache,
    },
    paymentsProxy: {
      authType: AuthType.bearer,
      memoryCache,
    },
  },
}

```


[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 affirm-payment/node/clients/payments.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

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

export default class AffirmDataSource extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(``, context, options)
  }

  public getPaymentRequest = (
    qs: string,
    account: string = this.context.account,
    workspace: string = this.context.workspace
  ) => {
    const base = this.baseUrl(account, workspace)

    return this.http.get(`${base}/payments/${qs}/request`, {
      metric: 'payment-request',
    })
  }

  public baseUrl = (account: string, workspace: string) => {
    return `http://${workspace}--${account}.${process.env.VTEX_PUBLIC_ENDPOINT}/affirm/payment-provider`
  }
}

```


[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 affirm-payment/node/clients/paymentsProxy.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

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

export default class AffirmProxyDataSource extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(``, context, options)
  }

  public updatePaymentRequest = ({
    inboundUrl,
    orderId,
    token,
    callbackUrl,
    orderTotal,
  }: PaymentRequestPayload) =>
    this.http.post(
      inboundUrl,
      {
        token,
        orderId,
        callbackUrl,
        orderTotal,
      },
      { metric: 'payment-update' }
    )
}

```


[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 affirm-payment/node/resolvers/affirm.ts from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const queries = {
  affirmSettings: async (_: void, __: void, ctx: Context) => {
    const appId = process.env.VTEX_APP_ID as string
    const settings = await ctx.clients.apps.getAppSettings(appId)
    return settings
  },
  orderData: async (_: void, { qs }: { qs: string }, ctx: Context) => {
    const {
      clients: { licenseManager, payments },
      vtex: { account, authToken, logger },
    } = ctx

    // if this is a subaccount, accountName will be the name of the main account
    const { accountName } = await licenseManager
      .getAccountData(authToken)
      .catch(error => {
        logger.error({
          message: 'getAccountData-error',
          error,
        })
        return {}
      })

    return payments.getPaymentRequest(
      qs,
      accountName,
      accountName === account ? undefined : 'master' // if this is a subaccount, send request to master workspace of main account
    )
  },
}

export const mutations = {
  orderUpdate: async (
    _: void,
    {
      inboundUrl,
      orderId,
      token,
      callbackUrl,
      orderTotal,
    }: PaymentRequestPayload,
    ctx: Context
  ) => {
    const {
      clients: { paymentsProxy },
    } = ctx

    return paymentsProxy.updatePaymentRequest({
      inboundUrl,
      orderId,
      token,
      callbackUrl,
      orderTotal,
    })
  },
}

```


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

[Assistant]
Here's the implementation:

```typescript
declare const vtex: any
interface Window extends Window {
  affirm: any
  _affirm_config: any
  modalTriggered: boolean
}

```


[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 affirm-payment/react/typings/graphql.d.ts from the affirm-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 affirm-payment/react/components/AffirmModal.tsx from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component } from 'react'
import Helmet from 'react-helmet'
import { graphql, MutationOptions, FetchResult } from 'react-apollo'

import withSettings from './withSettings'
import withOrderData from './withOrderData'
import OrderUpdate from '../graphql/OrderUpdate.graphql'

interface AffirmAuthenticationProps {
  appPayload: string
  settings: AffirmSettings
  orderData: OrderData
  orderUpdateMutation(options?: MutationOptions): Promise<FetchResult>
}

interface AffirmSettings {
  enableKatapult: boolean
  companyName: string
}

interface OrderData {
  transactionId: string
  orderId: string
  miniCart: any
  value: number
  inboundRequestsUrl: string
  callbackUrl: string
}

declare const vtex: any
declare const $: any

const version = process.env.VTEX_APP_VERSION

class AffirmModal extends Component<AffirmAuthenticationProps> {
  public state = {
    scriptLoaded: false,
  }

  public componentWillMount = () => {
    this.inject()
    window.modalTriggered = false
  }

  public async inject() {
    const { sandboxMode } = JSON.parse(this.props.appPayload)

    const affirmUrl = !sandboxMode
      ? `https://cdn1.affirm.com/js/v2/affirm`
      : `https://cdn1-sandbox.affirm.com/js/v2/affirm`

    this.injectScript(
      'affirm-checkout-sdk-js',
      `${affirmUrl}.js`,
      this.handleOnLoad
    )
  }

  public affirm: any = {}

  public async respondTransaction(status: boolean) {
    if (!status) {
      await fetch(
        `${this.props.orderData.callbackUrl}?tid=${this.props.orderData.transactionId}&message=Modal failed or was closed by user&status=denied`,
        {
          method: 'post',
          mode: 'no-cors',
        }
      )
    }
    $(window).trigger('transactionValidation.vtex', [status])
  }

  public injectScript = (id: string, src: string, onLoad: () => void) => {
    if (document.getElementById(id)) {
      return
    }

    // eslint-disable-next-line prefer-destructuring
    const head = document.getElementsByTagName('head')[0]

    const js = document.createElement('script')
    js.id = id
    js.src = src
    js.async = true
    js.defer = true
    js.onload = onLoad

    head.appendChild(js)
  }

  public handleOnLoad = () => {
    this.setState({ scriptLoaded: true })
  }

  public componentDidUpdate() {
    const {
      orderData,
      orderData: { miniCart },
      settings: { companyName, enableKatapult },
      orderUpdateMutation,
    } = this.props
    const { scriptLoaded } = this.state

    const { publicKey } = JSON.parse(this.props.appPayload)
    if (!scriptLoaded || window.modalTriggered) return
    window.modalTriggered = true
    $(window).on('beforeunload', () => {
      return ''
    })
    window._affirm_config = {
      public_api_key: publicKey,
    }
    const affirmItems = orderData.miniCart.items.map((item: any) => ({
      leasable: true,
      display_name: item.name,
      sku: item.id,
      unit_price: Math.round(item.price * 100),
      qty: item.quantity,
    }))
    let discountTotal = 0
    orderData.miniCart.items.forEach((item: any) => {
      discountTotal += item.discount * -1
    })
    const discountsObject =
      discountTotal > 0
        ? {
            DISCOUNT: {
              discount_amount: Math.round(discountTotal * 100),
              discount_display_name: 'Discount',
            },
          }
        : {}
    window.affirm.checkout({
      merchant: {
        exchange_lease_enabled: enableKatapult,
        name: companyName || undefined,
        user_confirmation_url: '',
        user_cancel_url: '',
        user_confirmation_url_action: 'GET',
      },
      shipping: {
        name: {
          first: miniCart.buyer.firstName,
          last: miniCart.buyer.lastName,
        },
        address: {
          line1: miniCart.shippingAddress.street,
          line2: miniCart.shippingAddress.complement,
          city: miniCart.shippingAddress.city,
          state: miniCart.shippingAddress.state,
          zipcode: miniCart.shippingAddress.postalCode,
          country: miniCart.shippingAddress.country,
        },
        phone_number: miniCart.buyer.phone,
        email: miniCart.buyer.email,
      },
      billing: {
        name: {
          first: miniCart.buyer.firstName,
          last: miniCart.buyer.lastName,
        },
        address: {
          line1: miniCart.billingAddress.street,
          line2: miniCart.billingAddress.complement,
          city: miniCart.billingAddress.city,
          state: miniCart.billingAddress.state,
          zipcode: miniCart.billingAddress.postalCode,
          country: miniCart.billingAddress.country,
        },
        phone_number: miniCart.buyer.phone,
        email: miniCart.buyer.email,
      },
      items: affirmItems,
      metadata: {
        shipping_type: '',
        mode: 'modal',
        platform_type: 'VTEX',
        platform_version: version,
        platform_affirm: 'Affirm_2.0',
      },
      order_id: orderData.orderId,
      discounts: discountsObject,
      shipping_amount: Math.round(miniCart.shippingValue * 100),
      tax_amount: Math.round(miniCart.taxValue * 100),
      total: Math.round(orderData.value * 100),
    })
    vtex.checkout.MessageUtils.hidePaymentMessage()
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const self = this
    window.affirm.checkout.open({
      // eslint-disable-next-line prettier/prettier
      async onFail() {
        vtex.checkout.MessageUtils.showPaymentMessage()
        $(window).off('beforeunload')
        await self.respondTransaction(false)
      },
      // eslint-disable-next-line prettier/prettier
      async onSuccess(a: any) {
        vtex.checkout.MessageUtils.showPaymentMessage()
        orderUpdateMutation({
          variables: {
            url: orderData.inboundRequestsUrl
              .replace('https', 'http')
              .replace(':action', 'auth'),
            orderId: orderData.orderId,
            token: a.checkout_token,
            callbackUrl: orderData.callbackUrl,
            orderTotal: Math.round(orderData.value * 100),
          },
        })
          .then(response => {
            $(window).off('beforeunload')
            if (response.data?.orderUpdate) {
              self.respondTransaction(true)
            } else {
              self.respondTransaction(false)
            }
          })
          .catch(() => {
            $(window).trigger('transactionValidation.vtex', [false])
          })
      },
    })

    window.affirm.ui.error.on('close', async () => {
      vtex.checkout.MessageUtils.showPaymentMessage()
      $(window).off('beforeunload')
      await self.respondTransaction(false)
    })
  }

  public render() {
    const { scriptLoaded } = this.state
    const { publicKey } = JSON.parse(this.props.appPayload)

    return (
      scriptLoaded &&
      publicKey && (
        <Helmet>
          <script>
            {`
              _affirm_config = {
              public_api_key:  "${publicKey}"
              };
          `}
          </script>
        </Helmet>
      )
    )
  }
}

export default graphql(OrderUpdate, { name: 'orderUpdateMutation' })(
  withSettings(withOrderData(AffirmModal))
)

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { PureComponent } from 'react'
import { graphql } from 'react-apollo'

import OrderData from '../graphql/OrderData.graphql'

interface WithOrderDataProps {
  data?: any
  appPayload: string
}

export default function withOrderData(Component: any): any {
  class WithOrderData extends PureComponent<WithOrderDataProps> {
    public render() {
      const {
        data: { orderData },
        ...rest
      } = this.props
      if (!orderData) return null

      return <Component orderData={orderData} {...rest} />
    }
  }

  return graphql(OrderData, {
    options: (props: WithOrderDataProps) => ({
      variables: {
        qs: JSON.parse(props.appPayload).paymentIdentifier,
      },
      ssr: false,
    }),
  })(WithOrderData)
}

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { PureComponent } from 'react'
import { graphql } from 'react-apollo'

import Settings from '../graphql/Settings.graphql'

interface WithSettingsProps {
  data?: any
}

export default function withSettings(Component: any): any {
  class WithSettings extends PureComponent<WithSettingsProps> {
    public render() {
      const {
        data: { affirmSettings },
        ...rest
      } = this.props
      if (!affirmSettings) return null

      return <Component settings={affirmSettings} {...rest} />
    }
  }

  return graphql(Settings, { options: { ssr: false } })(WithSettings)
}

```


[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 affirm-payment/react/graphql/OrderData.graphql from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```graphql
query OrderData ($qs: String) {
  orderData(qs: $qs) @context(provider: "vtex.affirm-payment") {
    transactionId
    orderId
    miniCart {
      buyer {
        firstName
        lastName
        email
        phone
      }
      billingAddress {
        number
        street
        complement
        city
        state
        postalCode
        country
      }
      shippingAddress {
        number
        street
        complement
        city
        state
        postalCode
        country
      }
      items {
        id
        name
        price
        quantity
        discount
      }
      shippingValue
      taxValue
    }
    value
    inboundRequestsUrl
    callbackUrl
    returnUrl
  }
}

```


[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 affirm-payment/react/graphql/Settings.graphql from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```graphql
query Settings {
  affirmSettings {
    enableKatapult
    companyName
  }
}

```


[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 affirm-payment/react/graphql/OrderUpdate.graphql from the affirm-payment VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation OrderUpdate(
  $url: String
  $orderId: String
  $token: String
  $callbackUrl: String
  $orderTotal: Int
) {
  orderUpdate(
    inboundUrl: $url
    orderId: $orderId
    token: $token
    callbackUrl: $callbackUrl
    orderTotal: $orderTotal
  ) {
    status
  }
}

```


[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 admin-catalog-translations/messages/ja.json from the admin-catalog-translations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/catalog-translation.action-buttons.save": "保存",
  "admin/catalog-translation.action-buttons.cancel": "キャンセル",
  "admin/catalog-translation.action-buttons.edit": "編集",
  "admin/catalog-translation.entry-type.collection": "コレクション",
  "admin/catalog-translation.errors.not-found-header": "{entry} が見つかりません",
  "admin/catalog-translation.errors.not-found-message": "{entry} ID {entryId} が見つかりません",
  "admin/catalog-translation.errors.error-header": "{entry} 情報の取得中にエラーが発生",
  "admin/catalog-translation.errors.error-message": "検索した ${entry} 情報の取得中にエラーがありました。もう一度やり直してください",
  "admin/catalog-translation.navigation.label": "カタログの翻訳",
  "admin/catalog-translation.navigation.search.kws": "カタログ, 翻訳",
  "admin/catalog-translation.product.header": "製品の翻訳",
  "admin/catalog-translation.category.header": "カテゴリの翻訳",
  "admin/catalog-translation.brand.header": "ブランドの翻訳",
  "admin/catalog-translation.sku.header": "SKU の翻訳",
  "admin/catalog-translation.specifications.header": "仕様の翻訳",
  "admin/catalog-translation.collections.header": "コレクションの翻訳",
  "admin/catalog-translation.collections.search-label": "コレクション ID",
  "admin/catalog-translation.collections.block-header": "{selectedLocale} のコレクションの翻訳",
  "admin/catalog-translation.form-fields.name": "名前",
  "admin/catalog-translation.navigation.category": "カテゴリ",
  "admin/catalog-translation.navigation.product": "製品",
  "admin/catalog-translation.navigation.sku": "SKU",
  "admin/catalog-translation.navigation.brand": "ブランド",
  "admin/catalog-translation.navigation.specifications": "仕様",
  "admin/catalog-translation.navigation.collections": "コレクション",
  "admin/catalog-translation.export.modal.missing-category-id": "カテゴリ ID を選択してください",
  "admin/catalog-translation.export.modal.header": "{selectedLocale} の {entry} データをエクスポートする",
  "admin/catalog-translation.export.modal.header-product": "製品",
  "admin/catalog-translation.export.modal.header-sku": "SKU",
  "admin/catalog-translation.export.modal.export-tab": "エクスポート",
  "admin/catalog-translation.export.modal.cancelation": "キャンセル",
  "admin/catalog-translation.export.modal.confirmation-products": "製品をエクスポートする",
  "admin/catalog-translation.export.modal.confirmation-skus": "SKU をエクスポートする",
  "admin/catalog-translation.export.modal.search-header": "カテゴリを選択する",
  "admin/catalog-translation.export.modal.category-search-placeholder": "カテゴリー名または ID を入力する",
  "admin/catalog-translation.export.modal.error-exporting": "エクスポート中にエラーがありました。数分後にもう一度やり直してください。",
  "admin/catalog-translation.export.modal.see-files-tab": "ファイルを表示する",
  "admin/catalog-translation.export.modal.long-process.warning": "翻訳には時間がかかることがあります。このページを離れても、後から確認できます。",
  "admin/catalog-translation.export.modal.table-header.catId": "カテゴリ ID",
  "admin/catalog-translation.export.modal.table-header.locale": "ロケール",
  "admin/catalog-translation.export.modal.table-header.requested.by": "依頼者",
  "admin/catalog-translation.export.modal.table-header.requested.at": "依頼日時",
  "admin/catalog-translation.export.modal.table-header.download": "ダウンロード",
  "admin/catalog-translation.export.modal.download-list.error": "ファイルを作成中にエラーが発生しました",
  "admin/catalog-translation.export.modal.download-list.download-btn": "ダウンロード",
  "admin/catalog-translation.import.modal.cancelation": "キャンセル",
  "admin/catalog-translation.import.modal.confirmation": "翻訳を送信する",
  "admin/catalog-translation.import.modal.header.collections": "{selectedLocale} のコレクションの翻訳をインポートする",
  "admin/catalog-translation.import.modal.import-tab": "インポート",
  "admin/catalog-translation.import.modal.request-tab": "リクエスト",
  "admin/catalog-translation.import.modal.download-button": "xlsx モデルをダウンロードする",
  "admin/catalog-translation.import.modal.dropzone": "ここに XLSX をドロップするか、または ",
  "admin/catalog-translation.import.modal.dropzone-choose-file": "ファイルを選びます",
  "admin/catalog-translation.import.modal.total-entries": "エントリー合計",
  "admin/catalog-translation.import.modal.total-warnings": "警告",
  "admin/catalog-translation.import.modal.total-errors": "エラーです。エントリーは無視されます",
  "admin/catalog-translation.import.modal.error-uploading": "翻訳アップロード中のエラー",
  "admin/catalog-translation.import.modal.table-header.locale": "ロケール",
  "admin/catalog-translation.import.modal.table-header.translated-by": "翻訳者",
  "admin/catalog-translation.import.modal.table-header.created-at": "作成日時",
  "admin/catalog-translation.import.modal.table-header.progress": "進行状況",
  "admin/catalog-translation.import.modal.table-header.total-translated": "% 翻訳済み",
  "admin/catalog-translation.import.modal.status-list.error": "エラー",
  "admin/catalog-translation.import.warning-and-error": "/",
  "admin/catalog-translation.import.table-header.line": "ライン",
  "admin/catalog-translation.import.table-header.missing-fields": "不足しているフィールド",
  "admin/catalog-translation.export.modal.title-brand": "エクスポートするブランドデータ:",
  "admin/catalog-translation.export.modal.confirmation-brands": "ブランドをエクスポートする",
  "admin/catalog-translation.export.modal.export-active-brands": "アクティブなブランドのみをエクスポートする",
  "admin/catalog-translation.import.modal.entry-name-header": "{selectedLocale} の {entryName} の翻訳をインポートする",
  "admin/catalog-translation.export.modal.specification-header": "{selectedLocale} の仕様の翻訳をエクスポートする",
  "admin/catalog-translation.export.modal.download-button": "xlsx モデルをダウンロードする",
  "admin/catalog-translation.export.modal.dropzone": "ここに XLSX をドロップするか、または ",
  "admin/catalog-translation.export.modal.dropzone-choose-file": "ファイルを選びます",
  "admin/catalog-translation.export.modal.total-entries": "エントリー合計",
  "admin/catalog-translation.export.modal.total-warnings": "警告",
  "admin/catalog-translation.export.modal.total-errors": "エラーです。エントリーは無視されます",
  "admin/catalog-translation.export.modal.error-uploading": "翻訳アップロード中のエラー",
  "admin/catalog-translation.export.modal.confirmation": "翻訳をエクスポートする"
}

```


[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 admin-catalog-translations/messages/pt.json from the admin-catalog-translations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/catalog-translation.action-buttons.save": "Salvar",
  "admin/catalog-translation.action-buttons.cancel": "Cancelar",
  "admin/catalog-translation.action-buttons.edit": "Editar",
  "admin/catalog-translation.entry-type.collection": "Coleção",
  "admin/catalog-translation.errors.not-found-header": "{entry} não encontrada/o",
  "admin/catalog-translation.errors.not-found-message": "Informação de {entry} com id {entryId} não foi encontrada",
  "admin/catalog-translation.errors.error-header": "Erro ao buscar informação para {entry}",
  "admin/catalog-translation.errors.error-message": "Houve um erro ao buscar informação para a/o ${entry} que você procurou. Tente novamente mais tarde",
  "admin/catalog-translation.navigation.label": "Tradução Catálogos",
  "admin/catalog-translation.navigation.search.kws": "catalogos, traducao",
  "admin/catalog-translation.product.header": "Tradução de Produtos",
  "admin/catalog-translation.category.header": "Tradução de Categorias",
  "admin/catalog-translation.sku.header": "Tradução de SKU",
  "admin/catalog-translation.specifications.header": "Tradução de Especificaciones",
  "admin/catalog-translation.collections.header": "Tradução de Coleções",
  "admin/catalog-translation.collections.search-label": "ID da coleção",
  "admin/catalog-translation.collections.block-header": "Tradução da coleção para {selectedLocale}",
  "admin/catalog-translation.form-fields.name": "Nome",
  "admin/catalog-translation.brand.header": "Brand Translation",
  "admin/catalog-translation.navigation.category": "Categorias",
  "admin/catalog-translation.navigation.product": "Produtos",
  "admin/catalog-translation.navigation.sku": "SKU",
  "admin/catalog-translation.navigation.brand": "Marcas",
  "admin/catalog-translation.navigation.specifications": "Especificaciones",
  "admin/catalog-translation.navigation.collections": "Coleções",
  "admin/catalog-translation.export.modal.missing-category-id": "Por favor, selecione id da categoria",
  "admin/catalog-translation.export.modal.header": "Exportar dados de {entry} para {selectedLocale}",
  "admin/catalog-translation.export.modal.header-product": "produtos",
  "admin/catalog-translation.export.modal.header-sku": "SKUs",
  "admin/catalog-translation.export.modal.export-tab": "Exportar",
  "admin/catalog-translation.export.modal.cancelation": "Cancelar",
  "admin/catalog-translation.export.modal.confirmation-products": "Exportar Produtos",
  "admin/catalog-translation.export.modal.confirmation-skus": "Exportar SKUs",
  "admin/catalog-translation.export.modal.search-header": "Selecione uma categoria",
  "admin/catalog-translation.export.modal.category-search-placeholder": "Nome ou id da categoria",
  "admin/catalog-translation.export.modal.error-exporting": "Ocorreu um erro ao exportar. Tente novamente em alguns minutos.",
  "admin/catalog-translation.export.modal.see-files-tab": "Ver arquivos",
  "admin/catalog-translation.export.modal.long-process.warning": "O processo de tradução pode levar alguns minutos. Você pode deixar essa página e baixar o arquivo mais tarde.",
  "admin/catalog-translation.export.modal.table-header.catId": "Id Categoria",
  "admin/catalog-translation.export.modal.table-header.locale": "Locale",
  "admin/catalog-translation.export.modal.table-header.requested.by": "Solicitado por",
  "admin/catalog-translation.export.modal.table-header.requested.at": "Solicitado em",
  "admin/catalog-translation.export.modal.table-header.download": "Download",
  "admin/catalog-translation.export.modal.download-list.error": "Erro ao criar arquivo",
  "admin/catalog-translation.export.modal.download-list.download-btn": "Download",
  "admin/catalog-translation.import.modal.cancelation": "Cancelar",
  "admin/catalog-translation.import.modal.confirmation": "Enviar Traduções",
  "admin/catalog-translation.import.modal.header.collections": "Importar traduções de coleções para {selectedLocale}",
  "admin/catalog-translation.import.modal.import-tab": "Importar",
  "admin/catalog-translation.import.modal.request-tab": "Traduções",
  "admin/catalog-translation.import.modal.download-button": "Download xlsx modelo",
  "admin/catalog-translation.import.modal.dropzone": "Drop aqui seu XLSX ou ",
  "admin/catalog-translation.import.modal.dropzone-choose-file": "escolha um arquivo",
  "admin/catalog-translation.import.modal.total-entries": "registros",
  "admin/catalog-translation.import.modal.total-warnings": "alertas",
  "admin/catalog-translation.import.modal.total-errors": "erros. Os registros serão ignorados",
  "admin/catalog-translation.import.modal.error-uploading": "Erro ao fazer upload",
  "admin/catalog-translation.import.modal.table-header.locale": "Locale",
  "admin/catalog-translation.import.modal.table-header.translated-by": "Traduzido por",
  "admin/catalog-translation.import.modal.table-header.created-at": "Criado em",
  "admin/catalog-translation.import.modal.table-header.progress": "Progresso",
  "admin/catalog-translation.import.modal.table-header.total-translated": "% traduzido",
  "admin/catalog-translation.import.modal.status-list.error": "Erro",
  "admin/catalog-translation.import.warning-and-error": "de",
  "admin/catalog-translation.import.table-header.line": "Linha",
  "admin/catalog-translation.import.table-header.missing-fields": "Campos vazios",
  "admin/catalog-translation.export.modal.title-brand": "Exportar Dados da Marca para",
  "admin/catalog-translation.export.modal.confirmation-brands": "Exportação de Marcas",
  "admin/catalog-translation.export.modal.export-active-brands": "Exportar apenas Marcas Ativas",
  "admin/catalog-translation.import.modal.entry-name-header": "Importar Traduções de {entryName} para {selectedLocale}",
  "admin/catalog-translation.export.modal.specification-header": "Exportar traduções de especificações para {selectedLocale}",
  "admin/catalog-translation.export.modal.download-button": "Baixar modelo xlsx",
  "admin/catalog-translation.export.modal.dropzone": "Deixe aqui seu XLSX ou",
  "admin/catalog-translation.export.modal.dropzone-choose-file": "escolha um arquivo",
  "admin/catalog-translation.export.modal.total-entries": "entradas totais",
  "admin/catalog-translation.export.modal.total-warnings": "advertências",
  "admin/catalog-translation.export.modal.total-errors": "erros. As entradas serão ignoradas",
  "admin/catalog-translation.export.modal.error-uploading": "Erro ao enviar traduções",
  "admin/catalog-translation.export.modal.confirmation": "Traduções de exportação"
}

```


[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 admin-catalog-translations/messages/en.json from the admin-catalog-translations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/catalog-translation.action-buttons.save": "Save",
  "admin/catalog-translation.action-buttons.cancel": "Cancel",
  "admin/catalog-translation.action-buttons.edit": "Edit",
  "admin/catalog-translation.entry-type.collection": "Collection",
  "admin/catalog-translation.errors.not-found-header": "{entry} not found",
  "admin/catalog-translation.errors.not-found-message": "The {entry} ID {entryId} could not found",
  "admin/catalog-translation.errors.error-header": "Error getting {entry} information",
  "admin/catalog-translation.errors.error-message": "There was an error getting the ${entry} information you searched for. Please try again",
  "admin/catalog-translation.navigation.label": "Catalog Translation",
  "admin/catalog-translation.navigation.search.kws": "catalog, translation",
  "admin/catalog-translation.product.header": "Product Translation",
  "admin/catalog-translation.category.header": "Category Translation",
  "admin/catalog-translation.brand.header": "Brand Translation",
  "admin/catalog-translation.sku.header": "SKU Translation",
  "admin/catalog-translation.specifications.header": "Specifications Translation",
  "admin/catalog-translation.collections.header": "Collections Translation",
  "admin/catalog-translation.collections.search-label": "Collection ID",
  "admin/catalog-translation.collections.block-header": "Collection translation to {selectedLocale}",
  "admin/catalog-translation.form-fields.name": "Name",
  "admin/catalog-translation.navigation.category": "Category",
  "admin/catalog-translation.navigation.product": "Product",
  "admin/catalog-translation.navigation.sku": "SKU",
  "admin/catalog-translation.navigation.brand": "Brands",
  "admin/catalog-translation.navigation.specifications": "Specifications",
  "admin/catalog-translation.navigation.collections": "Collections",
  "admin/catalog-translation.export.modal.missing-category-id": "Please select a Category Id",
  "admin/catalog-translation.export.modal.header": "Export {entry} Data for {selectedLocale}",
  "admin/catalog-translation.export.modal.header-product": "product",
  "admin/catalog-translation.export.modal.header-sku": "SKU",
  "admin/catalog-translation.export.modal.export-tab": "Export",
  "admin/catalog-translation.export.modal.cancelation": "Cancel",
  "admin/catalog-translation.export.modal.confirmation-products": "Export Products",
  "admin/catalog-translation.export.modal.confirmation-skus": "Export SKUs",
  "admin/catalog-translation.export.modal.search-header": "Select a category",
  "admin/catalog-translation.export.modal.category-search-placeholder": "Enter category name or id",
  "admin/catalog-translation.export.modal.error-exporting": "There was an error exporting it. Please try again in a few minutes.",
  "admin/catalog-translation.export.modal.see-files-tab": "See files",
  "admin/catalog-translation.export.modal.long-process.warning": "The process to translate can take a while. You can leave the page and check it later.",
  "admin/catalog-translation.export.modal.table-header.catId": "Category Id",
  "admin/catalog-translation.export.modal.table-header.locale": "Locale",
  "admin/catalog-translation.export.modal.table-header.requested.by": "Requested by",
  "admin/catalog-translation.export.modal.table-header.requested.at": "Requested at",
  "admin/catalog-translation.export.modal.table-header.download": "Download",
  "admin/catalog-translation.export.modal.download-list.error": "Error creating file",
  "admin/catalog-translation.export.modal.download-list.download-btn": "Download",
  "admin/catalog-translation.import.modal.cancelation": "Cancel",
  "admin/catalog-translation.import.modal.confirmation": "Send Translations",
  "admin/catalog-translation.import.modal.header.collections": "Import Collection Translations for {selectedLocale}",
  "admin/catalog-translation.import.modal.import-tab": "Import",
  "admin/catalog-translation.import.modal.request-tab": "Requests",
  "admin/catalog-translation.import.modal.download-button": "Download xlsx model",
  "admin/catalog-translation.import.modal.dropzone": "Drop here your XLSX or ",
  "admin/catalog-translation.import.modal.dropzone-choose-file": "choose a file",
  "admin/catalog-translation.import.modal.total-entries": "total entries",
  "admin/catalog-translation.import.modal.total-warnings": "warnings",
  "admin/catalog-translation.import.modal.total-errors": "errors. The entries will be ignored",
  "admin/catalog-translation.import.modal.error-uploading": "Error uploading translations",
  "admin/catalog-translation.import.modal.table-header.locale": "Locale",
  "admin/catalog-translation.import.modal.table-header.translated-by": "Translated by",
  "admin/catalog-translation.import.modal.table-header.created-at": "Created at",
  "admin/catalog-translation.import.modal.table-header.progress": "Progress",
  "admin/catalog-translation.import.modal.table-header.total-translated": "% translated",
  "admin/catalog-translation.import.modal.status-list.error": "Error",
  "admin/catalog-translation.import.warning-and-error": "of",
  "admin/catalog-translation.import.table-header.line": "Line",
  "admin/catalog-translation.import.table-header.missing-fields": "Missing Fields",
  "admin/catalog-translation.export.modal.title-brand": "Export Brand Data for",
  "admin/catalog-translation.export.modal.confirmation-brands": "Export brands",
  "admin/catalog-translation.export.modal.export-active-brands": "Export only Active Brands",
  "admin/catalog-translation.import.modal.entry-name-header": "Import {entryName} Translations for {selectedLocale}",
  "admin/catalog-translation.export.modal.specification-header": "Export Specifications Translations for {selectedLocale}",
  "admin/catalog-translation.export.modal.download-button": "Download xlsx model",
  "admin/catalog-translation.export.modal.dropzone": "Drop here your XLSX or ",
  "admin/catalog-translation.export.modal.dropzone-choose-file": "choose a file",
  "admin/catalog-translation.export.modal.total-entries": "total entries",
  "admin/catalog-translation.export.modal.total-warnings": "warnings",
  "admin/catalog-translation.export.modal.total-errors": "errors. The entries will be ignored",
  "admin/catalog-translation.export.modal.error-uploading": "Error uploading translations",
  "admin/catalog-translation.export.modal.confirmation": "Export translations"
}

```


[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 admin-catalog-translations/messages/fr.json from the admin-catalog-translations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/catalog-translation.action-buttons.save": "Sauvegarder",
  "admin/catalog-translation.action-buttons.cancel": "Annuler",
  "admin/catalog-translation.action-buttons.edit": "Modifier",
  "admin/catalog-translation.entry-type.collection": "Collection",
  "admin/catalog-translation.errors.not-found-header": "{entry} introuvable",
  "admin/catalog-translation.errors.not-found-message": "L’ {entry} ID{entryId} est introuvable",
  "admin/catalog-translation.errors.error-header": "Erreur lors de l’obtention des informations de {entry}",
  "admin/catalog-translation.errors.error-message": "Une erreur s’est produite lors de l’obtention des informations de ${entry} que vous avez recherchées. Veuillez réessayer",
  "admin/catalog-translation.navigation.label": "Traduction du catalogue",
  "admin/catalog-translation.navigation.search.kws": "catalogue, traduction",
  "admin/catalog-translation.product.header": "Traduction du produit",
  "admin/catalog-translation.category.header": "Traduction de la catégorie",
  "admin/catalog-translation.brand.header": "Traduction de la marque",
  "admin/catalog-translation.sku.header": "Traductions du SKU",
  "admin/catalog-translation.specifications.header": "Traduction des spécifications",
  "admin/catalog-translation.collections.header": "Traduction des collections",
  "admin/catalog-translation.collections.search-label": "ID de la collection",
  "admin/catalog-translation.collections.block-header": "Traduction de la collection en {selectedLocale}",
  "admin/catalog-translation.form-fields.name": "Nom",
  "admin/catalog-translation.navigation.category": "Catégorie",
  "admin/catalog-translation.navigation.product": "Produit",
  "admin/catalog-translation.navigation.sku": "SKU",
  "admin/catalog-translation.navigation.brand": "Marques",
  "admin/catalog-translation.navigation.specifications": "Caractéristiques",
  "admin/catalog-translation.navigation.collections": "Collections",
  "admin/catalog-translation.export.modal.missing-category-id": "Veuillez sélectionner un ID de catégorie",
  "admin/catalog-translation.export.modal.header": "Exporter {entry} les données pour {selectedLocale}",
  "admin/catalog-translation.export.modal.header-product": "produit",
  "admin/catalog-translation.export.modal.header-sku": "SKU",
  "admin/catalog-translation.export.modal.export-tab": "Exporter",
  "admin/catalog-translation.export.modal.cancelation": "Annuler",
  "admin/catalog-translation.export.modal.confirmation-products": "Exporter les produits",
  "admin/catalog-translation.export.modal.confirmation-skus": "Exporter les SKU",
  "admin/catalog-translation.export.modal.search-header": "Sélectionner une catégorie",
  "admin/catalog-translation.export.modal.category-search-placeholder": "Entrez le nom ou L’ID de la catégorie",
  "admin/catalog-translation.export.modal.error-exporting": "Une erreur s’est produite lors de l’exportation. Veuillez réessayer dans quelques minutes.",
  "admin/catalog-translation.export.modal.see-files-tab": "Voir les fichiers",
  "admin/catalog-translation.export.modal.long-process.warning": "Le processus de traduction peut prendre un certain temps. Vous pouvez quitter la page et la vérifier plus tard.",
  "admin/catalog-translation.export.modal.table-header.catId": "ID de la catégorie",
  "admin/catalog-translation.export.modal.table-header.locale": "Locale",
  "admin/catalog-translation.export.modal.table-header.requested.by": "Demandé par",
  "admin/catalog-translation.export.modal.table-header.requested.at": "Demandé à",
  "admin/catalog-translation.export.modal.table-header.download": "Télécharger",
  "admin/catalog-translation.export.modal.download-list.error": "Erreur lors de la création du fichier",
  "admin/catalog-translation.export.modal.download-list.download-btn": "Télécharger",
  "admin/catalog-translation.import.modal.cancelation": "Abandonner",
  "admin/catalog-translation.import.modal.confirmation": "Envoyer des traductions",
  "admin/catalog-translation.import.modal.header.collections": "Importer les traductions de collections pour {selectedLocale}",
  "admin/catalog-translation.import.modal.import-tab": "Importer",
  "admin/catalog-translation.import.modal.request-tab": "Demandes",
  "admin/catalog-translation.import.modal.download-button": "Télécharger le modèle xlsx",
  "admin/catalog-translation.import.modal.dropzone": "Déposez ici votre XLSX ou ",
  "admin/catalog-translation.import.modal.dropzone-choose-file": "choisir un fichier",
  "admin/catalog-translation.import.modal.total-entries": "total des entrées",
  "admin/catalog-translation.import.modal.total-warnings": "avertissements",
  "admin/catalog-translation.import.modal.total-errors": "erreurs. Les entrées seront ignorées",
  "admin/catalog-translation.import.modal.error-uploading": "Erreur lors du chargement des traductions",
  "admin/catalog-translation.import.modal.table-header.locale": "Locale",
  "admin/catalog-translation.import.modal.table-header.translated-by": "Traduit par",
  "admin/catalog-translation.import.modal.table-header.created-at": "Créé le",
  "admin/catalog-translation.import.modal.table-header.progress": "Progrès",
  "admin/catalog-translation.import.modal.table-header.total-translated": "% traduit",
  "admin/catalog-translation.import.modal.status-list.error": "Erreur",
  "admin/catalog-translation.import.warning-and-error": "de",
  "admin/catalog-translation.import.table-header.line": "Ligne",
  "admin/catalog-translation.import.table-header.missing-fields": "Champs manquants",
  "admin/catalog-translation.export.modal.title-brand": "Exporter les données de la marque pour",
  "admin/catalog-translation.export.modal.confirmation-brands": "Exporter les marques",
  "admin/catalog-translation.export.modal.export-active-brands": "Exporter uniquement les marques actives",
  "admin/catalog-translation.import.modal.entry-name-header": "Importer les traductions de {entryName} pour {selectedLocale}",
  "admin/catalog-translation.export.modal.specification-header": "Traductions des spécifications d’exportation pour {selectedLocale}",
  "admin/catalog-translation.export.modal.download-button": "Télécharger le modèle xlsx",
  "admin/catalog-translation.export.modal.dropzone": "Déposez ici votre XLSX ou ",
  "admin/catalog-translation.export.modal.dropzone-choose-file": "choisir un fichier",
  "admin/catalog-translation.export.modal.total-entries": "total des entrées",
  "admin/catalog-translation.export.modal.total-warnings": "avertissements",
  "admin/catalog-translation.export.modal.total-errors": "erreurs. Les entrées seront ignorées",
  "admin/catalog-translation.export.modal.error-uploading": "Erreur lors du chargement des traductions",
  "admin/catalog-translation.export.modal.confirmation": "Exporter les traductions"
}

```


[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 admin-catalog-translations/messages/context.json from the admin-catalog-translations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/catalog-translation.action-buttons.save": "Save",
  "admin/catalog-translation.action-buttons.cancel": "Cancel",
  "admin/catalog-translation.action-buttons.edit": "Edit",
  "admin/catalog-translation.entry-type.collection": "Collection",
  "admin/catalog-translation.errors.not-found-header": "{entry} not found",
  "admin/catalog-translation.errors.not-found-message": "The {entry} ID {entryId} could not found",
  "admin/catalog-translation.errors.error-header": "Error getting {entry} information",
  "admin/catalog-translation.errors.error-message": "There was an error getting the ${entry} information you searched for. Please try again",
  "admin/catalog-translation.navigation.label": "Catalog Translation",
  "admin/catalog-translation.navigation.search.kws": "catalog, translation",
  "admin/catalog-translation.product.header": "Product Translation",
  "admin/catalog-translation.category.header": "Category Translation",
  "admin/catalog-translation.sku.header": "SKU Translation",
  "admin/catalog-translation.brand.header": "Brand Translation",
  "admin/catalog-translation.specifications.header": "Specifications Translation",
  "admin/catalog-translation.collections.header": "Collections Translation",
  "admin/catalog-translation.collections.search-label": "Collection ID",
  "admin/catalog-translation.collections.block-header": "Collection translation to {selectedLocale}",
  "admin/catalog-translation.form-fields.name": "Name",
  "admin/catalog-translation.navigation.category": "Categories",
  "admin/catalog-translation.navigation.product": "Products",
  "admin/catalog-translation.navigation.sku": "SKU",
  "admin/catalog-translation.navigation.brand": "Brands",
  "admin/catalog-translation.navigation.specifications": "Specifications",
  "admin/catalog-translation.navigation.collections": "Collections",
  "admin/catalog-translation.export.modal.missing-category-id": "Please select a Category Id",
  "admin/catalog-translation.export.modal.header": "Export {entry} Data for {selectedLocale}",
  "admin/catalog-translation.export.modal.header-product": "product",
  "admin/catalog-translation.export.modal.header-sku": "SKU",
  "admin/catalog-translation.export.modal.export-tab": "Export",
  "admin/catalog-translation.export.modal.cancelation": "Cancel",
  "admin/catalog-translation.export.modal.confirmation-products": "Export Products",
  "admin/catalog-translation.export.modal.confirmation-skus": "Export SKUs",
  "admin/catalog-translation.export.modal.search-header": "Select a category",
  "admin/catalog-translation.export.modal.category-search-placeholder": "Enter category name or id",
  "admin/catalog-translation.export.modal.error-exporting": "There was an error exporting it. Please try again in a few minutes.",
  "admin/catalog-translation.export.modal.see-files-tab": "See files",
  "admin/catalog-translation.export.modal.long-process.warning": "The process to translate can take a while. You can leave the page and check it later.",
  "admin/catalog-translation.export.modal.table-header.catId": "Category Id",
  "admin/catalog-translation.export.modal.table-header.locale": "Locale",
  "admin/catalog-translation.export.modal.table-header.requested.by": "Requested by",
  "admin/catalog-translation.export.modal.table-header.requested.at": "Requested at",
  "admin/catalog-translation.export.modal.table-header.download": "Download",
  "admin/catalog-translation.export.modal.download-list.error": "Error creating file",
  "admin/catalog-translation.export.modal.download-list.download-btn": "Download",
  "admin/catalog-translation.import.modal.cancelation": "Cancel",
  "admin/catalog-translation.import.modal.confirmation": "Send Translations",
  "admin/catalog-translation.import.modal.header.collections": "Import Collection Translations for {selectedLocale}",
  "admin/catalog-translation.import.modal.import-tab": "Import",
  "admin/catalog-translation.import.modal.request-tab": "Requests",
  "admin/catalog-translation.import.modal.download-button": "Download xlsx model",
  "admin/catalog-translation.import.modal.dropzone": "Drop here your XLSX or ",
  "admin/catalog-translation.import.modal.dropzone-choose-file": "choose a file",
  "admin/catalog-translation.import.modal.total-entries": "total entries",
  "admin/catalog-translation.import.modal.total-warnings": "warnings",
  "admin/catalog-translation.import.modal.total-errors": "errors. The entries will be ignored",
  "admin/catalog-translation.import.modal.error-uploading": "Error uploading translations",
  "admin/catalog-translation.import.modal.table-header.locale": "Locale",
  "admin/catalog-translation.import.modal.table-header.translated-by": "Translated by",
  "admin/catalog-translation.import.modal.table-header.created-at": "Created at",
  "admin/catalog-translation.import.modal.table-header.progress": "Progress",
  "admin/catalog-translation.import.modal.table-header.total-translated": "% translated",
  "admin/catalog-translation.import.modal.status-list.error": "Error",
  "admin/catalog-translation.import.warning-and-error": "of",
  "admin/catalog-translation.import.table-header.line": "Line",
  "admin/catalog-translation.import.table-header.missing-fields": "Missing Fields",
  "admin/catalog-translation.export.modal.title-brand": "Export Brand Data for",
  "admin/catalog-translation.export.modal.confirmation-brands": "Export Brands",
  "admin/catalog-translation.export.modal.export-active-brands": "Export only Active Brands",
  "admin/catalog-translation.import.modal.entry-name-header": "Import {entryName} Translations for {selectedLocale}",
  "admin/catalog-translation.export.modal.specification-header": "Export Specifications Translations for {selectedLocale}",
  "admin/catalog-translation.export.modal.download-button": "Download xlsx model",
  "admin/catalog-translation.export.modal.dropzone": "Drop here your XLSX or ",
  "admin/catalog-translation.export.modal.dropzone-choose-file": "choose a file",
  "admin/catalog-translation.export.modal.total-entries": "total entries",
  "admin/catalog-translation.export.modal.total-warnings": "warnings",
  "admin/catalog-translation.export.modal.total-errors": "errors. The entries will be ignored",
  "admin/catalog-translation.export.modal.error-uploading": "Error uploading translations",
  "admin/catalog-translation.export.modal.confirmation": "Export translations"
}

```