[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 external-promotion-provider-middleware/node/__tests__/unit/middlewares/getAppConfiguration.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { getAppConfiguration } from '../../../middlewares'

describe('getAppConfiguration', () => {
  const ctx = {
    body: '',
    clients: {
      apps: { getAppSettings: jest.fn() },
    },
    vtex: { logger: { error: jest.fn() }, settings: {} },
  } as any

  it('should insert the app settings into context', async () => {
    const spyGetAppSettings = jest.spyOn(ctx.clients.apps, 'getAppSettings')

    spyGetAppSettings.mockImplementation().mockResolvedValueOnce({
      externalEndpoint: 'http://localhost:3000/api',
    })
    const next = jest.fn()

    await getAppConfiguration(ctx, next)
    expect(spyGetAppSettings).toHaveBeenCalled()
    expect(ctx.vtex.settings.externalEndpoint).toEqual(
      'http://localhost:3000/api'
    )
  })
  it('should return error when there is no externalProvider set', async () => {
    ctx.vtex.settings.externalEndpoint = undefined
    const spyGetAppSettingsError = jest.spyOn(
      ctx.clients.apps,
      'getAppSettings'
    )

    spyGetAppSettingsError.mockImplementation().mockResolvedValueOnce({})

    const next = jest.fn()

    await getAppConfiguration(ctx, next)

    expect(ctx.body).toMatchObject({
      error: `No external endpoint was set. Go to https://${process.env.VTEX_WORKSPACE}--${process.env.VTEX_ACCOUNT}.myvtex.com/admin/apps/${process.env.VTEX_APP_ID}/setup/ and set your external endpoint`,
    })
  })
  it('should return error when getAppSettings is rejected', async () => {
    const spyGetAppSettingsError = jest.spyOn(
      ctx.clients.apps,
      'getAppSettings'
    )

    spyGetAppSettingsError
      .mockImplementation()
      .mockRejectedValueOnce(new Error('Failed to get app settings'))

    const next = jest.fn()

    await getAppConfiguration(ctx, next)

    expect(ctx.body).toMatchObject({
      error: 'Failed to get app settings',
    })
  })
})

```


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

[User] Show me the implementation of external-promotion-provider-middleware/node/__tests__/unit/middlewares/calculateExternalBenefits.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
import * as cobody from 'co-body'

import { calculateExternalBenefits } from '../../../middlewares'
import { parseOrderFormToProtocol } from '../../../utils'

jest.mock('co-body')
jest.mock('../../../utils')

describe('calculateExternalBenefits', () => {
  const mainCtx = {
    state: { orderForm: { items: [], paymentData: { payments: '' } } },
    req: {},
    clients: {
      externalProvider: {
        getBenefits: jest.fn().mockResolvedValue({ items: [] }),
      },
    },
    body: {},
    vtex: { logger: { error: jest.fn(), info: jest.fn() }, route: { id: '' } },
  } as any

  const next = jest.fn()

  jest.spyOn(cobody, 'json').mockImplementation().mockResolvedValue('')

  it('should be able to call parseOrderFormToProtocol function', async () => {
    await calculateExternalBenefits(mainCtx, next)

    expect(parseOrderFormToProtocol).toHaveBeenCalled()
  })

  it('should be able to call getBenefits function', async () => {
    await calculateExternalBenefits(mainCtx, next)

    expect(mainCtx.clients.externalProvider.getBenefits).toHaveBeenCalled()
  })

  it('should be able to set the response body when the route is /simulation', async () => {
    const ctx = {
      state: {
        orderForm: { items: [] },
      },
      req: {},
      clients: {
        externalProvider: {
          getBenefits: jest.fn().mockResolvedValueOnce({ items: [] }),
        },
      },
      vtex: {
        logger: { error: jest.fn(), info: jest.fn() },
        route: { id: 'simulation' },
      },
    } as any

    await calculateExternalBenefits(ctx, next)

    expect(ctx.body).toMatchObject({ items: [] })
  })

  it('should not call next function when the route is /simulation', async () => {
    const ctx = {
      state: {
        orderForm: { items: [{ id: 1 }] },
      },
      req: {},
      clients: {
        externalProvider: {
          getBenefits: jest.fn().mockResolvedValueOnce({ items: [] }),
        },
      },
      vtex: {
        logger: { error: jest.fn(), info: jest.fn() },
        route: { id: 'simulation' },
      },
    } as any

    const nextSpy = jest.fn()

    await calculateExternalBenefits(ctx, nextSpy)

    expect(nextSpy).not.toBeCalled()
  })

  it('should not call next function when the items is [] in externalProviderResponse', async () => {
    const ctx = {
      state: {
        orderForm: { items: [{ id: 1 }], paymentData: { payments: '' } },
      },
      req: {},
      clients: {
        externalProvider: {
          getBenefits: jest.fn().mockResolvedValueOnce({ items: [] }),
        },
      },
      vtex: {
        logger: { error: jest.fn(), info: jest.fn() },
        route: { id: '' },
      },
    } as any

    const nextSpy = jest.fn()

    await calculateExternalBenefits(ctx, nextSpy)

    expect(nextSpy).not.toBeCalled()
  })

  it('should not set the response body when the route does not match /simulation and when items array is not empty', async () => {
    const ctx = {
      state: {
        orderForm: { items: [], paymentData: { payments: '' } },
      },
      req: {},
      clients: {
        externalProvider: {
          getBenefits: jest
            .fn()
            .mockResolvedValueOnce({ items: [{ id: 1, variations: [] }] }),
        },
      },
      vtex: {
        logger: { error: jest.fn(), info: jest.fn() },
        route: { id: '' },
      },
    } as any

    await calculateExternalBenefits(ctx, next)

    expect(ctx.body).toBeUndefined()
  })

  it('should return 404 when getBenefits function fails', async () => {
    const ctx = {
      state: {
        orderForm: { items: [] },
      },
      req: {},
      clients: {
        externalProvider: {
          getBenefits: jest.fn().mockRejectedValueOnce(''),
        },
      },
      vtex: {
        logger: { error: jest.fn(), info: jest.fn() },
        route: { id: '' },
      },
    } as any

    await calculateExternalBenefits(ctx, next)

    expect(ctx.status).toBe(400)
  })
  it('should return 404 when parseOrderFormToProtocol function fails', async () => {
    const ctx = {
      state: {
        orderForm: undefined,
      },
      req: {},
      clients: {
        externalProvider: {
          getBenefits: jest.fn().mockRejectedValueOnce(''),
        },
      },
      vtex: {
        logger: { error: jest.fn(), info: jest.fn() },
        route: { id: '' },
      },
    } as any

    await calculateExternalBenefits(ctx, next)

    expect(ctx.status).toBe(400)
  })
})

```


[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 external-promotion-provider-middleware/node/__tests__/unit/middlewares/applyManualPrices.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { applyManualPrices } from '../../../middlewares'

jest.mock('../../../utils')
jest.mock('../../../services')

describe('applyManualPrices', () => {
  it('should be able to set status 204 and call next', async () => {
    const ctx = {
      status: '',
      state: {},
      clients: { checkout: { updateItems: jest.fn() } },
    }

    const next = jest.fn()

    await applyManualPrices(ctx as any, next)
    expect(next).toBeCalled()
    expect(ctx.status).toBe(204)
  })
  it('should be able to set status 400 when error is thrown', async () => {
    const ctx = {
      status: '',
      state: {},
      clients: {
        checkout: { updateItems: jest.fn().mockRejectedValueOnce('') },
      },
      vtex: { logger: { error: jest.fn() } },
    }

    const next = jest.fn()

    await applyManualPrices(ctx as any, next)
    expect(ctx.status).toBe(400)
  })
})

```


[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 external-promotion-provider-middleware/node/__tests__/unit/utils/parseOrderFormToProtocol.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable jest/no-mocks-import */
import { parseOrderFormToProtocol } from '../../../utils'
import { orderForm } from '../../../__mocks__/orderForm'
import { parsedProtocol } from '../../../__mocks__/parsedProtocol'

describe('parseOrderFormToProtocol', () => {
  it('should return the protocol parsed', async () => {
    expect(parseOrderFormToProtocol(orderForm as any)).toMatchObject(
      parsedProtocol
    )
  })
  it('should be able to throw error when payload has no items array', async () => {
    expect(() => {
      parseOrderFormToProtocol({
        customData: {},
        paymentData: { payment: '' },
      } as any)
    }).toThrowError('Property "items" is obligatory')
  })
  it('should be able to throw error when items array has no skuId', async () => {
    expect(() => {
      parseOrderFormToProtocol({
        items: [
          { id: 33, otherfield: '' },
          { id: 23, otherfield: '' },
          { otherfield: '' },
        ],
        customData: {},
      } as any)
    }).toThrowError(
      `Property "id" is missing in index 2 inside Items Array (this property is obligatory)`
    )
  })
})

```


[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 external-promotion-provider-middleware/node/__tests__/unit/utils/applyApportionment.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable jest/no-mocks-import */
import { applyApportionment } from '../../../utils'
import { parsedProtocol } from '../../../__mocks__/parsedProtocol'
import { externalProviderResponse } from '../../../__mocks__/externalProviderResponse'

describe('applyApportionment', () => {
  it('should be able to apply the apportionment properly', () => {
    const apportionedPayload = applyApportionment(
      parsedProtocol as any,
      externalProviderResponse
    )

    const expectedPayload = [
      {
        index: 0,
        price: 533,
      },
      {
        index: 3,
        price: 1850,
      },
    ]

    expect(apportionedPayload).toMatchObject(expectedPayload)
  })
  it('should be able to throw error when skuId has two instances at the items array', () => {
    const { items } = parsedProtocol

    items.push({
      id: '30',
      productId: '3',
      variations: [
        {
          assemblies: [],
          tax: 0,
          price: 135714,
          listPrice: 135714,
          manualPrice: null,
          sellingPrice: 135714,
          quantity: 1,
        },
      ],
    } as any)

    const newParsedProtocol = { ...parsedProtocol, items: [...items] }

    expect(() => {
      applyApportionment(newParsedProtocol as any, externalProviderResponse)
    }).toThrowError(`Multiple items with SKUID 30`)
  })
})

```


[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 external-promotion-provider-middleware/node/__tests__/unit/utils/getOrderFormId.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { getOrderFormId } from '../../../utils'

describe('getOrderFormId', () => {
  it('should be able to slice checkout.vtex.com cookie and store in orderFormId variable', async () => {
    const ctx = {
      state: { orderform: {}, orderFormId: {} },
      cookies: {
        get: jest
          .fn()
          .mockReturnValueOnce('__ofid=03db3a179c7d4a9085152068b555eee1'),
      },
      clients: { checkout: { orderForm: jest.fn().mockResolvedValueOnce('') } },
    } as any

    expect(getOrderFormId(ctx.cookies)).toBe('03db3a179c7d4a9085152068b555eee1')
  })
  it('should return error when "checkout.vtex.com" cookie is not in request', async () => {
    const ctx = {
      state: { orderform: {}, orderFormId: {} },
      cookies: {
        get: jest.fn().mockReturnValue(undefined),
      },
      clients: { checkout: { orderForm: jest.fn().mockResolvedValueOnce('') } },
    } as any

    expect(() => {
      getOrderFormId(ctx.cookies)
    }).toThrow(
      'No checkout.vtex.com cookie containing the orderformId was sent'
    )
  })
})

```


[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 external-promotion-provider-middleware/node/__tests__/unit/utils/validateProviderResponse.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable jest/no-mocks-import */
import { validateProviderResponse } from '../../../utils'
import { orderForm } from '../../../__mocks__/orderForm'
import { externalProviderResponse } from '../../../__mocks__/externalProviderResponse'

describe('validateProviderResponse', () => {
  describe('validateIndexConsistency method', () => {
    it('should be able to throw error when requestIndex does not match index in orderForm', () => {
      const mockedUncorrectProviderResponse = {
        items: [
          {
            id: 33,
            variations: [
              {
                requestIndex: 2,
                quantity: 1,
                externalPromotions: [
                  {
                    matchedParameters: {},
                    identifier: '3f0c2115-10a6-4fda-aec4-5950d8de9a6c',
                    isPercentual: true,
                    value: 0.1,
                  },
                ],
              },
            ],
          },
        ],
      }

      expect(() => {
        validateProviderResponse.indexConsistency(
          orderForm as any,
          mockedUncorrectProviderResponse
        )
      }).toThrowError(
        `RequestIndex from response does not match orderForm's original index for skuId ${mockedUncorrectProviderResponse.items[0].id}`
      )
    })
    it('should be able to throw error when requestIndex does not exist in original orderForm', () => {
      const mockedUncorrectProviderResponse = {
        items: [
          {
            id: 33,
            variations: [
              {
                requestIndex: 10,
                quantity: 1,
                externalPromotions: [
                  {
                    matchedParameters: {},
                    identifier: '3f0c2115-10a6-4fda-aec4-5950d8de9a6c',
                    isPercentual: true,
                    value: 0.1,
                  },
                ],
              },
            ],
          },
        ],
      }

      expect(() => {
        validateProviderResponse.indexConsistency(
          orderForm as any,
          mockedUncorrectProviderResponse
        )
      }).toThrowError(
        `RequestIndex from response does not match orderForm's original index for skuId ${mockedUncorrectProviderResponse.items[0].id}`
      )
    })
    it('should not throw error when requestIndex matches index in orderForm', () => {
      expect(
        validateProviderResponse.indexConsistency(
          orderForm as any,
          externalProviderResponse
        )
      ).toBeUndefined()
    })
  })
  describe('validateSchema method', () => {
    it('should be able to throw error when schema does not match', async () => {
      const mockedUncorrectProviderResponse = {
        items: [
          {
            id: '33',
            variations: [
              {
                requestIndex: '2',
                quantity: 1,
                externalPromotions: [
                  {
                    matchedParameters: {
                      requiresAuthenticationForPreAuthorizedPaymentOption:
                        'requiresAuthenticationForPreAuthorizedPaymentOption',
                    },
                    identifier: 123443,
                    isPercentual: 'true',
                    value: '0.1',
                  },
                ],
              },
            ],
          },
        ],
      }

      const expected =
        'items[0].id must be a `number` type, but the final value was: `"33"`.·items[0].variations[0].requestIndex must be a `number` type, but the final value was: `"2"`.·items[0].variations[0].externalPromotions[0].identifier must be a `string` type, but the final value was: `123443`.·items[0].variations[0].externalPromotions[0].isPercentual must be a `boolean` type, but the final value was: `"true"`.·items[0].variations[0].externalPromotions[0].value must be a `number` type, but the final value was: `"0.1"`.·Key requiresAuthenticationForPreAuthorizedPaymentOption inside matchedParameters must have less than (or equal) 50 characters.·Value requiresAuthenticationForPreAuthorizedPaymentOption in key requiresAuthenticationForPreAuthorizedPaymentOption (matchedParameters array) must have less than (or equal) 50 characters.'

      await expect(
        validateProviderResponse.schemaConsistency(
          mockedUncorrectProviderResponse as any
        )
      ).rejects.toThrowError(expected.split('·').join('\n\n'))
    })
    it('should not throw error when schema does matches', async () => {
      const mockedCorrectProviderResponse = {
        items: [
          {
            id: 33,
            variations: [
              {
                requestIndex: 1,
                quantity: 1,
                externalPromotions: [
                  {
                    matchedParameters: {
                      items: 'tech genérica',
                    },
                    identifier: '3f0c2115-10a6-4fda-aec4-5950d8de9a6c',
                    isPercentual: true,
                    value: 0.1,
                  },
                  {
                    matchedParameters: {
                      items: 'tech genérica',
                    },
                    identifier: '3f0c2115-10a6-4fda-aec4-5950d8de9a6c',
                    isPercentual: true,
                    value: 0.1,
                  },
                ],
              },
            ],
          },
          {
            id: 30,
            variations: [
              {
                requestIndex: 4,
                quantity: 1,
                externalPromotions: [
                  {
                    matchedParameters: {
                      paymentData: 'tech genérica',
                    },
                    identifier: '3f0c2115-10a6-4fda-aec4-5950d8de9a6c',
                    isPercentual: true,
                    value: 0.1,
                  },
                ],
              },
              {
                requestIndex: 4,
                quantity: 1,
                externalPromotions: [
                  {
                    matchedParameters: {
                      paymentData: 'tech genérica',
                    },
                    identifier: '3f0c2115-10a6-4fda-aec4-5950d8de9a6c',
                    isPercentual: true,
                    value: 0.1,
                  },
                ],
              },
            ],
          },
        ],
      }

      expect(
        await validateProviderResponse.schemaConsistency(
          mockedCorrectProviderResponse as any
        )
      ).toBeUndefined()
    })
  })
})

```


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

[User] Show me the implementation of external-promotion-provider-middleware/node/__tests__/unit/services/orderFormConfiguration.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { orderFormConfiguration } from '../../../services'

const configuration = {
  allowManualPrice: true,
  apps: [
    {
      fields: ['externalPromotions'],
      id: 'promotion-provider-middleware',
      major: 0,
    },
  ],
}

function orderformConfiguration(
  withExternalProvider: boolean,
  allowManualPrice = false
) {
  const apps = [
    {
      fields: ['marketplacePaymentMethod'],
      id: 'cn-magazineluiza-integration',
      major: 1,
    },
  ]

  const externalPromotions = {
    fields: ['externalPromotions'],
    id: 'promotion-provider-middleware',
    major: 1,
  }

  return {
    allowManualPrice,
    apps: [...apps, withExternalProvider && externalPromotions],
  }
}

describe('orderFormConfigurationService', () => {
  describe('getOrderFormConfiguration', () => {
    it('should be able to set isAppAlreadySet as true', async () => {
      const checkout = {
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(true)),
      }

      const {
        isAppAlreadySet,
      } = await orderFormConfiguration.getCurrentConfiguration(checkout as any)

      expect(isAppAlreadySet).toBe(true)
    })
    it('should be able to set isAppAlreadySet as false', async () => {
      const checkout = {
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(false)),
      }

      const {
        isAppAlreadySet,
      } = await orderFormConfiguration.getCurrentConfiguration(checkout as any)

      expect(isAppAlreadySet).toBe(false)
    })
  })

  describe('setOrderFormConfiguration', () => {
    it('should not call setOrderFormConfiguration when isAppAlreadySet and isManualPriceTrue are true', async () => {
      const checkout = {
        setOrderFormConfiguration: jest.fn(),
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(true, true)),
      }

      await orderFormConfiguration.setConfiguration({
        client: checkout as any,
        configuration: configuration as any,
      })

      expect(checkout.setOrderFormConfiguration).not.toHaveBeenCalled()
    })
    it('should call setOrderFormConfiguration when isManualPriceTrue is false', async () => {
      const checkout = {
        setOrderFormConfiguration: jest.fn(),
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(true)),
      }

      await orderFormConfiguration.setConfiguration({
        client: checkout as any,
        configuration: configuration as any,
      })

      expect(checkout.setOrderFormConfiguration).toHaveBeenCalled()
    })
    it('should call setOrderFormConfiguration when isAppAlreadySet is false', async () => {
      const checkout = {
        setOrderFormConfiguration: jest.fn(),
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(false, true)),
      }

      await orderFormConfiguration.setConfiguration({
        client: checkout as any,
        configuration: configuration as any,
      })

      expect(checkout.setOrderFormConfiguration).toHaveBeenCalled()
    })
    it('should call setOrderFormConfiguration when isAppAlreadySet and isManualPriceTrue are false', async () => {
      const checkout = {
        setOrderFormConfiguration: jest.fn(),
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(false, false)),
      }

      await orderFormConfiguration.setConfiguration({
        client: checkout as any,
        configuration: configuration as any,
      })

      expect(checkout.setOrderFormConfiguration).toHaveBeenCalled()
    })
    it('should throw error when setOrderFormConfiguration fails', async () => {
      const checkout = {
        setOrderFormConfiguration: jest.fn().mockRejectedValueOnce({}),
        getOrderFormConfiguration: jest
          .fn()
          .mockResolvedValueOnce(orderformConfiguration(true)),
      }

      const { setConfiguration } = orderFormConfiguration

      await expect(
        setConfiguration({
          client: checkout as any,
          configuration: configuration as any,
        })
      ).rejects.toThrow('Error while setting orderform configuration')
    })
  })
})

```


[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 external-promotion-provider-middleware/node/__tests__/unit/services/orderForm.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { orderform as orderformService } from '../../../services'

describe('orderform', () => {
  describe('getOrderFormById', () => {
    it('should be able to return the orderform', async () => {
      const ctx = {
        clients: {
          checkout: {
            orderForm: jest.fn().mockResolvedValueOnce({ items: [] }),
          },
        },
      }

      const orderformId = '1'
      const orderform = await orderformService.getOrderFormById(
        ctx.clients.checkout as any,
        orderformId
      )

      expect(orderform).toMatchObject({ items: [] })
    })
    it('should be able to throw error when orderform can not be fecthed', async () => {
      const ctx = {
        clients: {
          checkout: {
            orderForm: jest.fn().mockRejectedValueOnce(''),
          },
        },
      }

      const orderformId = '1'

      await expect(
        orderformService.getOrderFormById(
          ctx.clients.checkout as any,
          orderformId
        )
      ).rejects.toThrowError('Error when fetching orderform')
    })
  })
  describe('deleteAllManualPrices', () => {
    it('should be able to return the orderform without manual prices', async () => {
      const ctx = {
        clients: {
          checkout: {
            updateItems: jest.fn().mockResolvedValueOnce({ items: [] }),
          },
        },
        vtex: {
          logger: {
            error: (message) => console.error(message),
          },
        },
      }

      const currentOrderform = {
        items: [{ id: 1 }, { id: 2 }],
        orderFormId: '1',
      }

      const spyUpdateItems = jest.spyOn(ctx.clients.checkout, 'updateItems')

      const orderform = await orderformService.deleteAllManualPrices(
        ctx.clients.checkout as any,
        ctx.vtex.logger as any,
        currentOrderform as any
      )

      expect(spyUpdateItems).toHaveBeenCalledWith(
        currentOrderform.orderFormId,
        [
          {
            index: 0,
            price: null,
          },
          {
            index: 1,
            price: null,
          },
        ],
        'AUTH_TOKEN'
      )

      expect(orderform).toMatchObject({ items: [] })
    })
    it('should be able to throw error when updateItems fails', async () => {
      const ctx = {
        clients: {
          checkout: {
            updateItems: jest.fn().mockRejectedValueOnce(''),
          },
        },
        vtex: {
          logger: {
            error: (message) => console.error(message),
          },
        },
      }

      const currentOrderform = { items: [], orderformId: '1' }

      await expect(
        orderformService.deleteAllManualPrices(
          ctx.clients.checkout as any,
          ctx.vtex.logger as any,
          currentOrderform as any
        )
      ).rejects.toThrowError(
        'Error when removing all manual prices from orderform'
      )
    })
  })
})

```


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

[User] Show me the implementation of external-promotion-provider-middleware/node/__tests__/unit/services/customData.spec.ts from the external-promotion-provider-middleware VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* eslint-disable jest/no-mocks-import */
import { customData } from '../../../services'
import { orderForm } from '../../../__mocks__/orderForm'
import { externalProviderResponse } from '../../../__mocks__/externalProviderResponse'

describe('customData', () => {
  const ctx = {
    clients: {
      checkout: {
        setSingleCustomData: jest.fn().mockResolvedValueOnce({ items: [] }),
      },
    },
  }

  it('should to call function setSingleCustomData with its respective params', async () => {
    await customData.setCustomData({
      client: ctx.clients.checkout,
      externalProviderResponse,
      orderForm,
    } as any)

    const spyOnSetSingleCustomData = jest.spyOn(
      ctx.clients.checkout,
      'setSingleCustomData'
    )

    const value =
      '[{"id":33,"externalPromotions":[{"matchedParameters":{"slaIds":"transportadora genérica"},"identifier":"3f0c2115-10a6-4fda-aec4-5950d8de9a6c","isPercentual":false,"value":-700},{"matchedParameters":{"slaIds":"transportadora genérica"},"identifier":"3f0c2115-10a6-4fda-aec4-5950d8de9a6c","isPercentual":false,"value":-100},{"matchedParameters":{"slaIds":"transportadora genérica"},"identifier":"3f0c2115-10a6-4fda-aec4-5950d8de9a6c","isPercentual":true,"value":0.2}]},{"id":30,"externalPromotions":[{"matchedParameters":{"dockId":"2343b"},"identifier":"3f0c2115-10a6-4fda-aec4-5950d8de9a6c","isPercentual":false,"value":-100},{"matchedParameters":{"skuName":"SKU 23 - Celular"},"identifier":"3f0c2115-10a6-4fda-aec4-5950d8de9a6c","isPercentual":false,"value":-500}]}]'

    expect(spyOnSetSingleCustomData).toBeCalledWith(
      orderForm.orderFormId,
      {
        appId: 'promotion-provider-middleware',
        appFieldName: 'externalPromotions',
        value,
      },
      'AUTH_TOKEN'
    )
  })
  it('should be able to throw an error when setSingleCustomData fails', async () => {
    jest
      .spyOn(ctx.clients.checkout, 'setSingleCustomData')
      .mockImplementation()
      .mockRejectedValueOnce('')

    await expect(
      customData.setCustomData({
        client: ctx.clients.checkout,
        externalProviderResponse,
        orderForm,
      } as any)
    ).rejects.toThrowError('It was not possible to set customData.')
  })
})

```


[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 payment-connector-aws-cdk-template/test/vtex-connector.test.ts from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```typescript
// import * as cdk from 'aws-cdk-lib';
// import { Template } from 'aws-cdk-lib/assertions';
// import * as VtexConnector from '../lib/vtex-connector-stack';

// example test. To run these tests, uncomment this file along with the
// example resource in lib/vtex-connector-stack.ts
test('SQS Queue Created', () => {
//   const app = new cdk.App();
//     // WHEN
//   const stack = new VtexConnector.VtexConnectorStack(app, 'MyTestStack');
//     // THEN
//   const template = Template.fromStack(stack);

//   template.hasResourceProperties('AWS::SQS::Queue', {
//     VisibilityTimeout: 300
//   });
});

```


[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 payment-connector-aws-cdk-template/test/vtex-connector.test.js from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```javascript
"use strict";
// import * as cdk from 'aws-cdk-lib';
// import { Template } from 'aws-cdk-lib/assertions';
// import * as VtexConnector from '../lib/vtex-connector-stack';
// example test. To run these tests, uncomment this file along with the
// example resource in lib/vtex-connector-stack.ts
test('SQS Queue Created', () => {
    //   const app = new cdk.App();
    //     // WHEN
    //   const stack = new VtexConnector.VtexConnectorStack(app, 'MyTestStack');
    //     // THEN
    //   const template = Template.fromStack(stack);
    //   template.hasResourceProperties('AWS::SQS::Queue', {
    //     VisibilityTimeout: 300
    //   });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidnRleC1jb25uZWN0b3IudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInZ0ZXgtY29ubmVjdG9yLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHNDQUFzQztBQUN0QyxxREFBcUQ7QUFDckQsZ0VBQWdFO0FBRWhFLHVFQUF1RTtBQUN2RSxrREFBa0Q7QUFDbEQsSUFBSSxDQUFDLG1CQUFtQixFQUFFLEdBQUcsRUFBRTtJQUMvQiwrQkFBK0I7SUFDL0IsY0FBYztJQUNkLDRFQUE0RTtJQUM1RSxjQUFjO0lBQ2QsZ0RBQWdEO0lBRWhELHdEQUF3RDtJQUN4RCw2QkFBNkI7SUFDN0IsUUFBUTtBQUNSLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gaW1wb3J0ICogYXMgY2RrIGZyb20gJ2F3cy1jZGstbGliJztcbi8vIGltcG9ydCB7IFRlbXBsYXRlIH0gZnJvbSAnYXdzLWNkay1saWIvYXNzZXJ0aW9ucyc7XG4vLyBpbXBvcnQgKiBhcyBWdGV4Q29ubmVjdG9yIGZyb20gJy4uL2xpYi92dGV4LWNvbm5lY3Rvci1zdGFjayc7XG5cbi8vIGV4YW1wbGUgdGVzdC4gVG8gcnVuIHRoZXNlIHRlc3RzLCB1bmNvbW1lbnQgdGhpcyBmaWxlIGFsb25nIHdpdGggdGhlXG4vLyBleGFtcGxlIHJlc291cmNlIGluIGxpYi92dGV4LWNvbm5lY3Rvci1zdGFjay50c1xudGVzdCgnU1FTIFF1ZXVlIENyZWF0ZWQnLCAoKSA9PiB7XG4vLyAgIGNvbnN0IGFwcCA9IG5ldyBjZGsuQXBwKCk7XG4vLyAgICAgLy8gV0hFTlxuLy8gICBjb25zdCBzdGFjayA9IG5ldyBWdGV4Q29ubmVjdG9yLlZ0ZXhDb25uZWN0b3JTdGFjayhhcHAsICdNeVRlc3RTdGFjaycpO1xuLy8gICAgIC8vIFRIRU5cbi8vICAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4vLyAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpTUVM6OlF1ZXVlJywge1xuLy8gICAgIFZpc2liaWxpdHlUaW1lb3V0OiAzMDBcbi8vICAgfSk7XG59KTtcbiJdfQ==
```


[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 payment-connector-aws-cdk-template/bin/vtex-connector.ts from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```typescript
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { VtexConnectorStack } from '../lib/vtex-connector-stack';

const app = new cdk.App();
new VtexConnectorStack(app, 'VtexConnectorStack', {
  /* If you don't specify 'env', this stack will be environment-agnostic.
   * Account/Region-dependent features and context lookups will not work,
   * but a single synthesized template can be deployed anywhere. */

  /* Uncomment the next line to specialize this stack for the AWS Account
   * and Region that are implied by the current CLI configuration. */
  // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },

  /* Uncomment the next line if you know exactly what Account and Region you
   * want to deploy the stack to. */
  // env: { account: '123456789012', region: 'us-east-1' },

  /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
```


[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 payment-connector-aws-cdk-template/bin/vtex-connector.d.ts from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```typescript
#!/usr/bin/env node
import 'source-map-support/register';

```


[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 payment-connector-aws-cdk-template/bin/vtex-connector.js from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```javascript
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("source-map-support/register");
const cdk = require("aws-cdk-lib");
const vtex_connector_stack_1 = require("../lib/vtex-connector-stack");
const app = new cdk.App();
new vtex_connector_stack_1.VtexConnectorStack(app, 'VtexConnectorStack', {
/* If you don't specify 'env', this stack will be environment-agnostic.
 * Account/Region-dependent features and context lookups will not work,
 * but a single synthesized template can be deployed anywhere. */
/* Uncomment the next line to specialize this stack for the AWS Account
 * and Region that are implied by the current CLI configuration. */
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
/* Uncomment the next line if you know exactly what Account and Region you
 * want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidnRleC1jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ2dGV4LWNvbm5lY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx1Q0FBcUM7QUFDckMsbUNBQW1DO0FBQ25DLHNFQUFpRTtBQUVqRSxNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUMxQixJQUFJLHlDQUFrQixDQUFDLEdBQUcsRUFBRSxvQkFBb0IsRUFBRTtBQUNoRDs7aUVBRWlFO0FBRWpFO21FQUNtRTtBQUNuRSw2RkFBNkY7QUFFN0Y7a0NBQ2tDO0FBQ2xDLHlEQUF5RDtBQUV6RCw4RkFBOEY7Q0FDL0YsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuaW1wb3J0ICdzb3VyY2UtbWFwLXN1cHBvcnQvcmVnaXN0ZXInO1xuaW1wb3J0ICogYXMgY2RrIGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IFZ0ZXhDb25uZWN0b3JTdGFjayB9IGZyb20gJy4uL2xpYi92dGV4LWNvbm5lY3Rvci1zdGFjayc7XG5cbmNvbnN0IGFwcCA9IG5ldyBjZGsuQXBwKCk7XG5uZXcgVnRleENvbm5lY3RvclN0YWNrKGFwcCwgJ1Z0ZXhDb25uZWN0b3JTdGFjaycsIHtcbiAgLyogSWYgeW91IGRvbid0IHNwZWNpZnkgJ2VudicsIHRoaXMgc3RhY2sgd2lsbCBiZSBlbnZpcm9ubWVudC1hZ25vc3RpYy5cbiAgICogQWNjb3VudC9SZWdpb24tZGVwZW5kZW50IGZlYXR1cmVzIGFuZCBjb250ZXh0IGxvb2t1cHMgd2lsbCBub3Qgd29yayxcbiAgICogYnV0IGEgc2luZ2xlIHN5bnRoZXNpemVkIHRlbXBsYXRlIGNhbiBiZSBkZXBsb3llZCBhbnl3aGVyZS4gKi9cblxuICAvKiBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSB0byBzcGVjaWFsaXplIHRoaXMgc3RhY2sgZm9yIHRoZSBBV1MgQWNjb3VudFxuICAgKiBhbmQgUmVnaW9uIHRoYXQgYXJlIGltcGxpZWQgYnkgdGhlIGN1cnJlbnQgQ0xJIGNvbmZpZ3VyYXRpb24uICovXG4gIC8vIGVudjogeyBhY2NvdW50OiBwcm9jZXNzLmVudi5DREtfREVGQVVMVF9BQ0NPVU5ULCByZWdpb246IHByb2Nlc3MuZW52LkNES19ERUZBVUxUX1JFR0lPTiB9LFxuXG4gIC8qIFVuY29tbWVudCB0aGUgbmV4dCBsaW5lIGlmIHlvdSBrbm93IGV4YWN0bHkgd2hhdCBBY2NvdW50IGFuZCBSZWdpb24geW91XG4gICAqIHdhbnQgdG8gZGVwbG95IHRoZSBzdGFjayB0by4gKi9cbiAgLy8gZW52OiB7IGFjY291bnQ6ICcxMjM0NTY3ODkwMTInLCByZWdpb246ICd1cy1lYXN0LTEnIH0sXG5cbiAgLyogRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vY2RrL2xhdGVzdC9ndWlkZS9lbnZpcm9ubWVudHMuaHRtbCAqL1xufSk7Il19
```


[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 payment-connector-aws-cdk-template/lib/vtex-frontend-stack.ts from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```typescript
import * as cdk from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as s3deploy from "aws-cdk-lib/aws-s3-deployment";
import * as cloudFront from "aws-cdk-lib/aws-cloudfront";

export const configureFrontend = (scope: any) => {
  ///////////// FRONTEND
  // Add S3 Bucket
  const s3Site = new s3.Bucket(scope, `FrontEndHackathonVTEX`, {
    bucketName: `${scope.account}-vtexday-hackathon`,
    removalPolicy: cdk.RemovalPolicy.DESTROY,
    autoDeleteObjects: true,
    websiteIndexDocument: "index.html",
    websiteErrorDocument: "index.html",
  });

  // Create Origin Access Identity and have s3 grant read access
  const oai = new cloudFront.OriginAccessIdentity(
    scope,
    `frontend-hackathon-vtex-origin-access-id`,
    {}
  );
  s3Site.grantRead(oai);

  // Create a new CloudFront Distribution
  const distribution = new cloudFront.CloudFrontWebDistribution(
    scope,
    `myreactapp-cf-distribution`,
    {
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: s3Site,
            originAccessIdentity: oai,
          },
          behaviors: [
            {
              isDefaultBehavior: true,
              compress: true,
              allowedMethods: cloudFront.CloudFrontAllowedMethods.ALL,
              cachedMethods:
                cloudFront.CloudFrontAllowedCachedMethods.GET_HEAD_OPTIONS,
              forwardedValues: {
                queryString: true,
                cookies: {
                  forward: "none",
                },
                headers: [
                  "Access-Control-Request-Headers",
                  "Access-Control-Request-Method",
                  "Origin",
                ],
              },
            },
          ],
        },
      ],
      comment: `myreactapp - CloudFront Distribution`,
      viewerProtocolPolicy: cloudFront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
    }
  );

  // Setup Bucket Deployment to automatically deploy new assets and invalidate cache
  new s3deploy.BucketDeployment(
    scope,
    `frontend-hackathon-vtex-s3bucketdeployment`,
    {
      sources: [s3deploy.Source.asset("frontend/build")],
      destinationBucket: s3Site,
      distribution: distribution,
      distributionPaths: ["/*"],
    }
  );

  // Final CloudFront URL
  new cdk.CfnOutput(scope, "CloudFront URL", {
    value: distribution.distributionDomainName,
  });

  const enableCorsOnBucket = (bucket: s3.IBucket) => {
    const cfnBucket = bucket.node.findChild("Resource") as s3.CfnBucket;
    cfnBucket.addPropertyOverride("CorsConfiguration", {
      CorsRules: [
        {
          AllowedOrigins: ["*"],
          AllowedMethods: ["HEAD", "GET", "PUT", "POST", "DELETE"],
          ExposedHeaders: [
            "x-amz-server-side-encryption",
            "x-amz-request-id",
            "x-amz-id-2"
          ],
          AllowedHeaders: ["*"]
        }
      ]
    });
  };
  enableCorsOnBucket(s3Site);
};

```


[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 payment-connector-aws-cdk-template/lib/vtex-backend-stack.ts from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```typescript
import * as cdk from "aws-cdk-lib";
import * as sqs from "aws-cdk-lib/aws-sqs";
import * as DynamoDB from "aws-cdk-lib/aws-dynamodb";
import * as Lambda from "aws-cdk-lib/aws-lambda";
import * as APIGateway from "aws-cdk-lib/aws-apigateway";
import * as path from "path";
import { DynamoEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";

export const configureBackend = (scope: any) => {
  const AdquirencyAPI = "testing-12345/v2"

  /////// DynamoDB

  //Create a DynamoDB table called PaymentTrackTable
  const PaymentTrackTable = new DynamoDB.Table(scope, "PaymentTrackTable", {
    partitionKey: {
      name: "paymentId",
      type: DynamoDB.AttributeType.STRING,
    },
    tableName: "PaymentTrackTable",
    billingMode: DynamoDB.BillingMode.PAY_PER_REQUEST,
    stream: DynamoDB.StreamViewType.NEW_IMAGE,
    removalPolicy: cdk.RemovalPolicy.DESTROY,
  });

  /////// QUEUE

  //create an SQS queue called PendingPaymentQueue
  const PendingPaymentQueue = new sqs.Queue(scope, "PendingPaymentQueue", {
    queueName: "PendingPaymentQueue",
    visibilityTimeout: cdk.Duration.seconds(30),
    receiveMessageWaitTime: cdk.Duration.seconds(10),
    retentionPeriod: cdk.Duration.days(1),
    encryption: sqs.QueueEncryption.SQS_MANAGED,
  });

  ///////  API GATEWAY

  //Create an API Gateway using Lambda Proxy
  const PaymentApi = new APIGateway.RestApi(scope, "PaymentApi", {
    restApiName: "PaymentApi",
    description: "PaymentApi",
    deployOptions: {
      stageName: "Prod",
    },
    defaultCorsPreflightOptions: {
      allowOrigins: APIGateway.Cors.ALL_ORIGINS,
      allowMethods: APIGateway.Cors.ALL_METHODS
    }
  });

  //// LAMBDAS

  //Create Payment Lambda function
  const Payment = new Lambda.Function(scope, "Payment", {
    runtime: Lambda.Runtime.PYTHON_3_9,
    code: Lambda.Code.fromAsset(
      path.join(__dirname, "../backend-connector/Payment"),
      {
        bundling: {
          image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
          command: [
            "bash",
            "-c",
            "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
          ],
        },
      }
    ),
    memorySize: 128,
    handler: "app.lambda_handler",
    environment: {
      TABLE_NAME: PaymentTrackTable.tableName,
      API_URL: `https://${AdquirencyAPI}/payment`,
    },
  });

  //Create UserPost Lambda function
  const UserApi = new Lambda.Function(scope, "User", {
    runtime: Lambda.Runtime.PYTHON_3_9,
    code: Lambda.Code.fromAsset(
      path.join(__dirname, "../backend-front/User"),
      {
        bundling: {
          image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
          command: [
            "bash",
            "-c",
            "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
          ],
        },
      }
    ),
    memorySize: 128,
    handler: "app.lambda_handler",
    environment: {
      TABLE_NAME: PaymentTrackTable.tableName
    },
  });

  //Create Manifest Lambda function
  const Manifest = new Lambda.Function(scope, "Manifest", {
    runtime: Lambda.Runtime.PYTHON_3_9,
    code: Lambda.Code.fromAsset(
      path.join(__dirname, "../backend-connector/Manifest"),
      {
        bundling: {
          image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
          command: [
            "bash",
            "-c",
            "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
          ],
        },
      }
    ),
    memorySize: 128,
    handler: "app.lambda_handler"
  });

  //Create Settlement Lambda function
  const Settlement = new Lambda.Function(scope, "Settlement", {
    runtime: Lambda.Runtime.PYTHON_3_9,
    code: Lambda.Code.fromAsset(
      path.join(__dirname, "../backend-connector/Settlement"),
      {
        bundling: {
          image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
          command: [
            "bash",
            "-c",
            "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
          ],
        },
      }
    ),
    memorySize: 128,
    handler: "app.lambda_handler"
  });

  //Create Refund Lambda function
  const Refund = new Lambda.Function(scope, "Refund", {
    runtime: Lambda.Runtime.PYTHON_3_9,
    code: Lambda.Code.fromAsset(
      path.join(__dirname, "../backend-connector/Refund"),
      {
        bundling: {
          image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
          command: [
            "bash",
            "-c",
            "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
          ],
        },
      }
    ),
    memorySize: 128,
    handler: "app.lambda_handler"
  });

  //Create Cancellation Lambda function
  const Cancellation = new Lambda.Function(scope, "Cancellation", {
    runtime: Lambda.Runtime.PYTHON_3_9,
    code: Lambda.Code.fromAsset(
      path.join(__dirname, "../backend-connector/Cancellation"),
      {
        bundling: {
          image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
          command: [
            "bash",
            "-c",
            "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
          ],
        },
      }
    ),
    memorySize: 128,
    handler: "app.lambda_handler"
  });

  //create api resource for Lambda Proxy
  const PaymentResource = PaymentApi.root.addResource("payments");
  const UserApiResource = PaymentApi.root.addResource("user");
  const ManifestResource = PaymentApi.root.addResource("manifest");
  const SettlementResource = PaymentApi.root.addResource("settlements");
  const CancellationResource = PaymentApi.root.addResource("cancellations");
  const RefundResource = PaymentApi.root.addResource("refunds");

  //create Lambda Proxy Integration
  const PaymentLambdaIntegration = new APIGateway.LambdaIntegration(
    Payment,
    {
      proxy: true,
    }
  );
  const ManifestLambdaIntegration = new APIGateway.LambdaIntegration(
    Manifest,
    {
      proxy: true,
    }
  );
  const UserApiLambdaIntegration = new APIGateway.LambdaIntegration(
    UserApi,
    {
      proxy: true,
    }
  );
  const SettlementLambdaIntegration = new APIGateway.LambdaIntegration(
    Settlement,
    {
      proxy: true,
    }
  );
  const CancellationLambdaIntegration = new APIGateway.LambdaIntegration(
    Cancellation,
    {
      proxy: true,
    }
  );
  const RefundLambdaIntegration = new APIGateway.LambdaIntegration(
    Refund,
    {
      proxy: true,
    }
  );

  //add Lambda Proxy Integration to apiResource
  PaymentResource.addMethod("POST", PaymentLambdaIntegration);
  ManifestResource.addMethod("GET", ManifestLambdaIntegration);
  UserApiResource.addMethod("POST", UserApiLambdaIntegration);
  SettlementResource.addMethod("POST", SettlementLambdaIntegration);
  CancellationResource.addMethod("POST", CancellationLambdaIntegration);
  RefundResource.addMethod("POST", RefundLambdaIntegration);

  //Create PendingPaymentStream Lambda function
  const PendingPaymentStream = new Lambda.Function(
    scope,
    "PendingPaymentStream",
    {
      runtime: Lambda.Runtime.PYTHON_3_9,
      code: Lambda.Code.fromAsset(
        path.join(__dirname, "../backend-connector/PendingPaymentStream"),
        {
          bundling: {
            image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
            command: [
              "bash",
              "-c",
              "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
            ],
          },
        }
      ),
      memorySize: 128,
      handler: "app.lambda_handler",
      environment: {
        TABLE_NAME: PaymentTrackTable.tableName,
        PENDING_PAYMENT_QUEUE: PendingPaymentQueue.queueName,
      },
    }
  );

  //Add DynamoDB Event Source for Stream with filter
  PendingPaymentStream.addEventSource(
    new DynamoEventSource(PaymentTrackTable, {
      startingPosition: Lambda.StartingPosition.TRIM_HORIZON,
      batchSize: 1,
      // onFailure: new SqsDlq(deadLetterQueue),
      retryAttempts: 10,
      filters: [
        Lambda.FilterCriteria.filter({
          eventName: Lambda.FilterRule.isEqual("INSERT"),
          dynamodb: {
            NewImage: {
              status: { S: Lambda.FilterRule.isEqual("undefined") },
            },
          },
        }),
        Lambda.FilterCriteria.filter({
          eventName: Lambda.FilterRule.isEqual("MODIFY"),
          dynamodb: {
            NewImage: {
              status: { S: Lambda.FilterRule.isEqual("undefined") },
            },
          },
        }),
      ],
    })
  );

  //Create ProcessPendingPayment Lambda function
  const ProcessPendingPayment = new Lambda.Function(
    scope,
    "ProcessPendingPayment",
    {
      runtime: Lambda.Runtime.PYTHON_3_9,
      code: Lambda.Code.fromAsset(
        path.join(__dirname, "../backend-connector/ProcessPendingPayment"),
        {
          bundling: {
            image: Lambda.Runtime.PYTHON_3_9.bundlingImage,
            command: [
              "bash",
              "-c",
              "pip install -r requirements.txt -t /asset-output && cp -au . /asset-output",
            ],
          },
        }
      ),
      memorySize: 128,
      handler: "app.lambda_handler",
      environment: {
        PENDING_PAYMENT_QUEUE: PendingPaymentQueue.queueName,
        API_URL: `https://${AdquirencyAPI}`,
      },
    }
  );

  ProcessPendingPayment.addEventSource(
    new SqsEventSource(PendingPaymentQueue, {
      batchSize: 1,
      enabled: true,
      reportBatchItemFailures: true,
      // retryAttempts: 10,
      // maxConcurrency: 2,
    })
  );

  /////// PERMISSIONS

  //Provide access to Lambdas on PaymentTrackTable
  PaymentTrackTable.grantReadWriteData(Payment);
  PaymentTrackTable.grantReadWriteData(PendingPaymentStream);
  PaymentTrackTable.grantReadWriteData(ProcessPendingPayment);
  PaymentTrackTable.grantStreamRead(PendingPaymentStream);

  //Provide access to PendingPaymentStream on
  PendingPaymentQueue.grantSendMessages(PendingPaymentStream);
  PendingPaymentQueue.grantConsumeMessages(ProcessPendingPayment);
};

```


[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 payment-connector-aws-cdk-template/lib/vtex-connector-stack.ts from the payment-connector-aws-cdk-template VTEX app.

[Assistant]
Here's the implementation:

```typescript
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { configureBackend } from "./vtex-backend-stack";
import { configureFrontend } from "./vtex-frontend-stack";

export class VtexConnectorStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    configureFrontend(this);
    configureBackend(this);

  }
}

```


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

[User] Show me the implementation of checkout-fullstory/docs/README.md from the checkout-fullstory VTEX app.

[Assistant]
Here's the implementation:

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

# VTEX FULLSTORY IDENTIFICATION

⚠⚠ **This is an ongoing, unsupported, unfinished and undocumented project. We do not guarantee any results after installation, use it at your own risk.** ⚠⚠

This app injects the Fullstory script to the Checkout IO pages.

<!-- DOCS-IGNORE:start -->
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-0-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<!-- DOCS-IGNORE:end -->

## Configuration

Simply install this app in the workspace you're interested in collecting data from.

<!-- DOCS-IGNORE:start -->

## Contributors ✨

Thanks goes to these wonderful people:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!

<!-- DOCS-IGNORE:end -->

----

```


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

[User] Show me the implementation of product-gifts/messages/ja.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "ギフト画像",
  "admin/editor.gift-image.description": "製品のギフト画像",
  "admin/editor.gift-image.imageLabel.title": "画像ラベル",
  "admin/editor.gift-image.imageLabel.description": "表示する製品の画像を指定するラベルです。",
  "admin/editor.gift-name.title": "ギフト名",
  "admin/editor.gift-name.description": "ギフトの名前です。",
  "admin/editor.gift-name.linkToProduct.title": "製品ページへのリンク",
  "admin/editor.gift-name.linkToProduct.description": "ギフト名が製品ページにもリンクするかどうかを定めます。",
  "admin/editor.gift-name.nameType.title": "表示名タイプ",
  "admin/editor.gift-name.nameType.description": "ギフトの SKU 名または製品名を表示します。",
  "admin/editor.product-gifts.title": "製品ギフト",
  "admin/editor.product-gifts.description": "現在の製品に利用できるギフトを表示します。",
  "admin/editor.product-gifts.maxVisibleItems.title": "最大表示項目",
  "admin/editor.product-gifts.maxVisibleItems.description": "同時にレンダリングされるギフトの最大数です。 (「すべて表示」を使うと、利用できるギフトを常にすべて表示します)",
  "admin/editor.product-gift-text.title": "製品ギフトテキスト",
  "admin/editor.product-gift-text.description": "利用できるギフトに関連した追加情報",
  "admin/editor.product-gift-text.text.title": "テキスト",
  "admin/editor.product-gift-text.text.description": "ギフトに関連したテキストのレンダリングに使う変数のある、翻訳可能な文字列です。フォーマットは UCI ルールを使っており、利用できる変数は以下の通りです: totalGifts、exceedingItems、visibleItems。"
}
```


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

[User] Show me the implementation of product-gifts/messages/pt.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "Imagem do presente",
  "admin/editor.gift-image.description": "Imagem do presente para ser renderizada na lista de presentes.",
  "admin/editor.gift-image.imageLabel.title": "Label da imagem",
  "admin/editor.gift-image.imageLabel.description": "Label da imagem que deve ser renderizada para o presente.",
  "admin/editor.gift-name.title": "Nome do presente",
  "admin/editor.gift-name.description": "Nome do presente",
  "admin/editor.gift-name.linkToProduct.title": "Link para página de produto",
  "admin/editor.gift-name.linkToProduct.description": "Nome do presente é um link para sua página do produto.",
  "admin/editor.gift-name.nameType.title": "Tipo de nome de exibição",
  "admin/editor.gift-name.nameType.description": "Mostrar o skuName ou produtoNome do presente.",
  "admin/editor.product-gifts.title": "Presentes",
  "admin/editor.product-gifts.description": "Mostre os presentes associados com o produto.",
  "admin/editor.product-gifts.maxVisibleItems.title": "Máximo de itens visíveis",
  "admin/editor.product-gifts.maxVisibleItems.description": "Número máximo de presentes a serem mostrados na lista. Utilize o valor \"Show all\" para mostrar sempre todos.",
  "admin/editor.product-gift-text.title": "Texto auxiliar para presentes",
  "admin/editor.product-gift-text.description": "Texto auxiliar para presentes.",
  "admin/editor.product-gift-text.text.title": "Texto",
  "admin/editor.product-gift-text.text.description": "Texto que aceita variáveis e segue o padrão UCI para formatação. As variáveis disponíveis são: totalGifts, exceedingItems and visibleItems."
}
```


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

[User] Show me the implementation of product-gifts/messages/en.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "Gift Image",
  "admin/editor.gift-image.description": "Product's gift image",
  "admin/editor.gift-image.imageLabel.title": "Image label",
  "admin/editor.gift-image.imageLabel.description": "Label to specify which image from the product should be displayed.",
  "admin/editor.gift-name.title": "Gift Name",
  "admin/editor.gift-name.description": "Name of the gift.",
  "admin/editor.gift-name.linkToProduct.title": "Link to product page",
  "admin/editor.gift-name.linkToProduct.description": "Whether or not the gift-name should also be a link to the product page.",
  "admin/editor.gift-name.nameType.title": "Type of display name",
  "admin/editor.gift-name.nameType.description": "Show the gift's skuName or productName.",
  "admin/editor.product-gifts.title": "Product Gifts",
  "admin/editor.product-gifts.description": "Display available gifts for the current product.",
  "admin/editor.product-gifts.maxVisibleItems.title": "Maximum visible items",
  "admin/editor.product-gifts.maxVisibleItems.description": "Maximum number of gifts that should be rendered at once. (use \"showAll\" to always show all available gifts)",
  "admin/editor.product-gift-text.title": "Product Gifts Text",
  "admin/editor.product-gift-text.description": "Additional information regarding available gifts",
  "admin/editor.product-gift-text.text.title": "Text",
  "admin/editor.product-gift-text.text.description": "A translatable string that has variables that might be used to render any text regarding the gifts. Its format uses UCI rules and the available variables are: totalGifts, exceedingItems and visibleItems."
}
```


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

[User] Show me the implementation of product-gifts/messages/fr.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "Image du cadeau",
  "admin/editor.gift-image.description": "Image du cadeau du produit",
  "admin/editor.gift-image.imageLabel.title": "Étiquette de l’image",
  "admin/editor.gift-image.imageLabel.description": "Étiquette pour spécifier quelle image du produit doit être affichée.",
  "admin/editor.gift-name.title": "Nom du cadeau",
  "admin/editor.gift-name.description": "Nom du cadeau.",
  "admin/editor.gift-name.linkToProduct.title": "Lien vers la page produit",
  "admin/editor.gift-name.linkToProduct.description": "Si le nom du cadeau doit être un lien vers la page du produit.",
  "admin/editor.gift-name.nameType.title": "Type de nom d’affichage",
  "admin/editor.gift-name.nameType.description": "Afficher le NomDeSku du cadeau ou le NomDuProduit.",
  "admin/editor.product-gifts.title": "Cadeaux du produit",
  "admin/editor.product-gifts.description": "Afficher les cadeaux disponibles pour le produit actuel.",
  "admin/editor.product-gifts.maxVisibleItems.title": "Nombre maximum d’éléments visibles",
  "admin/editor.product-gifts.maxVisibleItems.description": "Nombre maximum de cadeaux qui doivent être rendus en même temps. (utilisez \"toutAfficher\" pour toujours afficher tous les cadeaux disponibles)",
  "admin/editor.product-gift-text.title": "Texte des cadeaux de produit",
  "admin/editor.product-gift-text.description": "Informations complémentaires sur les cadeaux disponibles",
  "admin/editor.product-gift-text.text.title": "Texte",
  "admin/editor.product-gift-text.text.description": "Une chaîne de caractères traduisible qui a des variables qui pouvant être utilisées pour rendre n’importe quel texte concernant les cadeaux. Son format utilise les règles UCI et les variables disponibles sont : TotalCadeaux, ArticlesEnSurplus et ArticlesVisibles."
}
```


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

[User] Show me the implementation of product-gifts/messages/ko.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "선물 이미지",
  "admin/editor.gift-image.description": "제품의 선물 이미지",
  "admin/editor.gift-image.imageLabel.title": "이미지 라벨",
  "admin/editor.gift-image.imageLabel.description": "표시할 제품의 이미지를 지정하는 라벨.",
  "admin/editor.gift-name.title": "선물 이름",
  "admin/editor.gift-name.description": "선물 이름.",
  "admin/editor.gift-name.linkToProduct.title": "제품 페이지 링크",
  "admin/editor.gift-name.linkToProduct.description": "선물 이름이 제품 페이지에 대한 링크여야 하는지.",
  "admin/editor.gift-name.nameType.title": "표시 이름 유형",
  "admin/editor.gift-name.nameType.description": "선물의 skuName 또는 productName을 표시합니다.",
  "admin/editor.product-gifts.title": "제품 선물",
  "admin/editor.product-gifts.description": "현재 제품에 사용할 수 있는 선물 표시.",
  "admin/editor.product-gifts.maxVisibleItems.title": "표시되는 최대 항목 수",
  "admin/editor.product-gifts.maxVisibleItems.description": "한 번에 제공해야 하는 최대 선물 수입니다.(사용 가능한 모든 선물을 항상 표시하려면 \"모두 표시\" 사용)",
  "admin/editor.product-gift-text.title": "제품 선물 텍스트",
  "admin/editor.product-gift-text.description": "사용 가능한 선물에 대한 추가 정보",
  "admin/editor.product-gift-text.text.title": "텍스트",
  "admin/editor.product-gift-text.text.description": "선물에 관한 텍스트를 렌더링하는 데 사용할 수있는 변수가 있는 번역 가능한 문자열입니다. 형식은 UCI 규칙을 사용하며 사용 가능한 변수는 totalGifts, exceedingItems 및 visibleItems입니다."
}
```


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

[User] Show me the implementation of product-gifts/messages/th.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "รูปของขวัญ",
  "admin/editor.gift-image.description": "รูปของขวัญผลิตภัณฑ์",
  "admin/editor.gift-image.imageLabel.title": "ป้ายกำกับรูป",
  "admin/editor.gift-image.imageLabel.description": "ป้ายกำกับที่ระบุว่าควรแสดงรูปใดจากผลิตภัณฑ์",
  "admin/editor.gift-name.title": "ชื่อของขวัญ",
  "admin/editor.gift-name.description": "ชื่อของของขวัญ",
  "admin/editor.gift-name.linkToProduct.title": "เชื่อมโยงไปหน้าผลิตภัณฑ์",
  "admin/editor.gift-name.linkToProduct.description": "ชื่อของขวัญควรเป็นลิงก์เชื่อมโยงไปหน้าผลิตภัณฑ์หรือไม่",
  "admin/editor.gift-name.nameType.title": "ประเภทชื่อการแสดง",
  "admin/editor.gift-name.nameType.description": "แสดงชื่อ skuName หรือ productName ของของขวัญ",
  "admin/editor.product-gifts.title": "ของขวัญผลิตภัณฑ์",
  "admin/editor.product-gifts.description": "แสดงของขวัญที่มีสำหรับผลิตภัณฑ์ปัจจุบัน",
  "admin/editor.product-gifts.maxVisibleItems.title": "จำนวนสูงสุดของรายการสินค้าที่มองเห็นได้",
  "admin/editor.product-gifts.maxVisibleItems.description": "จำนวนสูงสุดของของขวัญที่จะแสดงทันที (ใช้ \"showAll\" เสมอเพื่อแสดงของขวัญทั้งหมดที่มี)",
  "admin/editor.product-gift-text.title": "ข้อความของขวัญผลิตภัณฑ์",
  "admin/editor.product-gift-text.description": "ข้อมูลเพิ่มเติมเกี่ยวกับของขวัญที่มี",
  "admin/editor.product-gift-text.text.title": "ข้อความ",
  "admin/editor.product-gift-text.text.description": "ข้อความที่แปลได้ซึ่งมีตัวแปรที่อาจใช้แสดงข้อความใด ๆ ที่เกี่ยวกับของขวัญ รูปแบบที่ใช้เป็นกฎ UCI และตัวแปรที่มีคือ: totalGifts, exceedingItems และ visibleItems"
}
```


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

[User] Show me the implementation of product-gifts/messages/es.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/editor.gift-image.title": "Imagen del regalo",
  "admin/editor.gift-image.description": "Imagen de regalo del producto",
  "admin/editor.gift-image.imageLabel.title": "Etiqueta de imagen",
  "admin/editor.gift-image.imageLabel.description": "Etiqueta para especificar qué imagen del producto debe mostrarse.",
  "admin/editor.gift-name.title": "Nombre del regalo",
  "admin/editor.gift-name.description": "Nombre del regalo.",
  "admin/editor.gift-name.linkToProduct.title": "Link a la página de producto",
  "admin/editor.gift-name.linkToProduct.description": "Si el nombre del regalo también debe ser un link a la página de producto.",
  "admin/editor.gift-name.nameType.title": "Tipo de nombre mostrado",
  "admin/editor.gift-name.nameType.description": "Mostrar el skuName o productName del regalo.",
  "admin/editor.product-gifts.title": "Regalos de productos",
  "admin/editor.product-gifts.description": "Mostrar regalos disponibles para el producto actual.",
  "admin/editor.product-gifts.maxVisibleItems.title": "Máximo de ítems visibles",
  "admin/editor.product-gifts.maxVisibleItems.description": "Número máximo de regalos que se deben renderizar a la vez. (Utiliza \"showAll\" para mostrar siempre todos los regalos disponibles.)",
  "admin/editor.product-gift-text.title": "Texto de regalos del producto",
  "admin/editor.product-gift-text.description": "Información adicional sobre regalos disponibles.",
  "admin/editor.product-gift-text.text.title": "Texto",
  "admin/editor.product-gift-text.text.description": "Una cadena traducible que tiene variables que podrían usarse para renderizar cualquier texto relacionado con los regalos. Su formato utiliza reglas UCI y las variables disponibles son: totalGifts, exceedingItems y visibleItems."
}
```


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

[User] Show me the implementation of product-gifts/docs/README.md from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

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

# Product Gifts

The Product Gifts app provides blocks responsible for displaying, in the Product Description block, all gifts available for a given product.

:information_source: *A product's gift is configured in a [Buy&Win promotion](https://help.vtex.com/tutorial/buy-and-win--tutorials_322)*

![product-gift](https://user-images.githubusercontent.com/52087100/75782082-20a08380-5d3d-11ea-9ae1-60873e03f1ac.png)

## Configuration

1. Add the `product-gifts` app to your theme's dependencies in the `manifest.json`. For example:

```json
"dependencies": {
  "vtex.product-gifts": "0.x"
}
```

Now, you are able to use all blocks exported by the `product-gifts` app. Check out the full list below:

| Block name     | Description                                     |
| -------------- | ----------------------------------------------- |
| `product-gifts`| ![mandatory](https://img.shields.io/badge/-Mandatory-red) Renders a default Product Gifts block implementation. |
| `gift-text` | ![mandatory](https://img.shields.io/badge/-Mandatory-red) Reads Catalog data regarding the product's gifts and provides it to its children. |
| `product-gift-list` | Renders the available gifts in a list format. It also provides context for its 3 children listed below. |
| `gift-name` | Renders the product's gift name. |
| `gift-image` | Renders the product's gift image.|
| `gift-description` | Renders the gift's description provided by the `product-gift-list` block. |

2. Add the `product-gifts` block to your `store.product` template:

```jsonc
"store.product": {
  "children": [
    // (...)
    "product-gifts",
  ]
}
```

When added to the `store.product` template but not declared with any children or prop, the Product Gifts block is rendered even so.

For the rendering, it uses the following block implementation behind the scenes:

```json
{
  "product-gifts": {
    "props": {
      "maxVisibleItems": {
        "desktop": 2,
        "mobile": 1
      }
    },
    "children": ["flex-layout.row#product-gifts-text", "product-gift-list"]
  },

  "flex-layout.row#product-gifts-text": {
    "props": {
      "verticalAlign": "middle",
      "colSizing": "auto",
      "preserveLayoutOnMobile": true
    },
    "children": [
      "rich-text#product-gifts",
      "flex-layout.col#product-gifts-text"
    ]
  },
  "flex-layout.col#product-gifts-text": {
    "children": ["gift-text"],
    "props": {
      "verticalAlign": "middle"
    }
  },
  "rich-text#product-gifts": {
    "props": {
      "text": "**+ GIFT**"
    }
  },
  "gift-text": {
    "props": {
      "text": "{exceedingItems, plural, =0{ } one {+ # gift} other {+ # gifts}}"
    }
  },
  "product-gift-list": {
    "children": ["flex-layout.row#gift"]
  },
  "flex-layout.row#gift": {
    "props": {
      "fullWidth": true
    },
    "children": ["flex-layout.col#gift-name-description", "gift-image"]
  },
  "flex-layout.col#gift-name-description": {
    "props": {
      "verticalAlign": "middle",
      "rowGap": 3
    },
    "children": ["gift-name", "gift-description"]
  }
}
```

### Advanced configuration

If desired, you can change the Product Gifts default implementation by explicitly declaring the code showed above in your `store.product` template.

As a result, you will be able to configure the Product Gifts behavior by using all available props for each block:

- **`product-gifts`**

![product-gifts](https://user-images.githubusercontent.com/27777263/75771051-ee385b80-5d27-11ea-8600-5ea7f47ff64c.png)

| Prop name         | Type                        | Description                                            | Default value |
| ----------------- | --------------------------- | ------------------------------------------------------ | ------------- |
| `maxVisibleItems` | `number` | `"showAll"` | Maximum number of gifts that will be displayed at once | `"showAll"`   |

- **`gift-text`**

![gift-text](https://user-images.githubusercontent.com/27777263/75767717-01e0c380-5d22-11ea-8054-4440438a5441.png)

| Prop name | Type     | Description                                                                                | Default value                                                       |
| --------- | -------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `text`    | `String` | A translatable string (according to [ICU pattern](https://formatjs.io/guides/message-syntax/)) that has variables that might be used to render any desired text regarding the gifts. | `"{exceedingItems, plural, =0{ } one {+ # gift} other {+ # gifts}}"` |

You can configure the string received by the `text` prop using the following variables:

| Variable name    | Description                                                                                |
| ---------------- | ---------------------------------------------------------------------------------------------- |
| `exceedingItems` | Number of items that were not rendered because of the `maxVisibleItems` prop of `product-gifts`. |
| `totalGifts`     | Total number of gifts available.                                                               |
| `visibleItems`   | Number of items that are being rendered.                                                       |

-  **`gift-name`**

![gift-name](https://user-images.githubusercontent.com/27777263/75767722-03aa8700-5d22-11ea-8150-2cbe2a7bb37a.png)

| Prop name           | Type      | Description                                                               | Default value |
| ------------------- | --------- | ------------------------------------------------------------------------- | ------------- |
| `linkToProductPage` | `Boolean` | Whether or not the `gift-name` block should be a link to the gift's product page. | `false`       |
| `nameType` | `enum` | Name type to be displayed alongside the gift. Possible values are:  `productName` (displays the gift's product name) and `skuName` (displays the gift's SKU name). | `skuName` |

- **`gift-image`**

![gift-image](https://user-images.githubusercontent.com/27777263/75767721-02795a00-5d22-11ea-8f51-fe80664b7f68.png)

| Prop name    | Type                     | Description                                     | Default value |
| ------------ | ------------------------ | ----------------------------------------------- | ------------- |
| `maxWidth`   | `Number` | `String` | Gift image maximum width.                    | `125`         |
| `maxHeight`  | `Number` | `String` | Gift image maximum height.                   | `125`         |
| `minWidth`   | `Number` | `String` | Gift image minimum width.                    | `125`         |
| `minHeight`  | `Number` | `String` | Gift image minimum height.                   | `125`         |
| `imageLabel` | `String`                 | The label of the image that should be rendered. | `undefined`   |

:information_source: *If no image label is defined, the* `gift-image` *block will use the first available image from the product's SKU.*

## Customization

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

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

| CSS Handles              |
| ------------------------ |
| giftDescription          |
| giftListItem             |
| giftNameLink             |
| giftNameText             |
| productGiftListContainer |
| productGiftText          |
| productGiftsContainer    |

```


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

[User] Show me the implementation of product-gifts/react/ProductGiftDescription.tsx from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import { useCssHandles } from 'vtex.css-handles'

import { useGift } from './components/ProductGift'

const CSS_HANDLES = ['giftDescription'] as const

const ProductGiftDescription: FC = () => {
  const handles = useCssHandles(CSS_HANDLES)
  const gift = useGift()

  return (
    <span className={`${handles.giftDescription} t-small c-muted-1`}>
      {gift?.description}
    </span>
  )
}

export default ProductGiftDescription

```


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

[User] Show me the implementation of product-gifts/react/ProductGiftImage.tsx from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages } from 'react-intl'
import { Image } from 'vtex.store-image'

import { useGift } from './components/ProductGift'

interface Props {
  maxWidth?: string | number
  maxHeight?: string | number
  minWidth?: string | number
  minHeight?: string | number
  imageLabel?: string
}

const DEFAULT_IMAGE_DIMENSIONS = 125

const ProductGiftImage: StoreFunctionComponent<Props> = ({
  maxWidth = DEFAULT_IMAGE_DIMENSIONS,
  maxHeight = DEFAULT_IMAGE_DIMENSIONS,
  minWidth = DEFAULT_IMAGE_DIMENSIONS,
  minHeight = DEFAULT_IMAGE_DIMENSIONS,
  imageLabel,
}) => {
  const gift = useGift()
  const productImage =
    gift.images.find(image => image.imageLabel === imageLabel) ?? gift.images[0]

  return (
    <Image
      maxWidth={maxWidth}
      maxHeight={maxHeight}
      minWidth={minWidth}
      minHeight={minHeight}
      src={productImage.imageUrl}
      alt={gift.productName}
      title={gift.skuName}
    />
  )
}

const messages = defineMessages({
  title: {
    id: 'admin/editor.gift-image.title',
    defaultMessage: '',
  },
  description: {
    id: 'admin/editor.gift-image.description',
    defaultMessage: '',
  },
  imageLabel: {
    id: 'admin/editor.gift-image.imageLabel.title',
    defaultMessage: '',
  },
  imageLabelDescription: {
    id: 'admin/editor.gift-image.imageLabel.description',
    defaultMessage: '',
  },
})

ProductGiftImage.schema = {
  title: messages.title.id,
  description: messages.description.id,
  type: 'object',
  properties: {
    imageLabel: {
      default: '',
      title: messages.imageLabel.id,
      description: messages.imageLabelDescription.id,
      type: 'string',
    },
  },
}

export default ProductGiftImage

```


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

[User] Show me the implementation of product-gifts/react/ProductGiftList.tsx from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import { useCssHandles } from 'vtex.css-handles'

import { useProductGiftsState } from './ProductGifts'
import ProductGift from './components/ProductGift'

const CSS_HANDLES = ['productGiftListContainer'] as const

const ProductGiftList: FC = ({ children }) => {
  const { gifts, maxVisibleItems } = useProductGiftsState()
  const handles = useCssHandles(CSS_HANDLES)
  const itemsToShow =
    maxVisibleItems === 'showAll' ? gifts.length : maxVisibleItems

  return (
    <div className={handles.productGiftListContainer}>
      {gifts.slice(0, itemsToShow).map((gift, idx) => (
        <ProductGift key={gift.skuName} giftIndex={idx}>
          {children}
        </ProductGift>
      ))}
    </div>
  )
}

export default ProductGiftList

```


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

[User] Show me the implementation of product-gifts/react/GiftText.tsx from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo } from 'react'
import { defineMessages } from 'react-intl'
import { IOMessage } from 'vtex.native-types'
import { useCssHandles } from 'vtex.css-handles'

import { useProductGiftsState } from './ProductGifts'

interface Props {
  text?: string
}

const CSS_HANDLES = ['productGiftText'] as const

const GiftText: StoreFunctionComponent<Props> = ({ text }) => {
  const { gifts, maxVisibleItems } = useProductGiftsState()
  const handles = useCssHandles(CSS_HANDLES)
  const resolvedMaxVisibleItems =
    maxVisibleItems === 'showAll' ? gifts.length : maxVisibleItems

  const values = useMemo(
    () => ({
      totalGifts: gifts.length,
      exceedingItems:
        gifts.length - resolvedMaxVisibleItems > 0
          ? gifts.length - resolvedMaxVisibleItems
          : 0,
      visibleItems:
        resolvedMaxVisibleItems > gifts.length
          ? gifts.length
          : resolvedMaxVisibleItems,
    }),
    [gifts.length, resolvedMaxVisibleItems]
  )

  return (
    <span className={handles.productGiftText}>
      <IOMessage id={text} values={values} />
    </span>
  )
}

/**
 * These messages are used in contentSchema.json and need to be defined for the messages
 * builder to pick them up. If these are not here, CMS will render their IDs.
 */
const messages = defineMessages({
  title: {
    id: 'admin/editor.product-gift-text.title',
    defaultMessage: '',
  },
  description: {
    id: 'admin/editor.product-gift-text.description',
    defaultMessage: '',
  },
  text: {
    id: 'admin/editor.product-gift-text.text.title',
    defaultMessage: '',
  },
  textDescription: {
    id: 'admin/editor.product-gift-text.text.description',
    defaultMessage: '',
  },
})

GiftText.schema = {
  title: messages.title.id,
  description: messages.description.id,
}

export default GiftText

```


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

[User] Show me the implementation of product-gifts/react/package.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "lint": "tsc --noEmit && eslint --quiet --fix --ext ts,tsx .",
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "apollo-client": "^2.6.8",
    "react": "^16.8.6",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.8.6",
    "react-intl": "^3.11.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/jest": "^24.9.0",
    "@types/node": "^13.1.8",
    "@types/react": "^16.9.19",
    "@vtex/test-tools": "^3.0.1",
    "@vtex/tsconfig": "^0.2.0",
    "apollo-cache-inmemory": "^1.6.5",
    "graphql": "^14.5.8",
    "prettier": "^1.18.2",
    "typescript": "3.9.7",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.flex-layout": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.flex-layout@0.17.0/public/@types/vtex.flex-layout",
    "vtex.native-types": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.native-types@0.7.5/public/@types/vtex.native-types",
    "vtex.product-context": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-context@0.9.9/public/@types/vtex.product-context",
    "vtex.product-gifts": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.product-gifts@0.2.1/public/@types/vtex.product-gifts",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.128.4/public/@types/vtex.render-runtime",
    "vtex.responsive-values": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.responsive-values@0.4.2/public/@types/vtex.responsive-values",
    "vtex.rich-text": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.rich-text@0.14.0/public/@types/vtex.rich-text",
    "vtex.search-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.search-graphql@0.43.0/public/@types/vtex.search-graphql",
    "vtex.store-image": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-image@0.11.0/public/@types/vtex.store-image",
    "waait": "^1.0.5"
  },
  "version": "0.4.0"
}

