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

[User] Show me the implementation of admin-pages/react/components/DomainMessages/cultureMessages.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

const messages = defineMessages({
  aa: { defaultMessage: 'Afar', id: 'admin/pages.editor.locale.aa' },
  ab: { defaultMessage: 'Abkhazian', id: 'admin/pages.editor.locale.ab' },
  ae: { defaultMessage: 'Avestan', id: 'admin/pages.editor.locale.ae' },
  af: { defaultMessage: 'Afrikaans', id: 'admin/pages.editor.locale.af' },
  ak: { defaultMessage: 'Akan', id: 'admin/pages.editor.locale.ak' },
  am: { defaultMessage: 'Amharic', id: 'admin/pages.editor.locale.am' },
  an: { defaultMessage: 'Aragonese', id: 'admin/pages.editor.locale.an' },
  ar: { defaultMessage: 'Arabic', id: 'admin/pages.editor.locale.ar' },
  as: { defaultMessage: 'Assamese', id: 'admin/pages.editor.locale.as' },
  av: { defaultMessage: 'Avaric', id: 'admin/pages.editor.locale.av' },
  ay: { defaultMessage: 'Aymara', id: 'admin/pages.editor.locale.ay' },
  az: { defaultMessage: 'Azerbaijani', id: 'admin/pages.editor.locale.az' },
  ba: { defaultMessage: 'Bashkir', id: 'admin/pages.editor.locale.ba' },
  be: { defaultMessage: 'Belarusian', id: 'admin/pages.editor.locale.be' },
  bg: { defaultMessage: 'Bulgarian', id: 'admin/pages.editor.locale.bg' },
  bh: { defaultMessage: 'Bihari', id: 'admin/pages.editor.locale.bh' },
  bi: { defaultMessage: 'Bislama', id: 'admin/pages.editor.locale.bi' },
  bm: { defaultMessage: 'Bambara', id: 'admin/pages.editor.locale.bm' },
  bn: { defaultMessage: 'Bangla', id: 'admin/pages.editor.locale.bn' },
  bo: { defaultMessage: 'Tibetan', id: 'admin/pages.editor.locale.bo' },
  br: { defaultMessage: 'Breton', id: 'admin/pages.editor.locale.br' },
  bs: { defaultMessage: 'Bosnian', id: 'admin/pages.editor.locale.bs' },
  ca: { defaultMessage: 'Catalan', id: 'admin/pages.editor.locale.ca' },
  ce: { defaultMessage: 'Chechen', id: 'admin/pages.editor.locale.ce' },
  ch: { defaultMessage: 'Chamorro', id: 'admin/pages.editor.locale.ch' },
  co: { defaultMessage: 'Corsican', id: 'admin/pages.editor.locale.co' },
  cr: { defaultMessage: 'Cree', id: 'admin/pages.editor.locale.cr' },
  cs: { defaultMessage: 'Czech', id: 'admin/pages.editor.locale.cs' },
  cu: { defaultMessage: 'Church Slavic', id: 'admin/pages.editor.locale.cu' },
  cv: { defaultMessage: 'Chuvash', id: 'admin/pages.editor.locale.cv' },
  cy: { defaultMessage: 'Welsh', id: 'admin/pages.editor.locale.cy' },
  da: { defaultMessage: 'Danish', id: 'admin/pages.editor.locale.da' },
  de: { defaultMessage: 'German', id: 'admin/pages.editor.locale.de' },
  dv: { defaultMessage: 'Divehi', id: 'admin/pages.editor.locale.dv' },
  dz: { defaultMessage: 'Dzongkha', id: 'admin/pages.editor.locale.dz' },
  ee: { defaultMessage: 'Ewe', id: 'admin/pages.editor.locale.ee' },
  el: { defaultMessage: 'Greek', id: 'admin/pages.editor.locale.el' },
  en: { defaultMessage: 'English', id: 'admin/pages.editor.locale.en' },
  eo: { defaultMessage: 'Esperanto', id: 'admin/pages.editor.locale.eo' },
  es: { defaultMessage: 'Spanish', id: 'admin/pages.editor.locale.es' },
  et: { defaultMessage: 'Estonian', id: 'admin/pages.editor.locale.et' },
  eu: { defaultMessage: 'Basque', id: 'admin/pages.editor.locale.eu' },
  fa: { defaultMessage: 'Persian', id: 'admin/pages.editor.locale.fa' },
  ff: { defaultMessage: 'Fulah', id: 'admin/pages.editor.locale.ff' },
  fi: { defaultMessage: 'Finnish', id: 'admin/pages.editor.locale.fi' },
  fj: { defaultMessage: 'Fijian', id: 'admin/pages.editor.locale.fj' },
  fo: { defaultMessage: 'Faroese', id: 'admin/pages.editor.locale.fo' },
  fr: { defaultMessage: 'French', id: 'admin/pages.editor.locale.fr' },
  fy: { defaultMessage: 'Western Frisian', id: 'admin/pages.editor.locale.fy' },
  ga: { defaultMessage: 'Irish', id: 'admin/pages.editor.locale.ga' },
  gd: { defaultMessage: 'Scottish Gaelic', id: 'admin/pages.editor.locale.gd' },
  gl: { defaultMessage: 'Galician', id: 'admin/pages.editor.locale.gl' },
  gn: { defaultMessage: 'Guarani', id: 'admin/pages.editor.locale.gn' },
  gu: { defaultMessage: 'Gujarati', id: 'admin/pages.editor.locale.gu' },
  gv: { defaultMessage: 'Manx', id: 'admin/pages.editor.locale.gv' },
  ha: { defaultMessage: 'Hausa', id: 'admin/pages.editor.locale.ha' },
  he: { defaultMessage: 'Hebrew', id: 'admin/pages.editor.locale.he' },
  hi: { defaultMessage: 'Hindi', id: 'admin/pages.editor.locale.hi' },
  ho: { defaultMessage: 'Hiri Motu', id: 'admin/pages.editor.locale.ho' },
  hr: { defaultMessage: 'Croatian', id: 'admin/pages.editor.locale.hr' },
  ht: { defaultMessage: 'Haitian Creole', id: 'admin/pages.editor.locale.ht' },
  hu: { defaultMessage: 'Hungarian', id: 'admin/pages.editor.locale.hu' },
  hy: { defaultMessage: 'Armenian', id: 'admin/pages.editor.locale.hy' },
  hz: { defaultMessage: 'Herero', id: 'admin/pages.editor.locale.hz' },
  ia: { defaultMessage: 'Interlingua', id: 'admin/pages.editor.locale.ia' },
  id: { defaultMessage: 'Indonesian', id: 'admin/pages.editor.locale.id' },
  ie: { defaultMessage: 'Interlingue', id: 'admin/pages.editor.locale.ie' },
  ig: { defaultMessage: 'Igbo', id: 'admin/pages.editor.locale.ig' },
  ii: { defaultMessage: 'Sichuan Yi', id: 'admin/pages.editor.locale.ii' },
  ik: { defaultMessage: 'Inupiaq', id: 'admin/pages.editor.locale.ik' },
  io: { defaultMessage: 'Ido', id: 'admin/pages.editor.locale.io' },
  is: { defaultMessage: 'Icelandic', id: 'admin/pages.editor.locale.is' },
  it: { defaultMessage: 'Italian', id: 'admin/pages.editor.locale.it' },
  iu: { defaultMessage: 'Inuktitut', id: 'admin/pages.editor.locale.iu' },
  ja: { defaultMessage: 'Japanese', id: 'admin/pages.editor.locale.ja' },
  jv: { defaultMessage: 'Javanese', id: 'admin/pages.editor.locale.jv' },
  ka: { defaultMessage: 'Georgian', id: 'admin/pages.editor.locale.ka' },
  kg: { defaultMessage: 'Kongo', id: 'admin/pages.editor.locale.kg' },
  ki: { defaultMessage: 'Kikuyu', id: 'admin/pages.editor.locale.ki' },
  kj: { defaultMessage: 'Kuanyama', id: 'admin/pages.editor.locale.kj' },
  kk: { defaultMessage: 'Kazakh', id: 'admin/pages.editor.locale.kk' },
  kl: { defaultMessage: 'Kalaallisut', id: 'admin/pages.editor.locale.kl' },
  km: { defaultMessage: 'Khmer', id: 'admin/pages.editor.locale.km' },
  kn: { defaultMessage: 'Kannada', id: 'admin/pages.editor.locale.kn' },
  ko: { defaultMessage: 'Korean', id: 'admin/pages.editor.locale.ko' },
  kr: { defaultMessage: 'Kanuri', id: 'admin/pages.editor.locale.kr' },
  ks: { defaultMessage: 'Kashmiri', id: 'admin/pages.editor.locale.ks' },
  ku: { defaultMessage: 'Kurdish', id: 'admin/pages.editor.locale.ku' },
  kv: { defaultMessage: 'Komi', id: 'admin/pages.editor.locale.kv' },
  kw: { defaultMessage: 'Cornish', id: 'admin/pages.editor.locale.kw' },
  ky: { defaultMessage: 'Kyrgyz', id: 'admin/pages.editor.locale.ky' },
  la: { defaultMessage: 'Latin', id: 'admin/pages.editor.locale.la' },
  lb: { defaultMessage: 'Luxembourgish', id: 'admin/pages.editor.locale.lb' },
  lg: { defaultMessage: 'Ganda', id: 'admin/pages.editor.locale.lg' },
  li: { defaultMessage: 'Limburgish', id: 'admin/pages.editor.locale.li' },
  ln: { defaultMessage: 'Lingala', id: 'admin/pages.editor.locale.ln' },
  lo: { defaultMessage: 'Lao', id: 'admin/pages.editor.locale.lo' },
  lt: { defaultMessage: 'Lithuanian', id: 'admin/pages.editor.locale.lt' },
  lu: { defaultMessage: 'Luba-Katanga', id: 'admin/pages.editor.locale.lu' },
  lv: { defaultMessage: 'Latvian', id: 'admin/pages.editor.locale.lv' },
  mg: { defaultMessage: 'Malagasy', id: 'admin/pages.editor.locale.mg' },
  mh: { defaultMessage: 'Marshallese', id: 'admin/pages.editor.locale.mh' },
  mi: { defaultMessage: 'Maori', id: 'admin/pages.editor.locale.mi' },
  mk: { defaultMessage: 'Macedonian', id: 'admin/pages.editor.locale.mk' },
  ml: { defaultMessage: 'Malayalam', id: 'admin/pages.editor.locale.ml' },
  mn: { defaultMessage: 'Mongolian', id: 'admin/pages.editor.locale.mn' },
  mr: { defaultMessage: 'Marathi', id: 'admin/pages.editor.locale.mr' },
  ms: { defaultMessage: 'Malay', id: 'admin/pages.editor.locale.ms' },
  mt: { defaultMessage: 'Maltese', id: 'admin/pages.editor.locale.mt' },
  my: { defaultMessage: 'Burmese', id: 'admin/pages.editor.locale.my' },
  na: { defaultMessage: 'Nauru', id: 'admin/pages.editor.locale.na' },
  nb: {
    defaultMessage: 'Norwegian Bokmål',
    id: 'admin/pages.editor.locale.nb',
  },
  nd: { defaultMessage: 'North Ndebele', id: 'admin/pages.editor.locale.nd' },
  ne: { defaultMessage: 'Nepali', id: 'admin/pages.editor.locale.ne' },
  ng: { defaultMessage: 'Ndonga', id: 'admin/pages.editor.locale.ng' },
  nl: { defaultMessage: 'Dutch', id: 'admin/pages.editor.locale.nl' },
  nn: {
    defaultMessage: 'Norwegian Nynorsk',
    id: 'admin/pages.editor.locale.nn',
  },
  no: { defaultMessage: 'Norwegian', id: 'admin/pages.editor.locale.no' },
  nr: { defaultMessage: 'South Ndebele', id: 'admin/pages.editor.locale.nr' },
  nv: { defaultMessage: 'Navajo', id: 'admin/pages.editor.locale.nv' },
  ny: { defaultMessage: 'Nyanja', id: 'admin/pages.editor.locale.ny' },
  oc: { defaultMessage: 'Occitan', id: 'admin/pages.editor.locale.oc' },
  oj: { defaultMessage: 'Ojibwa', id: 'admin/pages.editor.locale.oj' },
  om: { defaultMessage: 'Oromo', id: 'admin/pages.editor.locale.om' },
  or: { defaultMessage: 'Odia', id: 'admin/pages.editor.locale.or' },
  os: { defaultMessage: 'Ossetic', id: 'admin/pages.editor.locale.os' },
  pa: { defaultMessage: 'Punjabi', id: 'admin/pages.editor.locale.pa' },
  pi: { defaultMessage: 'Pali', id: 'admin/pages.editor.locale.pi' },
  pl: { defaultMessage: 'Polish', id: 'admin/pages.editor.locale.pl' },
  ps: { defaultMessage: 'Pashto', id: 'admin/pages.editor.locale.ps' },
  pt: { defaultMessage: 'Portuguese', id: 'admin/pages.editor.locale.pt' },
  qu: { defaultMessage: 'Quechua', id: 'admin/pages.editor.locale.qu' },
  rm: { defaultMessage: 'Romansh', id: 'admin/pages.editor.locale.rm' },
  rn: { defaultMessage: 'Rundi', id: 'admin/pages.editor.locale.rn' },
  ro: { defaultMessage: 'Romanian', id: 'admin/pages.editor.locale.ro' },
  ru: { defaultMessage: 'Russian', id: 'admin/pages.editor.locale.ru' },
  rw: { defaultMessage: 'Kinyarwanda', id: 'admin/pages.editor.locale.rw' },
  sa: { defaultMessage: 'Sanskrit', id: 'admin/pages.editor.locale.sa' },
  sc: { defaultMessage: 'Sardinian', id: 'admin/pages.editor.locale.sc' },
  sd: { defaultMessage: 'Sindhi', id: 'admin/pages.editor.locale.sd' },
  se: { defaultMessage: 'Northern Sami', id: 'admin/pages.editor.locale.se' },
  sg: { defaultMessage: 'Sango', id: 'admin/pages.editor.locale.sg' },
  si: { defaultMessage: 'Sinhala', id: 'admin/pages.editor.locale.si' },
  sk: { defaultMessage: 'Slovak', id: 'admin/pages.editor.locale.sk' },
  sl: { defaultMessage: 'Slovenian', id: 'admin/pages.editor.locale.sl' },
  sm: { defaultMessage: 'Samoan', id: 'admin/pages.editor.locale.sm' },
  sn: { defaultMessage: 'Shona', id: 'admin/pages.editor.locale.sn' },
  so: { defaultMessage: 'Somali', id: 'admin/pages.editor.locale.so' },
  sq: { defaultMessage: 'Albanian', id: 'admin/pages.editor.locale.sq' },
  sr: { defaultMessage: 'Serbian', id: 'admin/pages.editor.locale.sr' },
  ss: { defaultMessage: 'Swati', id: 'admin/pages.editor.locale.ss' },
  st: { defaultMessage: 'Southern Sotho', id: 'admin/pages.editor.locale.st' },
  su: { defaultMessage: 'Sundanese', id: 'admin/pages.editor.locale.su' },
  sv: { defaultMessage: 'Swedish', id: 'admin/pages.editor.locale.sv' },
  sw: { defaultMessage: 'Swahili', id: 'admin/pages.editor.locale.sw' },
  ta: { defaultMessage: 'Tamil', id: 'admin/pages.editor.locale.ta' },
  te: { defaultMessage: 'Telugu', id: 'admin/pages.editor.locale.te' },
  tg: { defaultMessage: 'Tajik', id: 'admin/pages.editor.locale.tg' },
  th: { defaultMessage: 'Thai', id: 'admin/pages.editor.locale.th' },
  ti: { defaultMessage: 'Tigrinya', id: 'admin/pages.editor.locale.ti' },
  tk: { defaultMessage: 'Turkmen', id: 'admin/pages.editor.locale.tk' },
  tl: { defaultMessage: 'Tagalog', id: 'admin/pages.editor.locale.tl' },
  tn: { defaultMessage: 'Tswana', id: 'admin/pages.editor.locale.tn' },
  to: { defaultMessage: 'Tongan', id: 'admin/pages.editor.locale.to' },
  tr: { defaultMessage: 'Turkish', id: 'admin/pages.editor.locale.tr' },
  ts: { defaultMessage: 'Tsonga', id: 'admin/pages.editor.locale.ts' },
  tt: { defaultMessage: 'Tatar', id: 'admin/pages.editor.locale.tt' },
  tw: { defaultMessage: 'Twi', id: 'admin/pages.editor.locale.tw' },
  ty: { defaultMessage: 'Tahitian', id: 'admin/pages.editor.locale.ty' },
  ug: { defaultMessage: 'Uyghur', id: 'admin/pages.editor.locale.ug' },
  uk: { defaultMessage: 'Ukrainian', id: 'admin/pages.editor.locale.uk' },
  ur: { defaultMessage: 'Urdu', id: 'admin/pages.editor.locale.ur' },
  uz: { defaultMessage: 'Uzbek', id: 'admin/pages.editor.locale.uz' },
  ve: { defaultMessage: 'Venda', id: 'admin/pages.editor.locale.ve' },
  vi: { defaultMessage: 'Vietnamese', id: 'admin/pages.editor.locale.vi' },
  vo: { defaultMessage: 'Volapük', id: 'admin/pages.editor.locale.vo' },
  wa: { defaultMessage: 'Walloon', id: 'admin/pages.editor.locale.wa' },
  wo: { defaultMessage: 'Wolof', id: 'admin/pages.editor.locale.wo' },
  xh: { defaultMessage: 'Xhosa', id: 'admin/pages.editor.locale.xh' },
  yi: { defaultMessage: 'Yiddish', id: 'admin/pages.editor.locale.yi' },
  yo: { defaultMessage: 'Yoruba', id: 'admin/pages.editor.locale.yo' },
  za: { defaultMessage: 'Zhuang', id: 'admin/pages.editor.locale.za' },
  zh: { defaultMessage: 'Chinese', id: 'admin/pages.editor.locale.zh' },
  zu: { defaultMessage: 'Zulu', id: 'admin/pages.editor.locale.zu' },
})