```


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

[User] Show me the implementation of product-gifts/react/ProductGifts.tsx from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { createContext, useContext, useMemo } from 'react'
import { defineMessages } from 'react-intl'
import { useQuery } from 'react-apollo'
import {
  useResponsiveValue,
  MaybeResponsiveInput,
} from 'vtex.responsive-values'
import { useCssHandles } from 'vtex.css-handles'
import useProduct from 'vtex.product-context/useProduct'

import ProductGiftsQuery from './graphql/product.graphql'

interface Props {
  maxVisibleItems?: MaybeResponsiveInput<number | 'showAll'>
}

interface State {
  gifts: Gift[]
  maxVisibleItems: number | 'showAll'
}

const GiftsStateContext = createContext<State>({
  gifts: [],
  maxVisibleItems: 0,
})

const CSS_HANDLES = ['productGiftsContainer'] as const

const ProductGifts: StoreFunctionComponent<Props> = ({
  children,
  maxVisibleItems = 'showAll',
}) => {
  const productContext: Maybe<ProductContextState> = useProduct()
  const { data, loading, error } = useQuery<ProductGiftsQueryResponse>(
    ProductGiftsQuery,
    {
      variables: {
        identifier: { field: 'id', value: productContext?.product?.productId },
      },
      skip: productContext?.product?.productId == null,
    }
  )
  const selectedItemId = productContext?.selectedItem?.itemId
  const handles = useCssHandles(CSS_HANDLES)
  const staticMaxVisibleItems = useResponsiveValue<number | 'showAll'>(
    maxVisibleItems
  )

  const selectedItemFromProductQuery = data?.product.items.find(
    item => item.itemId === selectedItemId
  )
  const sellers = selectedItemFromProductQuery?.sellers ?? []

  const gifts = sellers.reduce(
    (acc: Gift[], curr) => acc.concat(curr.commertialOffer.gifts ?? []),
    []
  )

  const state = useMemo(
    () => ({ gifts, maxVisibleItems: staticMaxVisibleItems }),
    [gifts, staticMaxVisibleItems]
  )

  if (!productContext) {
    console.error(
      'Could not find a ProductContext value. Make sure this component is being used inside a ProductContextProvider.'
    )
  }

  if (error) {
    console.error(error)
  }

  if (loading || state.gifts.length === 0) {
    return null
  }

  return (
    <GiftsStateContext.Provider value={state}>
      <div className={handles.productGiftsContainer}>{children}</div>
    </GiftsStateContext.Provider>
  )
}

const messages = defineMessages({
  title: {
    id: 'admin/editor.product-gifts.title',
    defaultMessage: '',
  },
  description: {
    id: 'admin/editor.product-gifts.description',
    defaultMessage: '',
  },
  maxVisibleItems: {
    id: 'admin/editor.product-gifts.maxVisibleItems.title',
    defaultMessage: '',
  },
  maxVisibleItemsDescription: {
    id: 'admin/editor.product-gifts.maxVisibleItems.description',
    defaultMessage: '',
  },
})

ProductGifts.schema = {
  title: messages.title.id,
  description: messages.description.id,
  type: 'object',
  properties: {
    maxVisibleItems: {
      default: 'showAll',
      title: messages.maxVisibleItems.id,
      description: messages.maxVisibleItemsDescription.id,
      type: 'string',
    },
  },
}

export function useProductGiftsState() {
  const context = useContext(GiftsStateContext)
  if (context === undefined) {
    throw new Error(
      'useProductGiftsState must be used within a ProductGiftsContextProvider'
    )
  }
  return context
}

export default ProductGifts

```


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

[User] Show me the implementation of product-gifts/react/ProductGiftName.tsx from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages } from 'react-intl'
import { Link } from 'vtex.render-runtime'
import { useCssHandles } from 'vtex.css-handles'

import { useGift } from './components/ProductGift'

interface Props {
  linkToProductPage: boolean
  nameType: 'skuName' | 'productName'
}

const CSS_HANDLES = ['giftNameLink', 'giftNameText'] as const

const ProductGiftName: StoreFunctionComponent<Props> = ({
  linkToProductPage = false,
  nameType = 'skuName',
}) => {
  const handles = useCssHandles(CSS_HANDLES)
  const gift = useGift()

  return linkToProductPage ? (
    // No need for this rule since <Link> already creates an anchor
    // with href attribute.
    // eslint-disable-next-line jsx-a11y/anchor-is-valid
    <Link
      className={`${handles.giftNameLink} c-on-base link`}
      to={`/${gift.linkText}/p`}
    >
      <span className={`${handles.giftNameText}`}>
        {nameType === 'skuName' ? gift.skuName : gift.productName}
      </span>
    </Link>
  ) : (
    <span className={`${handles.giftNameText} c-on-base`}>
      {nameType === 'skuName' ? gift.skuName : gift.productName}
    </span>
  )
}