export default messages

```


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

[User] Show me the implementation of admin-pages/react/components/DomainMessages/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import ApolloClient from 'apollo-client'
import { InjectedIntl } from 'react-intl'

export interface Props {
  runtime: RenderContext
  domain: string
  client: ApolloClient<unknown>
}

export interface Message {
  key: string
  message: string
}

export interface Data {
  messages: Message[]
}

export interface Variables {
  components: string[]
  domain: string
  renderMajor: number
}

export interface AvailableCulturesProps {
  client: ApolloClient<unknown>
  intl: InjectedIntl
}

export interface Languages {
  languages: {
    default: string
    supported: string[]
  }
}

export interface LabelledLocale {
  label: string
  value: string
}

```


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

[User] Show me the implementation of admin-pages/react/components/ActionMenu/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import {
  ActionMenu as StyleguideActionMenu,
  IconOptionsDots,
} from 'vtex.styleguide'

import { ActionMenuOption } from './typings'

interface Props {
  buttonSize?: string
  menuWidth?: number | string
  options: ActionMenuOption[]
  variation?: string
}

const icon = <IconOptionsDots color="currentColor" />

const ActionMenu: React.FunctionComponent<Props> = ({
  buttonSize,
  menuWidth,
  options,
  variation = 'tertiary',
}) => (
  <StyleguideActionMenu
    buttonProps={{
      icon,
      size: buttonSize,
      type: 'button',
      variation,
    }}
    hideCaretIcon
    menuWidth={menuWidth}
    options={options}
  />
)

export default ActionMenu

```


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

[User] Show me the implementation of admin-pages/react/components/ActionMenu/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface ActionMenuOption {
  isDangerous?: boolean
  label: string
  onClick: (e: ActionMenuOption) => void
}

```


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

[User] Show me the implementation of admin-pages/react/components/HighlightOverlay/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { CSSTransition } from 'react-transition-group'
import { canUseDOM } from 'vtex.render-runtime'

import useAutoScroll from './hooks/useAutoScroll'
import useHighlightOnHover from './hooks/useHighlightOnHover'
import useHighlightedElementInfo from './hooks/useHighlightedElementInfo'
import usePortal from './hooks/usePortal'
import useResizeObserver from './hooks/useResizeObserver'
import useStyles from './hooks/useStyles'
import OverlayMask from './OverlayMask'
import { State } from './typings'

import styles from './HighlightOverlay.css'

interface Props {
  editExtensionPoint: (treePath: string | null) => void
  editMode: boolean
  highlightHandler: (treePath: string | null) => void
  highlightTreePath: string | null
}

const classNames = {
  enter: styles['highlight-enter'],
  enterActive: styles['highlight-enter-active'],
  enterDone: styles['highlight-enter-done'],
  exit: styles['highlight-exit'],
  exitActive: styles['highlight-exit-active'],
  exitDone: styles['highlight-exit-done'],
}