const messages = defineMessages({
  title: {
    id: 'admin/editor.gift-name.title',
    defaultMessage: '',
  },
  description: {
    id: 'admin/editor.gift-name.description',
    defaultMessage: '',
  },
  linkToProduct: {
    id: 'admin/editor.gift-name.linkToProduct.title',
    defaultMessage: '',
  },
  linkToProductDescription: {
    id: 'admin/editor.gift-name.linkToProduct.description',
    defaultMessage: '',
  },
  nameType: {
    id: 'admin/editor.gift-name.nameType.title',
    defaultMessage: '',
  },
  nameTypeDescription: {
    id: 'admin/editor.gift-name.nameType.description',
    defaultMessage: '',
  },
})

ProductGiftName.schema = {
  title: messages.title.id,
  description: messages.description.id,
  type: 'object',
  properties: {
    linkToProduct: {
      default: false,
      title: messages.linkToProduct.id,
      description: messages.linkToProductDescription.id,
      type: 'boolean',
    },
    nameType: {
      title: messages.nameType.id,
      description: messages.nameType.id,
      type: 'string',
      enum: [
        'skuName',
        'productName'
      ],
      enumNames: [
        'skuName',
        'productName'
      ],
      default: 'skuName'
    },
  },
}

export default ProductGiftName

```


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

[User] Show me the implementation of product-gifts/store/contentSchemas.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "definitions": {
    "GiftText": {
      "type": "object",
      "properties": {
        "text": {
          "$ref": "app:vtex.native-types#/definitions/text",
          "title": "admin/editor.product-gift-text.text.title",
          "description": "admin/editor.product-gift-text.text.description"
        }
      }
    }
  }
}

```


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

[User] Show me the implementation of product-gifts/store/blocks.jsonc from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "product-gifts": {
    "props": {
      "maxVisibleItems": {
        "desktop": 2,
        "mobile": 1
      }
    },
    "children": ["flex-layout.row#product-gifts-text", "product-gift-list"]
  },

  "flex-layout.row#product-gifts-text": {
    "props": {
      "verticalAlign": "middle",
      "colSizing": "auto",
      "preserveLayoutOnMobile": true
    },
    "children": [
      "rich-text#product-gifts",
      "flex-layout.col#product-gifts-text"
    ]
  },
  "flex-layout.col#product-gifts-text": {
    "children": ["gift-text"],
    "props": {
      "verticalAlign": "middle"
    }
  },
  "rich-text#product-gifts": {
    "props": {
      "text": "**+ GIFT**"
    }
  },
  "gift-text": {
    "props": {
      "text": "{exceedingItems, plural, =0{ } one {+ # gift} other {+ # gifts}}"
    }
  },
  "product-gift-list": {
    "children": ["flex-layout.row#gift"]
  },
  "flex-layout.row#gift": {
    "props": {
      "fullWidth": true
    },
    "children": ["flex-layout.col#gift-name-description", "gift-image"]
  },
  "flex-layout.col#gift-name-description": {
    "props": {
      "verticalAlign": "middle",
      "rowGap": 3
    },
    "children": ["gift-name", "gift-description"]
  }
}