const HighlightOverlay: React.FC<Props> = props => {
  const [state, setState] = React.useState<State>(() => ({
    editExtensionPoint: props.editExtensionPoint,
    editMode: props.editMode,
    highlightHandler: props.highlightHandler,
    highlightTreePath: props.highlightTreePath,
    openBlockTreePath: null,
    sidebarBlocksMap: {},
  }))

  const {
    editMode,
    highlightTreePath,
    openBlockTreePath,
    sidebarBlocksMap,
  } = state

  const { subscribeToResize, unsubscribeToResize } = useResizeObserver()

  const portalContainer = usePortal({ subscribeToResize, unsubscribeToResize })

  useHighlightOnHover(state)

  React.useEffect(() => {
    const highlightableWindow = window

    if (canUseDOM) {
      highlightableWindow.__setHighlightTreePath = (
        newState: Partial<State>
      ) => {
        setState(prevState => {
          return {
            ...prevState,
            ...newState,
            sidebarBlocksMap: {
              ...prevState.sidebarBlocksMap,
              ...newState.sidebarBlocksMap,
            },
          }
        })
      }
    }
  }, [setState])

  const titleTreePath = highlightTreePath || openBlockTreePath

  const { visibleElement, hasValidElement } = useHighlightedElementInfo(
    titleTreePath,
    sidebarBlocksMap,
    state.elementHeight
  ) || { visibleElement: undefined, hasValidElement: false }

  useAutoScroll({ editMode, highlightTreePath, visibleElement })

  const isOverlayMaskActive = Boolean(
    hasValidElement && openBlockTreePath && portalContainer
  )

  useStyles({
    hasValidElement,
    highlightTreePath: titleTreePath,
    isOverlayMaskActive,
    setState,
    subscribeToResize,
    unsubscribeToResize,
    visibleElement,
  })

  const hasHighlight = highlightTreePath && hasValidElement

  const title =
    titleTreePath &&
    sidebarBlocksMap[titleTreePath] &&
    sidebarBlocksMap[titleTreePath].title

  return (
    <>
      <CSSTransition
        in={
          Boolean(hasValidElement && hasHighlight) ||
          Boolean(hasValidElement && openBlockTreePath)
        }
        classNames={classNames}
        mountOnEnter
        timeout={150}
      >
        <div
          data-testid="editor-provider-overlay"
          id="editor-provider-overlay"
          style={state.highlightStyle}
          className="absolute bw2 ba"
        >
          {title && (
            <p
              className="absolute white f7 ma0 right-0 ph2 pb2 pt1 truncate tc"
              style={state.labelStyle}
              title={title}
            >
              {title}
            </p>
          )}
        </div>
      </CSSTransition>
      {ReactDOM.createPortal(
        <OverlayMask style={state.maskStyle} isActive={isOverlayMaskActive} />,
        portalContainer
      )}
    </>
  )
}

export default HighlightOverlay

```


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

[User] Show me the implementation of admin-pages/react/components/HighlightOverlay/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

export interface State {
  editExtensionPoint: (treePath: string | null) => void
  editMode: boolean
  elementHeight?: HTMLElement['clientHeight']
  highlightStyle?: CSSProperties
  labelStyle?: CSSProperties
  maskStyle?: CSSProperties
  openBlockTreePath: string | null
  highlightHandler: (treePath: string | null) => void
  highlightTreePath: string | null
  sidebarBlocksMap: Record<string, { title?: string; isEditable: boolean }>
}

```


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

[User] Show me the implementation of admin-pages/react/components/HighlightOverlay/index.test.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

import { State } from './typings'
import HighlightOverlay from './index'

const extensionPointName = 'welcome'

function createMockDiv(width: number, height: number) {
  const renderProviderDiv = document.createElement('div')
  renderProviderDiv.setAttribute('class', 'render-provider')
  Object.assign(renderProviderDiv.style, {
    width: '1440px',
    height: '900px',
  })

  const div = document.createElement('div')
  Object.assign(div.style, {
    width: `${width}px`,
    height: `${height}px`,
  })

  // we have to mock this for jsdom.
  div.getBoundingClientRect = () => ({
    width,
    height,
    top: 0,
    left: 0,
    right: width,
    bottom: height,
    x: width,
    y: height,
    toJSON() {
      const { toJSON, ...rect } = this
      return rect
    },
  })
  div.textContent = 'Welcome'
  div.setAttribute('data-extension-point', extensionPointName)

  renderProviderDiv.getBoundingClientRect = () => ({
    width,
    height,
    top: 0,
    left: 0,
    right: width,
    bottom: height,
    x: width,
    y: height,
    toJSON() {
      const { toJSON, ...rect } = this
      return rect
    },
  })
  renderProviderDiv.appendChild(div)
  return renderProviderDiv
}

const mockBlocks: State['sidebarBlocksMap'] = {
  welcome: {
    isEditable: true,
    title: 'Welcome Banner',
  },
}

function setUpDom() {
  Object.defineProperty(HTMLElement.prototype, 'scrollWidth', {
    configurable: true,
    get: function getScrollWidth() {
      return this._scrollWidth || 0
    },
    set(val) {
      this._scrollWidth = val
    },
  })

  // eslint-disable-next-line
  // @ts-ignore
  document.body.scrollWidth = 1440
  document.body.appendChild(createMockDiv(300, 300))
}

function cleanUpDOM() {
  document.body.innerHTML = '<div></div>'
}

describe('HighlightOverlay', () => {
  beforeEach(() => {
    setUpDom()
  })
  afterEach(() => {
    cleanUpDOM()
  })

  it(`should edit extension-point when its element is clicked`, () => {
    const mockEditExtensionPoint = jest.fn()
    const mockHighlightHandler = jest.fn()
    const { getByText } = render(
      <HighlightOverlay
        editExtensionPoint={mockEditExtensionPoint}
        editMode
        highlightHandler={mockHighlightHandler}
        highlightTreePath={extensionPointName}
      />
    )
    const extensionPointDiv = getByText(/welcome/i)
    act(() => {
      window.__setHighlightTreePath({ sidebarBlocksMap: mockBlocks })
    })

    fireEvent.click(extensionPointDiv)

    expect(mockEditExtensionPoint).toBeCalledTimes(1)
    expect(mockEditExtensionPoint).toHaveBeenCalledWith(extensionPointName)
  })

  it(`should have highlight when an element is being edited`, () => {
    const mockEditExtensionPoint = jest.fn()
    const mockHighlightHandler = jest.fn()
    const { queryByTestId } = render(
      <HighlightOverlay
        editExtensionPoint={mockEditExtensionPoint}
        editMode
        highlightHandler={mockHighlightHandler}
        highlightTreePath={null}
      />
    )

    expect(queryByTestId('editor-provider-overlay')).toBeFalsy()

    act(() => {
      window.__setHighlightTreePath({
        openBlockTreePath: extensionPointName,
        sidebarBlocksMap: mockBlocks,
      })
    })

    expect(queryByTestId('editor-provider-overlay')).toBeTruthy()
  })

  it('should set tree path when corresponding element is hovered', () => {
    const mockEditExtensionPoint = jest.fn()
    const mockHighlightHandler = jest.fn()

    render(
      <HighlightOverlay
        editExtensionPoint={mockEditExtensionPoint}
        editMode
        highlightHandler={mockHighlightHandler}
        highlightTreePath={null}
      />
    )

    act(() => {
      window.__setHighlightTreePath({ sidebarBlocksMap: mockBlocks })
    })

    const extensionPointDiv = document.querySelector(
      '[data-extension-point="welcome"]'
    )

    if (extensionPointDiv) {
      fireEvent.mouseOver(extensionPointDiv)
    }

    expect(mockHighlightHandler).toHaveBeenCalledTimes(1)
    expect(mockHighlightHandler).toHaveBeenCalledWith('welcome')
  })

  it('should highlight element when it is set externally', () => {
    const mockEditExtensionPoint = jest.fn()
    const mockHighlightHandler = jest.fn()
    const { queryByTestId } = render(
      <HighlightOverlay
        editExtensionPoint={mockEditExtensionPoint}
        editMode
        highlightHandler={mockHighlightHandler}
        highlightTreePath={extensionPointName}
      />
    )

    expect(queryByTestId('editor-provider-overlay')).toBeFalsy()

    act(() => {
      window.__setHighlightTreePath({
        sidebarBlocksMap: mockBlocks,
      })
    })

    expect(queryByTestId('editor-provider-overlay')).toBeTruthy()
  })

  it(`should show extension point title when it's highlighted`, () => {
    const mockEditExtensionPoint = jest.fn()
    const mockHighlightHandler = jest.fn()
    const { queryByText } = render(
      <HighlightOverlay
        editExtensionPoint={mockEditExtensionPoint}
        editMode
        highlightHandler={mockHighlightHandler}
        highlightTreePath={extensionPointName}
      />
    )

    expect(queryByText(/welcome banner/i)).toBeFalsy()

    act(() => {
      window.__setHighlightTreePath({
        sidebarBlocksMap: mockBlocks,
      })
    })

    expect(queryByText(/welcome banner/i)).toBeTruthy()
  })
})