```


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

[User] Show me the implementation of product-gifts/store/interfaces.json from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "product-gifts": {
    "component": "ProductGifts",
    "render": "client",
    "composition": "children"
  },
  "product-gift-list": {
    "component": "ProductGiftList",
    "composition": "children"
  },
  "gift-name": {
    "component": "ProductGiftName"
  },
  "gift-image": {
    "component": "ProductGiftImage"
  },
  "gift-text": {
    "component": "GiftText",
    "content": {
      "$ref": "#/definitions/GiftText"
    }
  },
  "gift-description": {
    "component": "ProductGiftDescription"
  }
}

```


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

[User] Show me the implementation of product-gifts/react/typings/vtex.responsive-values.d.ts from the product-gifts VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.responsive-values' {
  enum InputDevices {
    mobile = 'mobile',
    phone = 'phone',
    tablet = 'tablet',
    desktop = 'desktop',
  }

  enum OutputDevices {
    phone = 'phone',
    tablet = 'tablet',
    desktop = 'desktop',
  }

  type ResponsiveInput<T> = { [P in keyof typeof InputDevices]?: T }
  type MaybeResponsiveInput<T> = T | ResponsiveInput<T>

  type ResponsiveOutput<T> = { [P in keyof typeof OutputDevices]: T }

  export function useResponsiveValue<T>(args: MaybeResponsiveInput<T>): T
}

```