```


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

[User] Show me the implementation of admin-pages/react/components/HighlightOverlay/HighlightOverlay.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.highlight-enter {
  opacity: 0;
  border-color: rgba(19, 76, 216, 0);
}

.highlight-enter-active {
  transition: opacity 150ms cubic-bezier(0.19, 1, 0.22, 1),
    border-color 150ms cubic-bezier(0.19, 1, 0.22, 1);
  opacity: 1;
  border-color: rgba(19, 76, 216, 1);
}

.highlight-enter-done {
  opacity: 1;
  border-color: rgba(19, 76, 216, 1);
}

.highlight-exit {
  opacity: 1;
  border-color: rgba(19, 76, 216, 1);
}

.highlight-exit-active {
  transition: opacity 150ms cubic-bezier(0.215, 0.61, 0.355, 1),
    border-color 150ms cubic-bezier(0.215, 0.61, 0.355, 1);
  opacity: 0;
  border-color: rgba(19, 76, 216, 0);
}

.highlight-exit-done {
  opacity: 0;
  border-color: rgba(19, 76, 216, 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 admin-pages/react/components/TemporaryAlert/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import {
  Alert,
  ThemeProvider,
  createSystem,
  tag,
  Flex,
  IconNotifications,
  Anchor,
} from '@vtex/admin-ui'
import { useIntl } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'

const system = createSystem('admin-pages')

export function TemporaryAlert() {
  const { workspace, production } = useRuntime()
  const { formatMessage } = useIntl()

  if (workspace !== 'newadmin' || !production) {
    return null
  }

  const url = window.top.location.href.replace(`${workspace}--`, '')

  return (
    <ThemeProvider system={system}>
      <tag.div
        csx={{
          padding: 4,
        }}
      >
        <Alert visible fluid>
          <Flex>
            <Flex align="center">
              <IconNotifications
                csx={{
                  color: 'blue',
                }}
              />
            </Flex>
            <Flex
              align="center"
              csx={{
                marginLeft: 2,
              }}
            >
              <span>
                {formatMessage({ id: 'admin/pages.editor.newadmin.alert' })}
                <Anchor href={url} target="_blank">
                  {formatMessage({
                    id: 'admin/pages.editor.newadmin.alert.anchor',
                  })}
                </Anchor>
              </span>
            </Flex>
          </Flex>
        </Alert>
      </tag.div>
    </ThemeProvider>
  )
}

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import classnames from 'classnames'
import { JSONSchema6 } from 'json-schema'
import React, { Fragment, useMemo, useRef, useState } from 'react'
import { graphql, MutationFunc } from 'react-apollo'
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'
import { WidgetProps } from 'react-jsonschema-form'
import URL from 'url-parse'
import { Spinner } from 'vtex.styleguide'

import UploadFile from '../../../queries/UploadFile.graphql'
import ActionMenu from '../../ActionMenu'
import { ActionMenuOption } from '../../ActionMenu/typings'
import Dropzone from './Dropzone'
import EmptyState from './EmptyState'
import ErrorAlert from './ErrorAlert'
import ImagePreview from './ImagePreview'

interface Props {
  disabled?: boolean
  onChange?: (pathname: string | null) => void
  onFileDrop?: (file: File) => void
  schema: JSONSchema6
  uploadFile?: MutationFunc<MutationData>
  value: string
}

interface State {
  error: string | null
  isLoading: boolean
}

interface MutationData {
  uploadFile: { fileUrl: string }
}

const messages = defineMessages({
  delete: {
    defaultMessage: 'Delete',
    id: 'admin/pages.admin.pages.form.field.array.item.delete',
  },
  edit: {
    defaultMessage: 'Edit',
    id: 'admin/pages.admin.pages.form.field.array.item.edit',
  },
  fileSizeError: {
    defaultMessage:
      'File exceeds the size limit of 4MB. Please choose a smaller one.',
    id: 'admin/pages.editor.image-uploader.error.file-size',
  },
  genericError: {
    defaultMessage: 'Something went wrong. Please try again.',
    id: 'admin/pages.editor.image-uploader.error.generic',
  },
})

const ImageUploader: React.FC<Props> = props => {
  const [state, setState] = useState<State>({ error: null, isLoading: false })
  const dropZoneRef = useRef<HTMLDivElement>(null)

  const intl = useIntl()

  const {
    disabled,
    onChange,
    schema: { title },
    value,
  } = props
  const { error, isLoading } = state

  const handleImageDrop = async (acceptedFiles: File[]) => {
    const { uploadFile } = props as {
      uploadFile: MutationFunc<MutationData>
    }

    if (acceptedFiles && acceptedFiles[0]) {
      setState(prevState => ({ ...prevState, isLoading: true }))

      try {
        let url = null

        if (uploadFile) {
          const {
            data: {
              uploadFile: { fileUrl },
            },
          } = (await uploadFile({
            variables: { file: acceptedFiles[0] },
          })) as { data: MutationData }
          url = fileUrl
        }

        if (onChange) {
          const path = url && new URL(url).pathname
          onChange(path)
        }

        if (props.onFileDrop) {
          props.onFileDrop(acceptedFiles[0])
        }

        setState(prevState => ({ ...prevState, isLoading: false }))
      } catch (e) {
        setState({
          error: intl.formatMessage(messages.genericError),
          isLoading: false,
        })
      }
    } else {
      setState(prevState => ({
        ...prevState,
        error: intl.formatMessage(messages.fileSizeError),
      }))
    }
  }

  const handleErrorReset = () => {
    setState(prevState => ({ ...prevState, error: null }))
  }

  const options: ActionMenuOption[] = useMemo(
    () => [
      {
        label: intl.formatMessage(messages.edit),
        onClick: () => {
          if (dropZoneRef.current) {
            dropZoneRef.current.click()
          }
        },
      },
      {
        label: intl.formatMessage(messages.delete),
        onClick: () => {
          if (onChange) {
            onChange(null)
          }
        },
      },
    ],
    [intl, onChange, dropZoneRef]
  )

  return (
    <Fragment>
      <FormattedMessage id={title as string}>
        {text => <span className="w-100 db mb3">{text}</span>}
      </FormattedMessage>
      <Dropzone
        disabled={disabled || isLoading}
        extraClasses={classnames({
          'ba b--dashed bw1 b--light-gray': !value || isLoading,
          'bg-light-gray pointer': !!value,
          'bg-white b--solid': isLoading,
          cursor: !isLoading && !value,
        })}
        onClick={handleErrorReset}
        onDrop={handleImageDrop}
        ref={dropZoneRef}
      >
        {isLoading ? (
          <div className="w-100 h-100 flex justify-center items-center">
            <Spinner />
          </div>
        ) : value ? (
          <ImagePreview imageUrl={value}>
            <ActionMenu
              variation="primary"
              menuWidth={200}
              options={options}
              buttonSize="small"
            />
          </ImagePreview>
        ) : (
          <EmptyState />
        )}
      </Dropzone>
      {error && <ErrorAlert message={error} />}
    </Fragment>
  )
}

ImageUploader.defaultProps = {
  disabled: false,
  value: '',
}

export default graphql<Props & (WidgetProps | {})>(UploadFile, {
  name: 'uploadFile',
})(ImageUploader)

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/Dropzone.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactElement } from 'react'
import ReactDropzone, { DropzoneOptions, useDropzone } from 'react-dropzone'

interface Props {
  children: ReactElement<unknown>
  disabled: boolean
  extraClasses?: string
  onClick: React.MouseEventHandler<HTMLElement>
  onDrop: DropzoneOptions['onDrop']
  ref?: React.Ref<HTMLDivElement>
}

const MAX_SIZE = 4 * 1024 * 1024

const Dropzone = React.forwardRef<HTMLDivElement, Props>(
  ({ disabled, children, extraClasses, onClick, onDrop }, ref) => {
    const { isDragActive } = useDropzone()

    const stlye = isDragActive
      ? { borderColor: '#134cd8', width: '14.25rem', height: '7rem' }
      : {}

    return (
      <ReactDropzone
        accept="image/*"
        disabled={disabled}
        maxSize={MAX_SIZE}
        multiple={false}
        onDrop={onDrop}
      >
        {({ getRootProps, getInputProps }) => (
          <div
            {...getRootProps({ onClick: e => onClick(e), stlye })}
            className={`w-100 h4 br2 ${extraClasses}`}
            ref={ref}
          >
            <input {...getInputProps()} />
            {children}
          </div>
        )}
      </ReactDropzone>
    )
  }
)

Dropzone.displayName = 'Dropzone'

Dropzone.defaultProps = {
  extraClasses: '',
}

export default Dropzone

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.emptyStateContainer {
  width: 100%;
  height: 8rem;
}

.emptyState {
  width: 100%;
  height: 100%;
  text-align: center;
  margin: auto;
}

.emptyStateContainer:hover > div {
  color: #134cd8;
  border-color: #134cd8;
  width: 12.93rem;
  height: 7rem;
}

.imageUploaderText {
  max-width: 11.3rem;
}

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/ImagePreview.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { createKeydownFromClick } from 'keydown-from-click'
import React, { useMemo } from 'react'

import styles from './ImagePreview.css'

interface Props {
  imageUrl: string
  children: React.ReactElement
}

function stopPropagation(
  e: Pick<React.MouseEvent<HTMLDivElement>, 'stopPropagation'>
) {
  e.stopPropagation()
}

const stopOnKeyDownPropagation = createKeydownFromClick(stopPropagation)

const ImagePreview: React.FC<Props> = ({ children, imageUrl }) => {
  const backgroundImageStyle = useMemo(
    () => ({
      backgroundImage: `url(${imageUrl}?width=710&height=384&aspect=true)`,
    }),
    [imageUrl]
  )

  return (
    <div
      className="w-100 h-100 relative bg-center contain"
      style={backgroundImageStyle}
    >
      <div
        className={`w-100 h-100 absolute bottom-0 br2 flex flex-column items-center justify-center ${styles.overlay}`}
      >
        <div
          style={{ top: '0.5rem', right: '0.5rem' }}
          className="absolute bg-action-primary br2 flex h2 items-center justify-center w2 white"
          onClick={stopPropagation}
          onKeyDown={stopOnKeyDownPropagation}
          role="button"
          tabIndex={0}
        >
          {children}
        </div>
      </div>
    </div>
  )
}

export default React.memo(ImagePreview)

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/ErrorAlert.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import { Alert } from 'vtex.styleguide'

interface Props {
  message: string
}

const ErrorAlert: React.FunctionComponent<Props> = ({ message }) => {
  const [isVisible, setIsVisible] = useState(true)

  return isVisible ? (
    <div className="w-100 mt3">
      <Alert onClose={() => setIsVisible(false)} type="error">
        {message}
      </Alert>
    </div>
  ) : null
}

export default ErrorAlert

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/EmptyState.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { FormattedMessage } from 'react-intl'

import IconImage from '../../MediaGalleryWidget/icons/IconImage'
import styles from './styles.css'

const EmptyState = ({ style }: { style?: React.CSSProperties }) => {
  return (
    <div
      className={`flex justify-center align-center items-center ${styles.emptyStateContainer}`}
    >
      <div
        style={style}
        className={`h-100 flex flex-column justify-center items-center pointer b--mid-gray b--dashed ba br2 c-muted-1 ${styles.emptyState}`}
      >
        <div className="mb4">
          <IconImage />
        </div>
        <div className={`tc ${styles.imageUploaderText}`}>
          <FormattedMessage id="admin/pages.editor.image-uploader.empty.button" />
        </div>
      </div>
    </div>
  )
}

export default React.memo(EmptyState)

```


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

[User] Show me the implementation of admin-pages/react/components/form/ImageUploader/ImagePreview.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.overlay {
  background: rgba(0, 0, 0, 0.15);
  opacity: 0;
  transition: opacity ease-in-out 100ms;
}

.overlay:hover {
  opacity: 1;
}

```


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

[User] Show me the implementation of admin-pages/react/components/form/I18nInput/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

import { appendInvisibleCharacter } from '../../../utils/components'
import BaseInput from '../BaseInput'
import TextArea from '../TextArea'
import { CustomWidgetProps } from '../typings'

import { isValidData } from './utils'

interface Props extends CustomWidgetProps {
  isTextarea?: boolean
}

/*
 * While there isn't currently an efficient way to update the inner Runtime's
 * intl, this component uses the IOMessage's fallback behavior to modify i18n
 * properties.
 *
 * Since the value actually represents an i18n key, typing in the name of an
 * existing one would cause the block to render the corresponding intl string.
 *
 * In order to prevent that, this component adds an invisible character after
 * the input value, so it will (probably) never match an i18n key. The
 * invisible character is removed once the form is submitted, before being sent
 * to the server.
 */

const I18nInput: React.FunctionComponent<Props> = ({
  isTextarea,
  onChange,
  value,
  ...commonProps
}) => {
  const [localValue, setLocalValue] = React.useState(value)

  const safeOnChange: CustomWidgetProps['onChange'] = React.useCallback(
    data => {
      if (!isValidData(data)) {
        return
      }

      const { target, value: newValue } = data

      let cursorPosition = target.selectionStart

      // Appends an invisible character to the input value. For more
      // information, please read the comment above this component.
      onChange(appendInvisibleCharacter(newValue))

      setLocalValue(newValue)

      // Prevents the cursor from jumping around
      target.selectionStart = cursorPosition
    },
    [onChange]
  )

  const finalProps = {
    ...commonProps,
    isI18n: true,
    onChange: safeOnChange,
    value: localValue,
  }

  if (isTextarea) {
    return <TextArea {...finalProps} />
  }

  return <BaseInput {...finalProps} />
}

export default I18nInput

```


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

[User] Show me the implementation of admin-pages/react/components/form/I18nInput/utils.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const isValidData = (
  data: unknown
): data is {
  target: HTMLInputElement | HTMLTextAreaElement
  value: string
} =>
  typeof data === 'object' &&
  data !== null &&
  Object.prototype.hasOwnProperty.call(data, 'target') &&
  Object.prototype.hasOwnProperty.call(data, 'value')

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { JSONSchema6 } from 'json-schema'
import React, { Component, Fragment } from 'react'
import {
  injectIntl,
  WrappedComponentProps as ComponentWithIntlProps,
} from 'react-intl'
import { ArrayFieldTemplateProps } from 'react-jsonschema-form'
import {
  Dimensions,
  SortableContainerProps,
  SortStart,
} from 'react-sortable-hoc'

import AddButton from './AddButton'
import ArrayList from './ArrayList'
import styles from './styles.css'

interface Props extends ComponentWithIntlProps {
  canAdd: boolean
  items?: ArrayFieldTemplateProps['items']
  onAddClick?: (event: Event) => void
  schema: JSONSchema6
}

interface State {
  sorting?: boolean
  openItem: number | null
}

function getHelperDimensions({ node }: SortStart): Dimensions {
  const label = node.querySelector(
    `.${styles['accordion-label']}`
  ) as HTMLElement
  const width = node instanceof HTMLElement ? node.offsetWidth : 0

  return {
    height: label && label.offsetHeight,
    width,
  }
}

class ArrayFieldTemplate extends Component<
  Props & ArrayFieldTemplateProps,
  State
> {
  private stackDepth: number

  public constructor(props: Props & ArrayFieldTemplateProps) {
    super(props)

    this.state = {
      openItem: null,
    }

    this.stackDepth =
      (this.props.formContext.componentFormState &&
        this.props.formContext.componentFormState.depth) ||
      0
  }

  public render() {
    const { canAdd, intl, items, schema, title } = this.props
    const { openItem, sorting } = this.state

    return (
      <Fragment>
        {!openItem && title && (
          <h4 className="mb4 mt0">{intl.formatMessage({ id: title })}</h4>
        )}
        <ArrayList
          formContext={this.props.formContext}
          getHelperDimensions={getHelperDimensions}
          getContainer={this.getContainer}
          helperClass={styles['accordion-item--dragged']}
          items={items}
          lockAxis="y"
          lockToContainerEdges
          onClose={this.handleClose}
          onOpen={this.handleOpen}
          onSortEnd={this.handleSortEnd}
          onSortStart={this.handleSortStart}
          openItem={openItem}
          stackDepth={this.stackDepth}
          schema={schema}
          sorting={sorting}
          useDragHandle
        >
          {canAdd ? <AddButton onClick={this.handleAddItem} /> : null}
        </ArrayList>
      </Fragment>
    )
  }

  private getContainer() {
    return (
      document.getElementById('component-editor-container') || document.body
    )
  }

  private handleOpen = (index: number) => (e: React.MouseEvent | unknown) => {
    if (e instanceof Event) {
      e.stopPropagation()
    }

    if (typeof this.props.formContext.pushComponentFormState === 'function') {
      this.props.formContext.pushComponentFormState({
        onClose: this.handleClose,
        title: this.props.intl.formatMessage({ id: this.props.title }),
      })
    }

    this.setState(state => ({
      ...state,
      openItem: index,
    }))
  }

  private handleClose = () => {
    if (typeof this.props.formContext.popComponentFormState === 'function') {
      this.props.formContext.popComponentFormState()
    }

    this.setState(state => ({
      ...state,
      openItem: null,
    }))
  }

  private handleSortStart = () => {
    this.setState({
      sorting: true,
    })
  }

  private handleSortEnd: SortableContainerProps['onSortEnd'] = (
    { oldIndex, newIndex },
    e
  ) => {
    const { items } = this.props
    const { onReorderClick } = items[oldIndex]

    if (oldIndex !== newIndex) {
      onReorderClick(oldIndex, newIndex)(e)
    }

    this.setState({
      sorting: false,
    })
  }

  private handleAddItem = (e: Event) => {
    const { onAddClick, items } = this.props

    onAddClick(e)
    this.setState({
      openItem: items.length,
    })

    if (typeof this.props.formContext.pushComponentFormState === 'function') {
      this.props.formContext.pushComponentFormState({
        onClose: this.handleClose,
        title: this.props.intl.formatMessage({ id: this.props.title }),
      })
    }
  }
}

const ArrayFieldTemplateWithIntl = injectIntl(ArrayFieldTemplate)

const StatelessArrayFieldTemplate: React.FunctionComponent<ArrayFieldTemplateProps> = props => {
  return <ArrayFieldTemplateWithIntl {...props} />
}

export default StatelessArrayFieldTemplate

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayList.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { JSONSchema6 } from 'json-schema'
import { CSSTransition } from 'react-transition-group'
import React, { Fragment } from 'react'
import { ArrayFieldTemplateProps } from 'react-jsonschema-form'
import { SortableContainer, SortableContainerProps } from 'react-sortable-hoc'

import { ANIMATION_TIMEOUT } from '../../consts'
import { ActionMenuOption } from '../../ActionMenu/typings'

import ArrayFieldTemplateItem from './ArrayFieldTemplateItem'
import ItemForm from './ItemForm'

import styles from './styles.css'
import transitionStyles from './ItemTransitions.css'

interface ArrayListProps {
  formContext: { currentDepth: number }
  items: ArrayFieldTemplateProps['items']
  onClose: () => void
  onOpen: (
    index: number
  ) => (e: Pick<React.MouseEvent, 'stopPropagation'> | ActionMenuOption) => void
  openItem: number | null
  schema: JSONSchema6
  sorting?: boolean
  stackDepth: number
}

const transitionClassNames = {
  appear: transitionStyles['item-enter'],
  appearActive: transitionStyles['item-enter-active'],
  appearDone: transitionStyles['item-enter-done'],
  enter: transitionStyles['item-enter'],
  enterActive: transitionStyles['item-enter-active'],
  enterDone: transitionStyles['item-enter-done'],
  exit: transitionStyles['item-exit'],
  exitActive: transitionStyles['item-exit-active'],
  exitDone: transitionStyles['item-exit-done'],
}

const ArrayList: React.FC<ArrayListProps & SortableContainerProps> = ({
  children,
  formContext,
  items,
  schema,
  openItem,
  onOpen,
  onClose,
  sorting,
  stackDepth,
}) => (
  <div className={sorting ? styles['accordion-list-container--sorting'] : ''}>
    {children}
    {items.map(element => (
      <Fragment key={element.index}>
        <ArrayFieldTemplateItem
          schema={schema}
          onOpen={onOpen(element.index)}
          onClose={onClose}
          formIndex={element.index}
          showDragHandle={items.length > 1}
          {...element}
        />
        <CSSTransition
          appear
          in={element.index === openItem}
          mountOnEnter
          unmountOnExit
          timeout={ANIMATION_TIMEOUT}
          classNames={transitionClassNames}
        >
          <ItemForm
            currentDepth={formContext.currentDepth}
            stackDepth={stackDepth + 1}
            onClose={onClose}
          >
            {element.children}
          </ItemForm>
        </CSSTransition>
      </Fragment>
    ))}
  </div>
)

export default SortableContainer(ArrayList)

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ItemForm.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import classnames from 'classnames'
import React from 'react'
import { defineMessages, useIntl } from 'react-intl'
import { CSSTransition } from 'react-transition-group'
import { Button } from 'vtex.styleguide'
import { useRuntime } from 'vtex.render-runtime'

import styles from './styles.css'
import transitionStyles from './ItemTransitions.css'

interface Props {
  children: React.ReactElement
  currentDepth: number
  onClose: () => void
  stackDepth: number
}

const messages = defineMessages({
  apply: {
    defaultMessage: 'Apply',
    id: 'admin/pages.admin.pages.form.field.array.item.apply',
  },
})

const ItemForm: React.FC<Props> = ({
  children,
  currentDepth,
  onClose,
  stackDepth,
}) => {
  const intl = useIntl()
  const { route } = useRuntime()

  const isStoreSettingsPage = route.path.includes("cms/store")

  return (
    <CSSTransition
      in={stackDepth < currentDepth}
      classNames={{
        enter: transitionStyles['item-depth-enter'],
        enterActive: transitionStyles['item-depth-enter-active'],
        enterDone: transitionStyles['item-depth-enter-done'],
        exit: transitionStyles['item-depth-exit'],
        exitActive: transitionStyles['item-depth-exit-active'],
        exitDone: transitionStyles['item-depth-exit-done'],
      }}
      timeout={150}
    >
      <div
        className={classnames(
          `${styles['accordion-item']}
          ${isStoreSettingsPage && styles['accordion-item-settings']}
          bg-white bb b--light-silver absolute left-0 top-0 ph6 w-100 z-1`
        )}
      >
        {children}
        <div className="mb5">
          <Button type="button" variation="primary" onClick={onClose}>
            {intl.formatMessage(messages.apply)}
          </Button>
        </div>
      </div>
    </CSSTransition>
  )
}

export default ItemForm

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.accordion-item {
  background-color: white;
}

.accordion-item-settings {
  padding: 2rem;
  transform: translateX(0rem) !important;
}

.accordion-list-container--sorting .accordion-item {
  pointer-events: none;
}

.accordion-item--dragged {
  z-index: 999;
}

.accordion-label {
  display: flex;
  position: relative;
  margin: 0 -24px 0;
  padding: 12px 16px;
  cursor: pointer;
  user-select: none;
}

.accordion-item--dragged .accordion-label {
  background-color: #fff;
}

.accordion-item--handle-hidden .accordion-label {
  padding-left: 16px;
}

.accordion-item--dragged .accordion-label {
  box-shadow: 4px 4px 8px 0 rgba(0, 0, 0, 0.2);
}

.accordion-label-title {
  color: #727273;
  font-weight: bold;
  cursor: pointer;
}

.accordion-item--dragged .accordion-handle,
.accordion-label:hover .accordion-handle {
  display: block;
}

.drag-handle-container {
  transform: translateZ(0);
  transition: transform ease-in-out 100ms;
}

.drag-handle-container:hover,
.accordion-item--dragged .drag-handle-container {
  transform: scale(1.1);
}

.drag-handle-container:hover circle,
.accordion-item--dragged .drag-handle-container circle {
  fill: #368df7;
}

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/AddButton.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { FormattedMessage } from 'react-intl'
import { ButtonWithIcon } from 'vtex.styleguide'

import AddIcon from '../../icons/AddIcon'

interface Props {
  onClick: (event: Event) => void
}

const icon = <AddIcon />

const AddButton: React.FC<Props> = ({ onClick }) => (
  <div className="ba b--muted-4 br2 mb3">
    <ButtonWithIcon block icon={icon} onClick={onClick} variation="tertiary">
      <FormattedMessage
        defaultMessage="Add"
        id="admin/pages.editor.components.arrayTemplate.button.add"
      >
        {text => <div className="mv3">{text}</div>}
      </FormattedMessage>
    </ButtonWithIcon>
  </div>
)

export default AddButton

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ItemTransitions.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.item-enter {
  transform: translateX(36rem);
}

.item-enter-active {
  transform: translateX(18rem);
  transition: transform 250ms ease-in-out;
}

.item-enter-done {
  transform: translateX(18rem);
}

.item-exit {
  transform: translateX(18rem);
}

.item-exit-active {
  transform: translateX(36rem);
  transition: transform 250ms ease-in-out;
}

.item-exit-done {
  transform: translateX(36rem);
}

.item-depth-enter {
  transform: translateX(18rem);
}

.item-depth-enter-active {
  transform: translateX(0rem);
  transition: transform 250ms ease-in-out;
}

.item-depth-enter-done {
  transform: translateX(0rem);
}

/* So the hidden item doesn't affect the height of the current form */
.item-depth-enter-done > :global(.vtex-admin-pages-4-x .form-group) {
  height: 0;
  overflow: hidden;
}

.item-depth-exit {
  transform: translateX(0rem);
}

.item-depth-exit-active {
  transform: translateX(18rem);
  transition: transform 250ms ease-in-out;
}

.item-depth-exit-done {
  transform: translateX(18rem);
}

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayFieldTemplateItem/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { createKeydownFromClick } from 'keydown-from-click'
import classnames from 'classnames'
import { JSONSchema6 } from 'json-schema'
import { path } from 'ramda'
import React, { useCallback, useMemo } from 'react'
import { defineMessages, InjectedIntlProps, injectIntl } from 'react-intl'
import { ArrayFieldTemplateProps } from 'react-jsonschema-form'
import { SortableElement, SortableElementProps } from 'react-sortable-hoc'

import ActionMenu from '../../../ActionMenu'
import { ActionMenuOption } from '../../../ActionMenu/typings'

import Handle from './Handle'
import NoImagePlaceholder from './NoImagePlaceholder'
import PreviewOverlay from './PreviewOverlay'

import templateStyles from '../styles.css'
import itemStyles from './ArrayFieldTemplateItem.css'

const stopPropagation = (e: Pick<React.MouseEvent, 'stopPropagation'>) => {
  e.stopPropagation()
}

interface CustomProps {
  children?: React.ReactElement<{ formData: number }> | React.ReactNode
  formIndex: number
  hasRemove: boolean
  onClose: () => void
  onOpen: (
    e: Pick<React.MouseEvent, 'stopPropagation'> | ActionMenuOption
  ) => void
  showDragHandle: boolean
  schema: JSONSchema6
}

type PropsFromItemTemplateProps = Pick<
  ArrayFieldTemplateProps['items'][0],
  'onDropIndexClick' | 'hasRemove' | 'children'
>
type Props = CustomProps &
  SortableElementProps &
  PropsFromItemTemplateProps &
  InjectedIntlProps

const messages = defineMessages({
  defaultTitle: {
    defaultMessage: 'Item',
    id: 'admin/pages.admin.pages.form.field.array.item',
  },
  delete: {
    defaultMessage: 'Delete',
    id: 'admin/pages.admin.pages.form.field.array.item.delete',
  },
  edit: {
    defaultMessage: 'Edit',
    id: 'admin/pages.admin.pages.form.field.array.item.edit',
  },
})

function getComponentSchema(schema: JSONSchema6): ComponentSchema | null {
  if (
    schema.items &&
    !Array.isArray(schema.items) &&
    typeof schema.items === 'object' &&
    typeof schema.items.properties === 'object'
  ) {
    return schema as ComponentSchema
  }
  return null
}

const isImageUploader = (schema: ComponentSchema) =>
  !!schema.widget && schema.widget['ui:widget'] === 'image-uploader'

const ArrayFieldTemplateItem: React.FC<Props> = props => {
  const {
    children,
    formIndex,
    hasRemove,
    intl,
    onOpen,
    onDropIndexClick,
    schema,
    showDragHandle,
  } = props

  const componentSchema = React.useMemo(() => getComponentSchema(schema), [
    schema,
  ])

  const handleItemClick = useCallback(
    (e: Pick<React.MouseEvent, 'stopPropagation'> | ActionMenuOption) => {
      onOpen(e)
    },
    [onOpen]
  )

  const handleItemKeyDown = createKeydownFromClick(handleItemClick)
  const itemStopPropagation = createKeydownFromClick(stopPropagation)

  const hasImageUploader = useMemo(
    () =>
      componentSchema &&
      componentSchema.items &&
      !Array.isArray(componentSchema.items) &&
      componentSchema.items.properties &&
      Object.values(componentSchema.items.properties).some(isImageUploader),
    [componentSchema]
  )

  const imagePreview = useMemo(() => {
    const properties =
      componentSchema &&
      componentSchema.items &&
      !Array.isArray(componentSchema.items) &&
      componentSchema.items.properties

    const imagePropertyKey =
      properties &&
      Object.keys(properties)
        .filter(property => isImageUploader(properties[property]))
        .sort((first, second) => {
          if (
            first.indexOf('mobile') !== -1 &&
            second.indexOf('mobile') === -1
          ) {
            return 1
          }

          if (
            first.indexOf('mobile') === -1 &&
            second.indexOf('mobile') !== -1
          ) {
            return -1
          }

          return 0
        })
        .find(key => {
          return !!children.props.formData[key]
        })

    return imagePropertyKey && children.props.formData[imagePropertyKey]
  }, [componentSchema, children.props.formData])

  const actionMenuOptions: ActionMenuOption[] = useMemo(() => {
    const options: ActionMenuOption[] = [
      {
        label: intl.formatMessage(messages.edit),
        onClick: e => {
          handleItemClick(e)
        },
      },
    ]

    if (hasRemove) {
      options.push({
        label: intl.formatMessage(messages.delete),
        onClick: () => {
          const e = new Event('click')
          onDropIndexClick(formIndex)(e)
        },
      })
    }

    return options
  }, [handleItemClick, onDropIndexClick, formIndex, hasRemove, intl])

  const title =
    children.props.formData.__editorItemTitle ||
    path(['items', 'properties', '__editorItemTitle', 'default'], schema)

  return (
    <div
      className={classnames(
        'bg-white bb b--light-silver',
        {
          [templateStyles['accordion-item--handle-hidden']]: showDragHandle,
        },
        templateStyles['accordion-item']
      )}
    >
      <div
        className={`${
          templateStyles['accordion-label']
        } bg-white flex items-center justify-center overflow-hidden relative outline-0 ${
          hasImageUploader ? 'h4' : 'h3'
        }`}
        onClick={handleItemClick}
        onKeyDown={handleItemKeyDown}
        role="treeitem"
        tabIndex={0}
      >
        {showDragHandle && <Handle />}
        <div
          className={classnames(
            'relative flex items-center',
            itemStyles['preview-container'],
            {
              [`${itemStyles['multi-item']} mr3`]: showDragHandle,
              [`${itemStyles['single-item']}`]: !showDragHandle,
              [`${itemStyles['preview-text-container']} ml3`]:
                !hasImageUploader && !showDragHandle,
            }
          )}
        >
          {hasImageUploader ? (
            <>
              {imagePreview ? (
                <img
                  alt="Preview"
                  className={`br3 bg-muted-5 h-100 w-100 ${itemStyles['preview-image']}`}
                  src={imagePreview}
                />
              ) : (
                <NoImagePlaceholder />
              )}
              <PreviewOverlay />
            </>
          ) : (
            <span className={`f6 ${templateStyles['accordion-label-title']}`}>
              {intl.formatMessage(
                title ? { id: title } : messages.defaultTitle
              )}
            </span>
          )}
          <div
            className={`absolute top-0 right-0 mr3 mt3 ${itemStyles['action-menu-container']}`}
            onClick={stopPropagation}
            onKeyDown={itemStopPropagation}
            role="button"
            tabIndex={0}
          >
            <ActionMenu
              variation="primary"
              menuWidth={200}
              options={actionMenuOptions}
              buttonSize="small"
            />
          </div>
        </div>
      </div>
    </div>
  )
}

export default injectIntl(SortableElement<Props>(ArrayFieldTemplateItem))

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayFieldTemplateItem/PreviewOverlay.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

import styles from './ArrayFieldTemplateItem.css'

const PreviewOverlay = () => (
  <div
    className={`br3 absolute w-100 h-100 top-0 ${styles['preview-overlay']}`}
  ></div>
)

export default React.memo(PreviewOverlay)

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayFieldTemplateItem/Handle.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { SortableHandle } from 'react-sortable-hoc'

import DragHandle from '../../../icons/DragHandle'
import styles from '../styles.css'

const Handle = SortableHandle(() => (
  <div
    className={`flex flex-grow-1 h-100 items-center justify-center ${styles['drag-handle-container']}`}
  >
    <DragHandle size={12} className={styles['accordion-handle']} />
  </div>
))

export default Handle

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayFieldTemplateItem/ArrayFieldTemplateItem.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.action-menu-container {
  opacity: 0;
  transition: opacity ease-in 100ms;
}

.preview-container:hover .action-menu-container {
  opacity: 1;
}

.preview-container {
  height: 100%;
}

.multi-item {
  width: calc(100% - 3rem);
}

.single-item {
  width: calc(100% - 1rem);
}

.preview-text-container {
  width: 100%;
}

.preview-image {
  object-fit: cover;
  transition: filter ease-in 100ms;
}

.preview-overlay {
  background-color: black;
  opacity: 0;
  transition: opacity ease-in 100ms;
  will-change: opacity;
}

.preview-container:hover .preview-overlay {
  opacity: 0.15;
}

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayFieldTemplateItem/NoImagePlaceholder.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { FormattedMessage } from 'react-intl'

import IconImage from './icons/IconImage'

const NoImagePlaceholder = () => (
  <div className="w-100 h-100 flex flex-column items-center justify-center bg-muted-5 br3">
    <IconImage />

    <FormattedMessage
      id="admin/pages.editor.components.no-image"
      defaultMessage="No image"
    >
      {text => <p className="c-muted-1 f6 mb0 mt4">{text}</p>}
    </FormattedMessage>
  </div>
)

export default React.memo(NoImagePlaceholder)

```


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

[User] Show me the implementation of admin-pages/react/components/form/ArrayFieldTemplate/ArrayFieldTemplateItem/icons/IconImage.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface Props {
  size?: number
  stroke?: string
}

const ImageIcon: React.FunctionComponent<Props> = ({ size, stroke }) => (
  <svg
    width={`${size}px`}
    height={`${size}px`}
    viewBox="0 0 24 24"
    version="1.1"
    xmlns="http://www.w3.org/2000/svg"
  >
    <g
      id="Artboard"
      stroke="none"
      strokeWidth="1"
      fill="none"
      fillRule="evenodd"
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <g
        id="image-2"
        transform="translate(0.000000, 1.000000)"
        stroke={stroke}
        strokeWidth="1.4"
      >
        <ellipse id="Oval" cx="8.25" cy="3.83426966" rx="3" ry="3.06741573" />
        <polygon
          id="Shape"
          points="0.75 22.238764 6.75 13.0365169 9.75 16.1039326 15.75 8.43539326 23.25 22.238764"
        />
      </g>
    </g>
  </svg>
)

ImageIcon.defaultProps = {
  size: 16,
  stroke: '#979899',
}

export default React.memo(ImageIcon)

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { withApollo, WithApolloClient } from 'react-apollo'
import { InjectedIntlProps, injectIntl } from 'react-intl'
import { CSSTransition } from 'react-transition-group'
import { ToastConsumerFunctions } from 'vtex.styleguide'

import { ANIMATION_TIMEOUT } from '../../consts'
import { useEditorContext } from '../../EditorContext'
import Modal from '../../Modal'
import SaveContentMutation from '../mutations/SaveContent'
import AbsoluteLoader from './AbsoluteLoader'
import BlockEditor from './BlockEditor'
import BlockSelector from './BlockSelector'
import useInitialEditingState from './hooks'
import { useModalContext } from './ModalContext'
import styles from './styles.css'
import Transitions from './Transitions'
import SendEventToAuditMutation from '../mutations/SendEventToAudit'

interface CustomProps {
  highlightHandler: (treePath: string | null) => void
  iframeRuntime: RenderContext
  updateHighlightTitleByTreePath: (
    titleByTreePath?: Record<string, { title?: string; isEditable: boolean }>
  ) => void
}

type Props = WithApolloClient<
  CustomProps & InjectedIntlProps & Pick<ToastConsumerFunctions, 'showToast'>
>

const Sidebar: React.FunctionComponent<Props> = ({
  client,
  highlightHandler,
  iframeRuntime,
  intl,
  showToast,
  updateHighlightTitleByTreePath,
}) => {
  const [scrollState, setScrollState] = React.useState('overflow-y-auto')
  const adminSidebar = React.createRef<HTMLElement>()
  const initialEditingState = useInitialEditingState({
    client,
    iframeRuntime,
    intl,
    showToast,
  })

  const {
    actionHandler: handleModalAction,
    cancelHandler: handleModalCancel,
    close: handleModalClose,
    getIsOpen: getIsModalOpen,
    getTextButtonAction,
    getTextButtonCancel,
    getTextMessage,
    getTitle,
    isActionDanger,
  } = useModalContext()

  const editor = useEditorContext()

  React.useEffect(() => {
    adminSidebar.current?.scroll(0, 0)

    if (editor.editTreePath && adminSidebar.current?.scrollTop === 0) {
      setScrollState('overflow-y-hidden vh-100')
    } else {
      setScrollState('overflow-x-auto')
    }
  }, [editor.editTreePath])

  return (
    <div
      id="sidebar-vtex-editor"
      className={'z-1 h-100 w-100 flex flex-row-reverse ' + scrollState}
    >
      <nav
        ref={adminSidebar}
        id="admin-sidebar"
        className={
          `transition animated fadeIn b--light-silver bw1 z-2 h-100 pt8 pt0-ns ` +
          `overflow-x-hidden w-100 font-display bg-white shadow-solid-x w-18em-ns ${styles['admin-sidebar']} ` +
          scrollState
        }
      >
        <div className="relative h-100 flex flex-column dark-gray overflow-y-auto">
          <Modal
            isActionDanger={isActionDanger}
            isActionLoading={editor.getIsLoading()}
            isOpen={getIsModalOpen()}
            onClickAction={handleModalAction}
            onClickCancel={handleModalCancel}
            onClose={handleModalClose}
            textButtonAction={getTextButtonAction()}
            textButtonCancel={getTextButtonCancel()}
            textMessage={getTextMessage()}
            title={getTitle()}
          />
          <div className="flex">
            <AbsoluteLoader
              containerClassName={`w-100 h-100 absolute top-0 ${
                !editor.getIsLoading() ? 'dn' : ''
              }`}
            />

            <CSSTransition
              classNames={{
                enter: styles['transition-selector-enter'],
                enterActive: styles['transition-selector-enter-active'],
                enterDone: styles['transition-selector-enter-done'],
                exit: styles['transition-selector-exit'],
                exitActive: styles['transition-selector-exit-active'],
                exitDone: styles['transition-selector-exit-done'],
              }}
              in={!!initialEditingState}
              timeout={ANIMATION_TIMEOUT}
            >
              <BlockSelector
                highlightHandler={highlightHandler}
                iframeRuntime={iframeRuntime}
                updateHighlightTitleByTreePath={updateHighlightTitleByTreePath}
              />
            </CSSTransition>

            <Transitions.Exit condition={!initialEditingState} to="right">
              <Transitions.Enter condition={!!initialEditingState} from="right">
                <SaveContentMutation>
                  {saveContent => (
                    <SendEventToAuditMutation>
                      {sendEventToAudit => (
                        <BlockEditor
                          iframeRuntime={iframeRuntime}
                          initialEditingState={initialEditingState}
                          saveContent={saveContent}
                          sendEventToAudit={sendEventToAudit}
                          showToast={showToast}
                        />
                      )}
                    </SendEventToAuditMutation>
                  )}
                </SaveContentMutation>
              </Transitions.Enter>
            </Transitions.Exit>
          </div>
        </div>
      </nav>
    </div>
  )
}

export default injectIntl(withApollo(Sidebar))

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/FormMetaContext.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component, createContext, useContext } from 'react'

import { FormMetaContext as FormMetaContextT } from './typings'

const defaultExternalState: FormMetaContextT = {
  getWasModified: () => {
    return false
  },
  setWasModified: () => {
    return
  },
}

const FormMetaContext = createContext(defaultExternalState)

export const useFormMetaContext = () => useContext(FormMetaContext)

export const FormMetaConsumer = FormMetaContext.Consumer

interface State extends FormMetaContextT {
  isLoading: boolean
  wasModified: boolean
}

export class FormMetaProvider extends Component<{}, State> {
  public constructor(props: {}) {
    super(props)

    this.state = {
      ...defaultExternalState,
      getWasModified: this.getWasModified,
      isLoading: false,
      setWasModified: this.setWasModified,
      wasModified: false,
    }
  }

  public render() {
    return (
      <FormMetaContext.Provider value={this.state}>
        {this.props.children}
      </FormMetaContext.Provider>
    )
  }

  private getWasModified: State['getWasModified'] = () => this.state.wasModified

  private setWasModified: State['setWasModified'] = (newValue, callback) => {
    this.setState({ wasModified: newValue }, () => {
      if (callback) {
        callback()
      }
    })
  }
}

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/utils.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import EXTENSIONS from './__fixtures__/extensions'
import { getIsSitewide } from './utils'

describe('getIsSitewide', () => {
  it('should return true for AFTER', () => {
    const mockEditTreePath = 'store.home/$after_footer'

    expect(getIsSitewide(EXTENSIONS, mockEditTreePath)).toBe(true)
  })

  it('should return true for AROUND', () => {
    const mockEditTreePath = 'store.home/$around_homeWrapper'

    expect(getIsSitewide(EXTENSIONS, mockEditTreePath)).toBe(true)
  })

  it('should return true for BEFORE', () => {
    const mockEditTreePath = 'store.home/$before_header.full'

    expect(getIsSitewide(EXTENSIONS, mockEditTreePath)).toBe(true)
  })

  it('should return false for blocks without role', () => {
    const mockEditTreePath = 'store.home/carousel#home'

    expect(getIsSitewide(EXTENSIONS, mockEditTreePath)).toBe(false)
  })
})

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.transition-editor-enter {
  transform: translateX(18em);
}

.transition-editor-enter-active {
  transition: transform 250ms ease-in;
  transform: translateX(0);
}

.transition-editor-enter-done {
  transform: translateX(0);
}

.transition-editor-exit {
  transform: translateX(0);
}

.transition-editor-exit-active {
  transition: transform 250ms ease-in;
  transform: translateX(18em);
}

.transition-editor-exit-done {
  transform: translateX(18em);
}

.transition-selector-enter {
  transform: translateX(0);
}

.transition-selector-enter-active {
  transition: transform 250ms ease-in;
  transform: translateX(-18em);
}

.transition-selector-enter-done {
  transform: translateX(-18em);
}

.transition-selector-exit {
  transform: translateX(-18em);
}

.transition-selector-exit-active {
  transition: transform 250ms ease-in;
  transform: translateX(0);
}

.transition-selector-exit-done {
  transform: translateX(0);
}

/* Non small */
@media screen and (min-width: 30em) {
  .admin-sidebar {
    border-left: 2px solid #f2f4f5;
  }

  .admin-sidebar::-webkit-scrollbar,
  .admin-sidebar::-webkit-scrollbar-track {
    width: 2px;
    background: #f2f4f5;
  }

  .admin-sidebar::-webkit-scrollbar-thumb {
    width: 2px;
    background: rgba(0, 0, 0, 0.2);
    border-radius: 2px;
  }
}

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/AbsoluteLoader.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import classnames from 'classnames'
import React from 'react'
import { Spinner } from 'vtex.styleguide'

import { useEditorContext } from '../../EditorContext'

interface Props {
  containerClassName?: string
}

const AbsoluteLoader: React.FunctionComponent<Props> = ({
  children,
  containerClassName,
}) => {
  const editor = useEditorContext()

  const isLoading = editor.getIsLoading()

  return (
    <>
      {isLoading ? (
        <div className="absolute bg-white-70 flex items-center h-100 justify-center w-100 z-2">
          <Spinner />
        </div>
      ) : null}

      <div className={classnames('relative', containerClassName)}>
        {children}
      </div>
    </>
  )
}

export default React.memo(AbsoluteLoader)

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/utils.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { formatIOMessage } from 'vtex.native-types'

import { getBlockPath } from '../../../utils/blocks'
import {
  getActiveContentId,
  getComponentSchema,
  getExtension,
  getIframeImplementation,
  getSchemaPropsOrContentFromRuntime,
} from '../../../utils/components'
import {
  GetDefaultCondition,
  GetFormData,
  GetInitialEditingState,
  UpdateEditorBlockData,
} from './typings'

export const isUnidentifiedPageContext = (
  pageContext: RenderRuntime['route']['pageContext']
) => pageContext.type !== '*' && pageContext.id === '*'

export const getIsSitewide = (
  extensions: Extensions,
  editTreePath: EditorContextType['editTreePath']
) => {
  const blockPath = getBlockPath(extensions, editTreePath)

  return (
    (blockPath.length > 0 &&
      ['AFTER', 'AROUND', 'BEFORE'].includes(blockPath[1].role)) ||
    false
  )
}

export const getDefaultCondition: GetDefaultCondition = ({
  iframeRuntime,
  isSitewide,
}) => {
  const iframePageContext = iframeRuntime.route.pageContext

  const pageContext: ExtensionConfiguration['condition']['pageContext'] = isSitewide
    ? {
        id: '*',
        type: '*',
      }
    : {
        id: isUnidentifiedPageContext(iframePageContext)
          ? '*'
          : iframePageContext.id,
        type: iframePageContext.type,
      }

  return {
    allMatches: true,
    id: '',
    pageContext,
    statements: [],
  }
}

export const getFormData: GetFormData = ({
  componentImplementation,
  content,
  contentSchema,
  iframeRuntime,
}) =>
  getSchemaPropsOrContentFromRuntime({
    component: componentImplementation,
    contentSchema,
    isContent: true,
    messages: iframeRuntime.messages,
    propsOrContent: content,
    runtime: iframeRuntime,
  }) || {}

export const getInitialEditingState: GetInitialEditingState = ({
  data,
  editor,
  iframeRuntime,
}) => {
  const treePath = editor.editTreePath || ''

  const extension = getExtension(treePath, iframeRuntime.extensions)

  const componentImplementation = getIframeImplementation(extension.component)

  const listContent = data && data.listContentWithSchema

  const contentSchema = listContent && JSON.parse(listContent.schemaJSON)

  const configurations = listContent && listContent.content

  const activeContentId = getActiveContentId({
    extensions: iframeRuntime.extensions,
    treePath: editor.editTreePath,
  })

  const activeContent =
    configurations &&
    configurations.find(
      configuration => configuration.contentId === activeContentId
    )

  const content =
    (activeContent &&
      activeContent.contentJSON &&
      JSON.parse(activeContent.contentJSON)) ||
    {}

  const condition = activeContent
    ? activeContent.condition
    : getDefaultCondition({
        iframeRuntime,
        isSitewide: editor.blockData.isSitewide,
      })

  const label = activeContent && activeContent.label

  const formData = getFormData({
    componentImplementation,
    content,
    contentSchema,
    iframeRuntime,
  })

  return {
    condition,
    contentId: activeContentId,
    content,
    formData,
    label,
    origin: (activeContent && activeContent.origin) || null,
  }
}

export const updateEditorBlockData: UpdateEditorBlockData = ({
  data,
  editor,
  id,
  iframeRuntime,
  intl,
  serverTreePath,
  template,
}) => {
  const treePath = editor.editTreePath || ''

  const extension = getExtension(treePath, iframeRuntime.extensions)

  const listContent = data && data.listContentWithSchema

  const componentImplementation = getIframeImplementation(extension.component)

  const contentSchema = listContent && JSON.parse(listContent.schemaJSON)

  const componentSchema = getComponentSchema({
    component: componentImplementation,
    contentSchema: contentSchema,
    isContent: true,
    propsOrContent: extension.content,
    runtime: iframeRuntime,
  })

  const title = formatIOMessage({ id: componentSchema.title || '', intl })

  const configurations = listContent && listContent.content

  const blockData = {
    componentImplementation,
    componentSchema,
    configurations,
    contentSchema,
    id,
    serverTreePath,
    template,
    title,
  }

  editor.setBlockData(blockData)
}

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { InjectedIntl } from 'react-intl'
import { ToastConsumerFunctions } from 'vtex.styleguide'

import { GetSchemaPropsOrContentFromRuntimeParams } from '../../../utils/components/typings'
import { ListContentData } from '../queries/ListContent'

export interface FormMetaContext {
  getWasModified: () => boolean
  setWasModified: (newValue: boolean, callback?: () => void) => void
}

export interface ModalContext {
  actionHandler?: () => void
  cancelHandler?: () => void
  close: () => void
  getIsOpen: () => boolean
  getTextButtonAction: () => string
  getTextButtonCancel: () => string
  getTextMessage: () => string
  getTitle: () => string
  isActionDanger: boolean
  open: (handlers?: {
    actionHandler?: ModalContext['actionHandler']
    cancelHandler?: ModalContext['cancelHandler']
    closeCallbackHandler?: () => void
    isActionDanger?: ModalContext['isActionDanger']
    textButtonAction?: ModalContext['textButtonAction']
    textButtonCancel?: ModalContext['textButtonCancel']
    textMessage?: ModalContext['textMessage']
    title?: ModalContext['title']
  }) => void
  textButtonAction: string
  textButtonCancel: string
  textMessage: string
  title: string
}

export interface SidebarComponent {
  name: string
  isEditable: boolean
  treePath: string
}

export interface ModifiedSidebarComponent extends SidebarComponent {
  modifiedTreePath: string
}

export interface EditingState
  extends Partial<Omit<ExtensionConfiguration, 'contentJSON'>> {
  content?: Extension['content']
  formData?: Extension['content']
}

// eslint-disable-next-line @typescript-eslint/prefer-interface
export type FormDataContainer = {
  formData: object
}

interface GetInitialEditingStateParams {
  data: ListContentData
  editor: EditorContextType
  iframeRuntime: RenderContext
}

export type GetInitialEditingState = (
  params: GetInitialEditingStateParams
) => EditingState

export type GetDefaultCondition = ({
  iframeRuntime,
  isSitewide,
}) => ExtensionConfiguration['condition']

interface GetFormDataParams {
  componentImplementation: GetSchemaPropsOrContentFromRuntimeParams['component']
  content: GetSchemaPropsOrContentFromRuntimeParams['propsOrContent']
  contentSchema: GetSchemaPropsOrContentFromRuntimeParams['contentSchema']
  iframeRuntime: GetSchemaPropsOrContentFromRuntimeParams['runtime']
}

export type GetFormData = (params: GetFormDataParams) => Extension['content']

export type UpdateEditorBlockData = (
  params: Pick<BlockData, 'id' | 'serverTreePath' | 'template'> & {
    data?: ListContentData
    editor: EditorContextType
    iframeRuntime: RenderContext
    intl: InjectedIntl
    isSitewide: boolean
  }
) => void

interface UseInitialEditingStateParams {
  client: ApolloClient
  iframeRuntime: RenderContext
  intl: InjectedIntl
  showToast: ToastConsumerFunctions['showToast']
}

export type UseInitialEditingState = (
  params: UseInitialEditingStateParams
) => EditingState | undefined

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/ModalContext.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component, createContext, useContext } from 'react'

import { ModalContext as ModalContextT } from './typings'

const defaultExternalState: ModalContextT = {
  close: () => {
    return
  },
  getIsOpen: () => false,
  getTextButtonAction: () => '',
  getTextButtonCancel: () => '',
  getTextMessage: () => '',
  getTitle: () => '',
  isActionDanger: false,
  open: () => {
    return
  },
  textButtonAction: '',
  textButtonCancel: '',
  textMessage: '',
  title: '',
}

const ModalContext = createContext(defaultExternalState)

export const useModalContext = () => useContext(ModalContext)

export const ModalConsumer = ModalContext.Consumer

interface State extends ModalContextT {
  closeCallbackHandler?: () => void
  isOpen: boolean
}

export class ModalProvider extends Component<{}, State> {
  public constructor(props: {}) {
    super(props)

    this.state = {
      close: this.close,
      getIsOpen: this.getIsOpen,
      getTextButtonAction: this.getTextButtonAction,
      getTextButtonCancel: this.getTextButtonCancel,
      getTextMessage: this.getTextMessage,
      getTitle: this.getTitle,
      isActionDanger: false,
      isOpen: false,
      open: this.open,
      textButtonAction: '',
      textButtonCancel: '',
      textMessage: '',
      title: '',
    }
  }

  public render() {
    return (
      <ModalContext.Provider value={this.state}>
        {this.props.children}
      </ModalContext.Provider>
    )
  }

  private close: State['close'] = () => {
    this.setState(
      {
        isOpen: false,
      },
      () => {
        if (this.state.closeCallbackHandler) {
          this.state.closeCallbackHandler()
        }

        this.setState({
          actionHandler: undefined,
          cancelHandler: undefined,
          closeCallbackHandler: undefined,
        })
      }
    )
  }

  private getIsOpen: State['getIsOpen'] = () => this.state.isOpen

  private getTextButtonAction: State['getTextButtonAction'] = () =>
    this.state.textButtonAction

  private getTextButtonCancel: State['getTextButtonCancel'] = () =>
    this.state.textButtonCancel

  private getTextMessage: State['getTextMessage'] = () => this.state.textMessage

  private getTitle: State['getTitle'] = () => this.state.title

  private open: State['open'] = params => {
    this.setState(prevState => ({
      ...prevState,
      ...params,
      isActionDanger: (params && params.isActionDanger) || false,
      isOpen: true,
      textButtonAction: (params && params.textButtonAction) || '',
      textButtonCancel: (params && params.textButtonCancel) || '',
      textMessage: (params && params.textMessage) || '',
      title: (params && params.title) || '',
    }))
  }
}

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/Sidebar/hooks.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useCallback, useEffect, useState } from 'react'

import { getSitewideTreePath } from '../../../utils/blocks'
import { useEditorContext } from '../../EditorContext'
import ListContent from '../graphql/ListContent.graphql'
import { ListContentData, ListContentVariables } from '../queries/ListContent'
import { EditingState, UseInitialEditingState } from './typings'
import {
  getInitialEditingState,
  getIsSitewide,
  updateEditorBlockData,
} from './utils'

const useInitialEditingState: UseInitialEditingState = ({
  client,
  iframeRuntime,
  intl,
  showToast,
}) => {
  const editor = useEditorContext()

  const treePath = editor.editTreePath || ''

  const isSitewide = getIsSitewide(iframeRuntime.extensions, treePath)

  const blockId =
    iframeRuntime.extensions[treePath] &&
    iframeRuntime.extensions[treePath].blockId

  const template =
    isSitewide || !iframeRuntime.page
      ? '*'
      : iframeRuntime.pages[iframeRuntime.page].blockId

  const serverTreePath = isSitewide ? getSitewideTreePath(treePath) : treePath

  const isEditing = editor.editTreePath !== null

  const [initialEditingState, setInitialEditingState] = useState<EditingState>()

  const fetchAndSetData = useCallback(async () => {
    try {
      const { data } = await client.query<
        ListContentData,
        ListContentVariables
      >({
        fetchPolicy: 'network-only',
        query: ListContent,
        variables: {
          bindingId: iframeRuntime.binding?.id,
          blockId,
          pageContext: iframeRuntime.route.pageContext,
          template,
          treePath: serverTreePath,
        },
      })

      setInitialEditingState(
        getInitialEditingState({
          data,
          editor,
          iframeRuntime,
        })
      )

      updateEditorBlockData({
        data,
        editor,
        id: blockId,
        iframeRuntime,
        intl,
        isSitewide,
        serverTreePath,
        template,
      })
    } catch (e) {
      showToast({
        horizontalPosition: 'right',
        message: intl.formatMessage({
          defaultMessage: 'Something went wrong. Please try again.',
          id: 'admin/pages.editor.components.open.error',
        }),
      })

      editor.editExtensionPoint(null)
    } finally {
      editor.setIsLoading(false)
    }
  }, [
    blockId,
    client,
    editor,
    iframeRuntime,
    intl,
    isSitewide,
    serverTreePath,
    showToast,
    template,
  ])

  useEffect(() => {
    if (isEditing && !initialEditingState) {
      fetchAndSetData()
    }
  }, [isEditing, fetchAndSetData, initialEditingState])

  useEffect(() => {
    if (!isEditing && initialEditingState) {
      setInitialEditingState(undefined)
    }
  }, [isEditing, initialEditingState])

  return initialEditingState
}

export default useInitialEditingState

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/mutations/DeleteContent.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { Mutation, MutationFn, MutationResult } from 'react-apollo'
import DeleteContent from '../graphql/DeleteContent.graphql'

export interface DeleteContentData {
  deleteContent: string
}

interface DeleteContentVariables {
  pageContext: PageContext
  contentId: string | null
  template: string
  treePath: string
}

export type DeleteContentMutationFn = MutationFn<
  DeleteContentData,
  DeleteContentVariables
>

export interface MutationRenderProps extends MutationResult<DeleteContentData> {
  deleteContent: DeleteContentMutationFn
}

class DeleteContentMutation extends Mutation<
  DeleteContentData,
  DeleteContentVariables
> {
  public static defaultProps = {
    mutation: DeleteContent,
  }
}

export default DeleteContentMutation

```


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

[User] Show me the implementation of admin-pages/react/components/EditorContainer/mutations/SendEventToAudit.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { Mutation, MutationFn, MutationResult } from 'react-apollo'

import SendEventToAudit from '../graphql/SendEventToAudit.graphql'

interface SendEventToAuditData {
  sendEventToAudit: any
}

interface MetaData {
  entityName: string
  entityBeforeAction: string
  entityAfterAction: string
  remoteIpAddress: string
  forwardFromVtexUserAgent: string
}

interface SendEventToAuditInput {
  id: string
  date: string
  mainAccountName: string
  accountName: string
  subjectId: string
  application: string
  workspace: string
  operation: string
  meta: MetaData
}

interface SendEventToAuditVariables {
  input: SendEventToAuditInput
}

export type SendEventToAuditMutationFn = MutationFn<
  SendEventToAuditData,
  SendEventToAuditVariables
>

export interface MutationRenderProps
  extends MutationResult<SendEventToAuditData> {
  sendEventToAudit: SendEventToAuditMutationFn
}

class SendEventToAuditMutation extends Mutation<
  SendEventToAuditData,
  SendEventToAuditVariables
> {
  public static defaultProps = {
    mutation: SendEventToAudit,
  }
}

export default SendEventToAuditMutation

```