[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/BlockEditor/BlockConfigurationList/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { MutationUpdaterFn } from 'react-apollo'
import { ToastConsumerFunctions } from 'vtex.styleguide'

import {
  DeleteContentData,
  DeleteContentMutationFn,
} from '../../../mutations/DeleteContent'
import { SendEventToAuditMutationFn } from '../../../mutations/SendEventToAudit'

interface GetDeleteStoreUpdaterParams
  extends Pick<BlockData, 'serverTreePath' | 'template'> {
  action: 'reset' | 'delete'
  blockId: EditorContextType['blockData']['id']
  iframeRuntime: RenderContext
  setBlockData: EditorContextType['setBlockData']
}

export type GetDeleteStoreUpdater = (
  params: GetDeleteStoreUpdaterParams
) => MutationUpdaterFn<DeleteContentData>

export interface UseListHandlersParams {
  activeContentId: ExtensionConfiguration['contentId']
  deleteContent: DeleteContentMutationFn
  sendEventToAudit: SendEventToAuditMutationFn
  iframeRuntime: RenderContext
  intl: ReactIntl.InjectedIntl
  showToast: ToastConsumerFunctions['showToast']
}

export type UseListHandlers = (
  params: UseListHandlersParams
) => {
  handleConfirmConfigurationDelete: (
    configuration: ExtensionConfiguration
  ) => void
  handleConfigurationDelete: (
    configuration: ExtensionConfiguration
  ) => Promise<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/EditorContainer/Sidebar/BlockEditor/BlockConfigurationList/hooks.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useCallback } from 'react'
import { defineMessages } from 'react-intl'
import { useRuntime } from 'vtex.render-runtime'

import { useEditorContext } from '../../../../EditorContext'
import { useModalContext } from '../../ModalContext'
import { getConfigurationType, getIsDefaultContent } from '../utils'
import { ConfigurationType } from '../typings'
import { UseListHandlers } from './typings'
import { getDeleteStoreUpdater } from './utils'
import { createEventObject } from '../../../../../utils/auditEvents'

const messages = defineMessages({
  cancel: {
    defaultMessage: 'Cancel',
    id: 'admin/pages.editor.components.modal.list.delete.button.cancel',
  },
  delete: {
    defaultMessage: 'Delete',
    id: 'admin/pages.editor.components.modal.list.delete.button.delete',
  },
  deleteActiveText: {
    defaultMessage:
      'You are trying to delete the active content. The next available content will take its place. Are you sure you want to continue? This action cannot be undone.',
    id: 'admin/pages.editor.components.modal.list.delete.active.text',
  },
  deleteActiveTitle: {
    defaultMessage: 'Delete active content',
    id: 'admin/pages.editor.components.modal.list.delete.active.title',
  },
  deleteError: {
    defaultMessage: 'Something went wrong. Please try again.',
    id: 'admin/pages.editor.components.toast.delete.error',
  },
  deleteInactiveText: {
    defaultMessage:
      'Are you sure you want to delete this content? This action cannot be undone.',
    id: 'admin/pages.editor.components.modal.list.delete.inactive.text',
  },
  deleteInactiveTitle: {
    defaultMessage: 'Delete content',
    id: 'admin/pages.editor.components.modal.list.delete.inactive.title',
  },
  reset: {
    defaultMessage: 'Reset',
    id: 'admin/pages.editor.components.modal.list.reset.button.reset',
  },
  deleteSuccess: {
    defaultMessage: 'Content deleted successfully.',
    id: 'admin/pages.editor.components.toast.delete.success',
  },
  resetError: {
    defaultMessage: 'Something went wrong. Please try again.',
    id: 'admin/pages.editor.components.toast.reset.error',
  },
  resetSuccess: {
    defaultMessage: 'Content reset successfully.',
    id: 'admin/pages.editor.components.toast.reset.success',
  },
  resetTitle: {
    defaultMessage: 'Reset content from an app',
    id: 'admin/pages.editor.components.modal.list.reset.title',
  },
  resetText: {
    defaultMessage:
      "You are trying to reset content created by an application. This action will discard any changes you've made. Are you sure you want to continue? This action cannot be undone.",
    id: 'admin/pages.editor.components.modal.list.reset.text',
  },
})

export const useListHandlers: UseListHandlers = ({
  activeContentId,
  deleteContent,
  sendEventToAudit,
  iframeRuntime,
  intl,
  showToast,
}) => {
  const editor = useEditorContext()

  const modal = useModalContext()
  const { account, workspace } = useRuntime()

  const handleConfigurationDelete = useCallback(
    async (configuration: ExtensionConfiguration) => {
      editor.setIsLoading(true)

      const action = getIsDefaultContent(configuration) ? 'reset' : 'delete'

      const {
        blockData: { id: blockId, serverTreePath, template },
        setBlockData,
      } = editor

      if (blockId && serverTreePath && template) {
        const { contentId } = configuration

        let wasSuccessful = true

        try {
          await deleteContent({
            update: getDeleteStoreUpdater({
              action,
              blockId,
              iframeRuntime,
              serverTreePath,
              setBlockData,
              template,
            }),
            variables: {
              contentId,
              pageContext: iframeRuntime.route.pageContext,
              template,
              treePath: serverTreePath,
            },
          })

          await iframeRuntime.updateRuntime()

          const event = createEventObject(
            action === 'reset'
              ? 'Reset content block version'
              : 'Delete content block version',
            'content',
            account,
            workspace,
            contentId
          )
          await sendEventToAudit({
            variables: { input: event },
          })

          editor.editExtensionPoint(null)
        } catch (error) {
          wasSuccessful = false

          console.error(error)
        } finally {
          const messageKey = action + (wasSuccessful ? 'Success' : 'Error')

          editor.setIsLoading(false)

          showToast({
            horizontalPosition: 'right',
            message: intl.formatMessage(
              messages[messageKey as keyof typeof messages]
            ),
          })
        }
      }
    },
    [deleteContent, editor, iframeRuntime, intl, showToast]
  )

  const handleConfirmConfigurationDelete = useCallback(
    (configuration: ExtensionConfiguration) => {
      const textMessageByType: Record<
        ConfigurationType,
        ReturnType<typeof defineMessages>
      > = {
        active: messages.deleteActiveText,
        inactive: messages.deleteInactiveText,
        app: messages.resetText,
      }

      const titleByType: Record<
        ConfigurationType,
        ReturnType<typeof defineMessages>
      > = {
        active: messages.deleteActiveTitle,
        inactive: messages.deleteInactiveTitle,
        app: messages.resetTitle,
      }

      const buttonMessageByType: Record<
        ConfigurationType,
        ReturnType<typeof defineMessages>
      > = {
        active: messages.delete,
        inactive: messages.delete,
        app: messages.reset,
      }

      const configurationType = getConfigurationType({
        configuration,
        activeContentId,
      })

      modal.open({
        isActionDanger: true,
        title: intl.formatMessage(titleByType[configurationType]),
        textButtonAction: intl.formatMessage(
          buttonMessageByType[configurationType]
        ),
        textButtonCancel: intl.formatMessage(messages.cancel),
        textMessage: intl.formatMessage(textMessageByType[configurationType]),
        actionHandler: async () => {
          await handleConfigurationDelete(configuration)
          modal.close()
        },
        cancelHandler: () => {
          modal.close()
        },
      })
    },
    [modal, handleConfigurationDelete, activeContentId, intl]
  )

  return {
    handleConfirmConfigurationDelete,
    handleConfigurationDelete,
  }
}

```


[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/BlockEditor/BlockConfigurationList/CreateButton.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 CreateButton = ({ onClick }: Props) => (
  <div className="mh5 ba b--muted-4 br2">
    <ButtonWithIcon
      block
      icon={<AddIcon />}
      onClick={onClick}
      variation="tertiary"
    >
      <FormattedMessage
        defaultMessage="New content"
        id="admin/pages.editor.configuration.button.create"
      />
    </ButtonWithIcon>
  </div>
)

export default React.memo(CreateButton)

```


[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/BlockEditor/BlockConfigurationEditor/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, { useMemo } from 'react'
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'
import { FormProps } from 'react-jsonschema-form'
// The styleguide is not exporting the warning icon
import {
  Button,
  ToastConsumerFunctions,
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
  // @ts-ignore
  IconWarning,
  Checkbox,
} from 'vtex.styleguide'

import { useEditorContext } from '../../../../EditorContext'
import EditableText from '../../../EditableText'
import { useFormMetaContext } from '../../FormMetaContext'
import { EditingState, FormDataContainer } from '../../typings'
import { isUnidentifiedPageContext } from '../../utils'
import EditorHeader from '../EditorHeader'
import { getIsDefaultContent } from '../utils'
import ConditionControls from './ConditionControls'
import Form from './Form'
import { useComponentFormStateStack } from './hooks'
import styles from './styles.css'
import { getSchemas } from './utils'

export enum ConfigurationStatus {
  ACTIVE = 'ACTIVE',
  INACTIVE = 'INACTIVE',
  SCHEDULED = 'SCHEDULED',
}

interface Props {
  state?: EditingState
  condition?: ExtensionConfiguration['condition']
  contentSchema?: JSONSchema6
  data: FormDataContainer
  editingContentId: EditingState['contentId']
  iframeRuntime: RenderContext
  isNew?: boolean
  isSitewide?: boolean
  label?: string | null
  onBack: () => void
  onChange: FormProps<FormDataContainer>['onChange']
  onStatusChange: () => void
  onConditionChange?: (
    changes: Partial<ExtensionConfiguration['condition']>
  ) => void
  onLabelChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
  onListClose?: () => void
  onListOpen?: () => void
  onSave: () => void
  showToast: ToastConsumerFunctions['showToast']
  title: ComponentSchema['title']
  statusFromRuntime: ConfigurationStatus
}

const messages = defineMessages({
  pageContextError: {
    defaultMessage:
      'Could not identify {entity}. The configuration will be set to "{template}".',
    id: 'admin/pages.editor.components.condition.toast.error.page-context',
  },
  activationLabel: {
    id: 'admin/pages.editor.components.condition.visibility.activation',
  },
  activationDisabledLabel: {
    id:
      'admin/pages.editor.components.condition.visibility.activation.disabled',
  },
  activationWarningLabel: {
    id: 'admin/pages.editor.components.condition.visibility.activation.warning',
  },
})

const BlockConfigurationEditor: React.FunctionComponent<Props> = ({
  state,
  condition,
  contentSchema,
  data,
  editingContentId,
  iframeRuntime,
  isNew,
  isSitewide = false,
  label,
  onBack,
  onChange,
  onStatusChange,
  onConditionChange,
  onLabelChange,
  onListOpen,
  onSave,
  showToast,
  title,
  statusFromRuntime,
}) => {
  const intl = useIntl()

  React.useEffect(() => {
    const { pageContext } = iframeRuntime.route

    if (isUnidentifiedPageContext(pageContext)) {
      showToast({
        horizontalPosition: 'right',
        message: intl.formatMessage(
          {
            id: messages.pageContextError.id,
          },
          {
            entity: intl.formatMessage({
              id: `admin/pages.editor.components.condition.scope.entity.${
                pageContext.type.startsWith('$') ? 'custom' : pageContext.type
              }`,
            }),
            template: intl.formatMessage({
              id: 'admin/pages.editor.components.condition.scope.template',
            }),
          }
        ),
      })
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const editor = useEditorContext()
  const formMeta = useFormMetaContext()
  const {
    currentDepth,
    componentFormState,
    popComponentFormState,
    pushComponentFormState,
  } = useComponentFormStateStack()

  const isContent = useMemo(() => editor.mode === 'content', [editor.mode])

  const { componentSchema, uiSchema } = useMemo(
    () =>
      getSchemas({
        contentSchema,
        editTreePath: editor.editTreePath,
        iframeRuntime,
        isContent,
      }),
    [contentSchema, editor.editTreePath, iframeRuntime, isContent]
  )

  const schema = useMemo(
    () => ({
      ...componentSchema,
      properties: {
        ...componentSchema.properties,
      },
      title: undefined,
    }),
    [componentSchema]
  )

  const isLoading = editor.getIsLoading()

  const shouldDisableSaveButton =
    isLoading || (!formMeta.getWasModified() && !isNew)

  const isArrayFieldOpen = Boolean(componentFormState)

  const isRootLevel = componentFormState === undefined

  const isDefaultContent = React.useMemo(() => {
    if (!editor.blockData || !editor.blockData.configurations) {
      return false
    }

    const defaultContent = editor.blockData.configurations.find(
      getIsDefaultContent
    )

    return defaultContent && defaultContent.contentId === editingContentId
  }, [editor.blockData, editingContentId])

  const status = state?.status ?? statusFromRuntime

  const hasOnlyEndDate = state?.condition?.statements?.some(
    statement => statement.verb === 'to'
  )

  const isSubcategoryPage = !!(
    iframeRuntime.route.pageContext?.id === 'search' &&
    iframeRuntime.route.pageContext?.type === 'subcategory'
  )

  const getStatusWarningText = () => {
    if (statusFromRuntime === ConfigurationStatus.ACTIVE) {
      return intl.formatMessage(messages.activationDisabledLabel)
    } else if (state?.status === ConfigurationStatus.ACTIVE) {
      return intl.formatMessage(messages.activationWarningLabel)
    }

    return
  }

  const statusWarningText = getStatusWarningText()

  return (
    <div className="w-100 h-100 absolute flex flex-column">
      <div
        className="flex-grow-1 overflow-y-auto overflow-x-hidden"
        id="component-editor-container"
      >
        <EditorHeader
          onBack={componentFormState ? componentFormState.onClose : onBack}
          onListOpen={onListOpen && isRootLevel ? onListOpen : undefined}
          title={componentFormState ? componentFormState.title : title}
        />

        <div className="ma4 mb5">
          {!isNew && statusFromRuntime !== ConfigurationStatus.ACTIVE && (
            <p className="pt4 pb4 pl4 pr2 bg-warning--faded lh-copy">
              <FormattedMessage
                id="admin/pages.editor.components.status.alert"
                defaultMessage="This version of the content is not being shown in the preview and to visitors."
              />
            </p>
          )}

          {isSubcategoryPage && (
            <p className="pt4 pb4 pl4 pr2 bg-warning--faded lh-copy">
              <FormattedMessage
                id="admin/pages.editor.components.editable.alert"
                defaultMessage="Editing this page will reflect on every subcategory page. If you want to have the content inherited from its parent(category) level, reset it."
              />
            </p>
          )}
        </div>

        <div
          className={classnames(
            'relative bg-white flex flex-column justify-between w-100 pb3 ph5',
            styles['size-editor'],
            styles['form'],
            { [styles['form--leave']]: isArrayFieldOpen }
          )}
        >
          <FormattedMessage
            defaultMessage="Untitled content"
            id="admin/pages.editor.configuration.defaultTitle"
          >
            {placeholder => (
              <EditableText
                baseClassName="lh-copy f5 fw5 near-black"
                onChange={onLabelChange}
                placeholder={placeholder as string}
                value={label || ''}
              />
            )}
          </FormattedMessage>

          <Form
            formContext={{
              currentDepth,
              componentFormState,
              popComponentFormState,
              pushComponentFormState,
            }}
            formData={data}
            onChange={onChange}
            onSubmit={onSave}
            schema={schema as JSONSchema6}
            uiSchema={uiSchema}
          />

          <div id="form__error-list-template___alert" />
        </div>

        {isContent && !isDefaultContent && !isArrayFieldOpen && (
          <>
            <FormattedMessage id="admin/pages.editor.components.condition.title">
              {message => (
                <div className="mb5 ph5 pt7 bt bw1 b--light-silver flex items-center f4">
                  {message}
                </div>
              )}
            </FormattedMessage>

            <div className="ph5 pt5 mb6">
              <>
                <Checkbox
                  checked={
                    status === ConfigurationStatus.ACTIVE || hasOnlyEndDate
                  }
                  id="status"
                  label={intl.formatMessage(messages.activationLabel)}
                  disabled={
                    statusFromRuntime === ConfigurationStatus.ACTIVE ||
                    condition?.statements.length
                  }
                  name="status"
                  onChange={onStatusChange}
                  value="status"
                />

                {statusWarningText && (
                  <div className="mt3 dib">
                    <span>{statusWarningText}</span>
                  </div>
                )}
              </>
            </div>
          </>
        )}

        {isContent &&
          !isDefaultContent &&
          condition &&
          onConditionChange &&
          !isArrayFieldOpen && (
            <ConditionControls
              condition={condition}
              isSitewide={isSitewide}
              onConditionChange={onConditionChange}
              pageContext={iframeRuntime.route.pageContext}
              status={status}
              statusFromRuntime={statusFromRuntime}
            />
          )}
      </div>

      <div
        className={classnames(
          'pr4 pv4 flex-row-reverse w-100 bt bw1 b--light-silver',
          {
            dn: isArrayFieldOpen,
            flex: !isArrayFieldOpen,
          }
        )}
      >
        <Button
          disabled={shouldDisableSaveButton}
          onClick={onSave}
          size="small"
          variation="primary"
        >
          <FormattedMessage
            defaultMessage="Save"
            id="admin/pages.editor.components.button.save"
          />
        </Button>

        <div className="mr5">
          <Button
            disabled={isLoading}
            onClick={onBack}
            size="small"
            variation="tertiary"
          >
            <FormattedMessage
              defaultMessage="Cancel"
              id="admin/pages.editor.components.button.cancel"
            />
          </Button>
        </div>
      </div>
    </div>
  )
}

export default BlockConfigurationEditor

```


[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/BlockEditor/BlockConfigurationEditor/utils.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

describe('getUiSchema', () => {
  const mockComponents = {
    'vtex.no-schema': {
      schema: {},
    },
    'vtex.schema-with-dependencies': {
      schema: {
        dependencies: {
          foo: {
            oneOf: [
              {
                properties: {
                  bar: { type: 'string', widget: { 'ui:widget': 'textarea' } },
                  foo: {
                    enum: ['0'],
                  },
                },
                required: ['bar'],
              },
              {
                properties: {
                  bar: {},
                  baz: { type: 'string', widget: { 'ui:widget': 'IOMessage' } },
                  foo: {
                    enum: ['1'],
                  },
                },
              },
            ],
          },
        },
        properties: {
          foo: {
            enum: ['0', '1'],
          },
        },
        required: ['foo'],
      },
    },
    'vtex.schema-with-nested-dependencies': {
      schema: {
        dependencies: {
          foo: {
            oneOf: [
              {
                dependencies: {
                  bar: {
                    oneOf: [
                      {
                        properties: {
                          baar: {
                            type: 'string',
                            widget: { 'ui:widget': 'textarea' },
                          },
                          bar: { enum: ['0'] },
                        },
                      },
                    ],
                  },
                },
                properties: {
                  bar: { enum: ['0'] },
                  foo: {
                    enum: ['0'],
                  },
                },
                required: ['bar'],
              },
              {
                properties: {
                  bar: {},
                  baz: { type: 'string', widget: { 'ui:widget': 'IOMessage' } },
                  foo: {
                    enum: ['1'],
                  },
                },
              },
            ],
          },
        },
        properties: {
          foo: {
            enum: ['0', '1'],
          },
        },
        required: ['foo'],
      },
    },
    'vtex.simple-schema': {
      schema: {
        properties: {
          foo: {
            properties: {
              bar: {
                widget: { 'ui:widget': 'textarea' },
              },
            },
            type: 'object',
          },
        },
      },
    },
  }

  it('should get ui schema for dependencies', () => {
    const uiSchema = {
      bar: { 'ui:widget': 'textarea' },
      baz: { 'ui:widget': 'IOMessage' },
    }
    const result = getUiSchema({}, mockComponents[
      'vtex.schema-with-dependencies'
    ].schema as ComponentSchema)
    expect(result).toEqual(uiSchema)
  })

  it('should get ui schema for nested dependencies', () => {
    const uiSchema = {
      baar: { 'ui:widget': 'textarea' },
      baz: { 'ui:widget': 'IOMessage' },
    }
    const result = getUiSchema({}, mockComponents[
      'vtex.schema-with-nested-dependencies'
    ].schema as ComponentSchema)
    expect(result).toEqual(uiSchema)
  })

  it('should deal with empty schemas', () => {
    const result = getUiSchema({}, mockComponents['vtex.no-schema']
      .schema as ComponentSchema)
    expect(result).toEqual({})
  })

  it('should get ui schema for simple schemas', () => {
    const uiSchema = { foo: { bar: { 'ui:widget': 'textarea' } } }
    const result = getUiSchema({}, mockComponents['vtex.simple-schema']
      .schema as ComponentSchema)
    expect(result).toEqual(uiSchema)
  })
})

```


[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/BlockEditor/BlockConfigurationEditor/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.form {
  transition: transform 250ms ease-in-out;
  transform: translateX(0rem);
}

.form--leave {
  transition: transform 250ms ease-in-out;
  transform: translateX(-18rem);
}

.form--leave > :global(.rjsf) {
  height: 0;
  overflow: hidden;
}

@media only screen and (max-width: 40em) {
  .size-editor {
    bottom: 0;
    height: 100%;
  }
}

@media only screen and (min-width: 40em) {
  .size-editor {
    max-width: 450px;
  }
}

```


[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/BlockEditor/BlockConfigurationEditor/utils.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { JSONSchema6 } from 'json-schema'
import traverse from 'json-schema-traverse'
import { assocPath, mergeDeepLeft } from 'ramda'
import { UiSchema, Widget } from 'react-jsonschema-form'

import {
  getComponentSchema,
  getExtension,
  getIframeImplementation,
} from '../../../../../utils/components'
import { GetSchemasArgs } from './typings'

/**
 * Generates an `UiSchema` following the `Component Schema` definition of `widgets`.
 * Each schema property can define an widget especifying how to display it.
 * @param {object} componentUiSchema The default static `UiSchema` definition
 * @param {object} componentSchema The full `Component Schema` (already
 *  applyed the `getSchema`, if its the case)
 * @return {object} A object defining the complete `UiSchema` that matches all the schema
 *  properties.
 */
export const getUiSchema = (
  componentUiSchema: UiSchema,
  componentSchema: ComponentSchema
): UiSchema => {
  /**
   * It goes deep into the schema tree to find widget definitions, generating
   * the correct path to the property.
   * e.g:
   * {
   *   banner1: {
   *     numberOfLines: {
   *       value: {
   *         'ui:widget': 'range'
   *       }
   *     }
   *   }
   * }
   *
   * @param {object} properties The schema properties to be analysed.
   */

  const arrayAttrs = /(anyOf|oneOf|allOf|dependencies)(\/\d+|\/\w+)?/g
  const noUISchemaProp = [
    'definitions',
    'properties',
    'patternProperties',
    'additionalProperties',
  ]
  let uiSchema = {}

  const getWidget = (
    schema: JSONSchema6 & { widget: Widget },
    JSONPointer: string
  ) => {
    if (schema.widget) {
      const widgetPath = JSONPointer.replace(arrayAttrs, '')
        .split('/')
        .filter(
          (pointer: string) => pointer && !noUISchemaProp.includes(pointer)
        )
      uiSchema = assocPath(widgetPath, schema.widget, uiSchema)
    }
  }

  traverse(componentSchema, getWidget)

  return mergeDeepLeft(uiSchema, componentUiSchema)
}

export const getSchemas = ({
  contentSchema,
  editTreePath,
  iframeRuntime,
  isContent,
}: GetSchemasArgs) => {
  const extension = getExtension(editTreePath, iframeRuntime.extensions)
  const componentImplementation = getIframeImplementation(extension.component)

  const componentSchema = getComponentSchema({
    component: componentImplementation,
    contentSchema,
    isContent: true,
    propsOrContent: extension[isContent ? 'content' : 'props'],
    runtime: iframeRuntime,
  })

  const componentUiSchema =
    componentImplementation && componentImplementation.uiSchema
      ? componentImplementation.uiSchema
      : {}

  const uiSchemaFromComponent = getUiSchema(componentUiSchema, componentSchema)

  return {
    componentSchema,
    uiSchema: uiSchemaFromComponent,
  }
}

```


[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/BlockEditor/BlockConfigurationEditor/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { JSONSchema6 } from 'json-schema'

export interface ComponentFormState {
  depth: number
  onClose: () => void
  onTitleChange?: () => void
  title: string
}

export interface GetSchemasArgs {
  contentSchema?: JSONSchema6
  editTreePath: string | null
  iframeRuntime: RenderContext
  isContent?: 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/EditorContainer/Sidebar/BlockEditor/BlockConfigurationEditor/hooks.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { useRef, useState } from 'react'

import { ComponentFormState } from './typings'

export function useComponentFormStateStack() {
  const [componentFormState, setComponentFormState] = useState<
    ComponentFormState | undefined
  >()
  const stack = useRef<ComponentFormState[]>([])

  function popComponentFormState() {
    stack.current.pop()

    setComponentFormState(stack.current[stack.current.length - 1])
  }

  function pushComponentFormState(state: ComponentFormState) {
    const stateWithDepth = { ...state, depth: stack.current.length + 1 }

    stack.current.push(stateWithDepth)
    setComponentFormState(stateWithDepth)
  }

  return {
    currentDepth: stack.current.length,
    componentFormState,
    popComponentFormState,
    pushComponentFormState,
  }
}

```


[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/BlockEditor/BlockConfigurationEditor/Form.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { equals } from 'ramda'
import React from 'react'
import JsonSchemaForm, { FormProps, Widget } from 'react-jsonschema-form'

import ArrayFieldTemplate from '../../../../form/ArrayFieldTemplate'
import BaseInput from '../../../../form/BaseInput'
import Dropdown from '../../../../form/Dropdown'
import ErrorListTemplate from '../../../../form/ErrorListTemplate'
import FieldTemplate from '../../../../form/FieldTemplate'
import I18nInput from '../../../../form/I18nInput'
import ObjectFieldTemplate from '../../../../form/ObjectFieldTemplate'
import Radio from '../../../../form/Radio'
import RichText from '../../../../form/RichText'
import TextArea from '../../../../form/TextArea'
import Toggle from '../../../../form/Toggle'
import MediaGalleryWidget from '../../../../MediaGalleryWidget'
import { FormDataContainer } from '../../typings'

export const widgets: Record<string, Widget> = {
  BaseInput,
  CheckboxWidget: Toggle,
  IOMessage: I18nInput,
  RadioWidget: Radio,
  RichText,
  SelectWidget: Dropdown as Widget,
  TextareaWidget: TextArea,
  'image-uploader': (MediaGalleryWidget as unknown) as Widget,
}

type Props = FormProps<FormDataContainer>
export default class Form extends React.Component<Props> {
  public shouldComponentUpdate(nextProps: Props) {
    return (
      !equals(this.props.formContext, nextProps.formContext) ||
      !equals(this.props.formData, nextProps.formData)
    )
  }

  public render() {
    return (
      <JsonSchemaForm
        schema={this.props.schema}
        formData={this.props.formData}
        onChange={this.props.onChange}
        onSubmit={this.props.onSubmit}
        FieldTemplate={FieldTemplate}
        ArrayFieldTemplate={ArrayFieldTemplate}
        ObjectFieldTemplate={ObjectFieldTemplate}
        uiSchema={this.props.uiSchema}
        widgets={widgets}
        showErrorList
        ErrorList={ErrorListTemplate}
        formContext={this.props.formContext}
      >
        <button className="dn" type="submit" />
      </JsonSchemaForm>
    )
  }
}

```


[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/BlockEditor/BlockConfigurationList/Card/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useKeydownFromClick } from 'keydown-from-click'
import React from 'react'
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'
import { Tag } from 'vtex.styleguide'

import ActionMenu from '../../../../../ActionMenu'
import { useEditorContext } from '../../../../../EditorContext'
import EarthIcon from '../../../../../icons/EarthIcon'
import TemplateIcon from '../../../../../icons/TemplateIcon'
import { isConfigurationExpired, isConfigurationScheduled } from '../utils'
import ConditionTags from './ConditionTags'
import StatusLabel from './StatusLabel'
import { getGenericContext } from './utils'
import styles from './styles.css'

interface Props {
  configuration: ExtensionConfiguration
  isActive: boolean
  isDefaultContent?: boolean
  isDisabled?: boolean
  isEditing: boolean
  onConfigurationOpen: (configuration: ExtensionConfiguration) => void
  onDelete: (configuration: ExtensionConfiguration) => void
  onConfigurationActivate: (
    configuration: ExtensionConfiguration
  ) => Promise<void>
}

function stopPropagation(e: Pick<Event, 'preventDefault' | 'stopPropagation'>) {
  e.preventDefault()
  e.stopPropagation()
}

const messages = defineMessages({
  defaultTitle: {
    defaultMessage: 'Untitled content',
    id: 'admin/pages.editor.configuration.defaultTitle',
  },
  delete: {
    defaultMessage: 'Delete',
    id: 'admin/pages.editor.component-list.action-menu.delete',
  },
  activate: {
    defaultMessage: 'Activate',
    id: 'admin/pages.editor.component-list.action-menu.activate',
  },
  reset: {
    defaultMessage: 'Reset',
    id: 'admin/pages.editor.component-list.action-menu.reset',
  },
  sitewideContext: {
    defaultMessage: 'entire site',
    id: 'admin/pages.editor.configuration.scope.sitewide.context',
  },
  sitewideSaved: {
    defaultMessage: 'Saved on',
    id: 'admin/pages.editor.configuration.scope.sitewide.saved',
  },
  tag: {
    defaultMessage: 'Editing',
    id: 'admin/pages.editor.configuration.tag.editing',
  },
  templateContext: {
    defaultMessage: 'template',
    id: 'admin/pages.editor.configuration.scope.template.context',
  },
  templateSaved: {
    defaultMessage: 'Saved in',
    id: 'admin/pages.editor.configuration.scope.template.saved',
  },
  tooltip: {
    defaultMessage: 'This card is currently being edited.',
    id: 'admin/pages.editor.component-list.action-menu.tooltip',
  },
})

const Card = ({
  configuration,
  isActive = false,
  isDefaultContent = false,
  isDisabled = false,
  isEditing = false,
  onConfigurationOpen,
  onDelete,
  onConfigurationActivate,
}: Props) => {
  const intl = useIntl()
  const editor = useEditorContext()

  const handleMainClick = React.useCallback(() => {
    onConfigurationOpen(configuration)
  }, [configuration, onConfigurationOpen])

  const handleMainKeyDown = useKeydownFromClick(handleMainClick)

  const stopPropagationByKeyDown = useKeydownFromClick(stopPropagation)

  const appName = React.useMemo(() => {
    if (!isDefaultContent) {
      return null
    }

    const splitOrigin = configuration.origin && configuration.origin.split('@')

    return splitOrigin && splitOrigin[0]
  }, [configuration.origin, isDefaultContent])

  const conditionPageContext = configuration.condition.pageContext

  const conditions = configuration.condition.statements

  const scope = React.useMemo(
    () =>
      getGenericContext({
        context: conditionPageContext,
        isSitewide: editor.blockData.isSitewide || false,
      }),
    [conditionPageContext, editor.blockData.isSitewide]
  )

  const iconByScope: Record<
    'sitewide' | 'template',
    JSX.Element
  > = React.useMemo(
    () => ({
      sitewide: <EarthIcon />,
      template: <TemplateIcon />,
    }),
    []
  )

  const status = React.useMemo(() => {
    if (isActive) {
      return 'active'
    }

    if (
      isConfigurationScheduled(configuration) &&
      !isConfigurationExpired(configuration)
    ) {
      return 'scheduled'
    }

    return 'inactive'
  }, [configuration, isActive])

  const menuOptions = React.useMemo(
    () => [
      {
        label: intl.formatMessage(messages.activate),
        onClick: async () => {
          await onConfigurationActivate(configuration)
        },
        disabled: isActive,
      },
      {
        isDangerous: true,
        label: intl.formatMessage(
          isDefaultContent ? messages.reset : messages.delete
        ),
        onClick: () => onDelete(configuration),
      },
    ],
    [
      configuration,
      intl,
      isActive,
      isDefaultContent,
      onConfigurationActivate,
      onDelete,
    ]
  )

  return (
    <div
      className={`relative mh5 mv5 pa5 br3 bg-action-secondary hover-bg-action-secondary outline-0 ${
        !isDisabled ? 'pointer' : ''
      }`}
      onClick={handleMainClick}
      onKeyDown={handleMainKeyDown}
      role="button"
      tabIndex={0}
    >
      <StatusLabel type={status} />

      <div className="c-on-base">
        {configuration.label ||
          intl.formatMessage({
            id: 'admin/pages.editor.configuration.defaultTitle',
          })}
      </div>

      {conditions.length > 0 && <ConditionTags conditions={conditions} />}

      {scope !== 'page' && (
        <div className="mt5">
          <FormattedMessage
            id={`admin/pages.editor.configuration.scope.${scope}.saved`}
          >
            {message => (
              <div className="flex items-center">
                {iconByScope[scope]}

                <span className="ml2 f6">
                  {message}{' '}
                  <FormattedMessage
                    id={`admin/pages.editor.configuration.scope.${scope}.context`}
                  >
                    {message => <span className="fw5">{message}</span>}
                  </FormattedMessage>
                </span>
              </div>
            )}
          </FormattedMessage>
        </div>
      )}

      {appName && (
        <div className="mt5">
          <FormattedMessage
            defaultMessage="Created by {name}"
            id="admin/pages.editor.configuration.createdBy"
            values={{ name: appName }}
          >
            {message => <div className="mt3 f7 c-muted-2">{message}</div>}
          </FormattedMessage>
        </div>
      )}

      <div
        className="absolute top-0 right-0 mt1"
        id="action-menu-parent"
        onClick={stopPropagation}
        onKeyDown={stopPropagationByKeyDown}
        role="button"
        tabIndex={0}
      >
        <ActionMenu options={menuOptions} />
      </div>

      {isEditing && (
        <div
          className={
            'absolute bottom-1 right-1 ' +
            styles['editor-configuration-card-tag-editing']
          }
        >
          <Tag size="small">{intl.formatMessage(messages.tag)}</Tag>
        </div>
      )}
    </div>
  )
}

export default Card

```


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

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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages, useIntl } from 'react-intl'

import ContentActiveIcon from '../../../../../icons/ContentActiveIcon'
import ContentInactiveIcon from '../../../../../icons/ContentInactiveIcon'
import ContentScheduledIcon from '../../../../../icons/ContentScheduledIcon'

interface Props {
  type: 'active' | 'inactive' | 'scheduled'
}

const messages = defineMessages({
  active: {
    defaultMessage: 'Active',
    id: 'admin/pages.editor.component-list.status.active',
  },
  inactive: {
    defaultMessage: 'Inactive',
    id: 'admin/pages.editor.component-list.status.inactive',
  },
  scheduled: {
    defaultMessage: 'Scheduled',
    id: 'admin/pages.editor.component-list.status.scheduled',
  },
})

const ICON_BY_STATUS = {
  active: <ContentActiveIcon />,
  inactive: <ContentInactiveIcon />,
  scheduled: <ContentScheduledIcon />,
}

const StatusLabel: React.FC<Props> = ({ type }) => {
  const intl = useIntl()

  return (
    <div className="flex items-center mb3">
      {ICON_BY_STATUS[type]}
      <div className="ml2 ttu f7 fw7">{intl.formatMessage(messages[type])}</div>
    </div>
  )
}

export default StatusLabel

```


[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/BlockEditor/BlockConfigurationList/Card/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
/* This is a temporary hack to remove the hover background from the
ActionMenu */
#action-menu-parent > div > div > div > button:active,
#action-menu-parent > div > div > div > button:hover {
  background-color: transparent !important;
}

.editor-configuration-card-tag-editing > div {
  background: rgba(0, 0, 0, 0.5);
}

```


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

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

[Assistant]
Here's the implementation:

```typescript
import { GetGenericContextArgs } from './typings'

export const getGenericContext = ({
  context,
  isSitewide,
}: GetGenericContextArgs) => {
  if (isSitewide) {
    return 'sitewide'
  }

  if (context.id === '*') {
    return 'template'
  }

  return 'page'
}

```


[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/BlockEditor/BlockConfigurationList/Card/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface GetGenericContextArgs {
  context: PageContext
  isSitewide: 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/EditorContainer/Sidebar/BlockEditor/BlockConfigurationList/Card/ConditionTags/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { defineMessages, useIntl } from 'react-intl'

import Tag from './Tag'

const messages = defineMessages({
  from: {
    defaultMessage: 'Start:',
    id: 'admin/pages.editor.configuration.condition.date.from',
  },
  to: {
    defaultMessage: 'End:',
    id: 'admin/pages.editor.configuration.condition.date.to',
  },
})

interface Props {
  conditions: ExtensionConfiguration['condition']['statements']
}

const ConditionTags: React.FC<Props> = ({ conditions }) => {
  const intl = useIntl()

  const format = React.useCallback(
    ({ kind, value }: { kind: ConditionSubject; value: string }) => {
      const textByKind: Record<ConditionSubject, string> = {
        date: `${intl.formatDate(value, {
          day: '2-digit',
          month: '2-digit',
          year: '2-digit',
        })} ${intl.formatTime(value)}`,
        // TODO
        utm: '',
      }

      return textByKind[kind]
    },
    [intl]
  )

  return (
    <div className="mt5">
      {conditions.map(item => {
        const parsedConditionObj: Record<string, string> = JSON.parse(
          item.objectJSON
        )

        if (!parsedConditionObj) {
          return null
        }

        return Object.entries(parsedConditionObj).reduce<JSX.Element[]>(
          (acc, [key, value]) => {
            const tagTitle = messages[key as keyof typeof messages]

            if (!tagTitle) {
              return acc
            }

            return [
              ...acc,
              <div className="mt3" key={key}>
                <Tag
                  kind={item.subject}
                  text={format({ kind: item.subject, value })}
                  title={intl.formatMessage({
                    id: tagTitle.id,
                  })}
                />
              </div>,
            ]
          },
          []
        )
      })}
    </div>
  )
}

export default ConditionTags

```


[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/BlockEditor/BlockConfigurationList/Card/ConditionTags/Tag.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Tag as StyleguideTag } from 'vtex.styleguide'

import CalendarIcon from '../../../../../../icons/CalendarIcon'
import PersonIcon from '../../../../../../icons/PersonIcon'

interface Props {
  kind: ConditionSubject
  text: string
  title: string
}

const iconByKind = {
  date: <CalendarIcon />,
  utm: <PersonIcon />,
}

const Tag: React.FunctionComponent<Props> = ({ kind, text, title }) => (
  <StyleguideTag bgColor="#FFFFFF" color="#727273">
    <div className="flex items-center">
      {iconByKind[kind]}

      <span className="mh2 fw5">{title}</span>

      <span className="fw4">{text}</span>
    </div>
  </StyleguideTag>
)

export default React.memo(Tag)

```


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

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

[Assistant]
Here's the implementation:

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

import { ConfigurationStatus } from '../..'
import { formatStatements } from '../../../../../../utils/conditions'
import { isUnidentifiedPageContext } from '../../../utils'
import Scheduler from './Scheduler'
import ScopeSelector from './ScopeSelector'
import Separator from './Separator'
import Typings from './typings'

interface Props {
  condition: ExtensionConfiguration['condition']
  isSitewide: boolean
  onConditionChange: (
    changes: Partial<ExtensionConfiguration['condition']>
  ) => void
  pageContext: RenderRuntime['route']['pageContext']
  statusFromRuntime: ConfigurationStatus
  status: ConfigurationStatus
}

class ConditionControls extends PureComponent<Props> {
  private isScopeDisabled =
    this.props.isSitewide || isUnidentifiedPageContext(this.props.pageContext)

  public render() {
    const { condition, isSitewide, pageContext, status } = this.props

    const scope = isSitewide
      ? 'sitewide'
      : condition.pageContext.id === '*'
      ? 'template'
      : 'entity'

    return (
      <div className="ph5">
        <Scheduler
          status={status}
          onConditionUpdate={this.handleDateChange}
          initialValues={this.getDatesInitialValues()}
        />

        <div className="mv7">
          <ScopeSelector
            isDisabled={this.isScopeDisabled}
            isSitewide={isSitewide}
            onChange={this.handleScopeChange}
            pageContext={pageContext}
            scope={scope}
          />

          <Separator />
        </div>
      </div>
    )
  }

  private getDatesInitialValues = () => {
    const { condition } = this.props

    const statement = condition.statements[0]

    const object = statement && JSON.parse(statement.objectJSON)

    const initialValues = object && {
      from: object.from && new Date(object.from),
      to: object.to && new Date(object.to),
    }

    return initialValues
  }

  private getPageContextFromScope(scope: ConfigurationScope): PageContext {
    const { pageContext } = this.props

    if (['sitewide', 'template'].includes(scope)) {
      return { id: '*', type: '*' }
    }

    return pageContext
  }

  private handleDateChange = (dates: Typings.DateRange) => {
    const object =
      dates.from || dates.to
        ? {
            ...(dates.from && dates.to
              ? dates
              : { date: dates.from || dates.to }),
          }
        : null

    const verb = object
      ? (dates.from && dates.to && 'between') || (dates.from && 'from') || 'to'
      : null

    const statements =
      object && verb
        ? formatStatements([
            {
              error: null,
              object,
              subject: 'date',
              verb,
            },
          ])
        : []

    this.props.onConditionChange({
      statements,
    })
  }

  private handleScopeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { condition, onConditionChange } = this.props

    const newPageContext = this.getPageContextFromScope(
      event.target.value as ConfigurationScope
    )

    if (
      newPageContext.id !== condition.pageContext.id ||
      newPageContext.type !== condition.pageContext.type
    ) {
      onConditionChange({
        pageContext: newPageContext,
      })
    }
  }
}

export default ConditionControls

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/typings.d.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
export interface DateRange {
  from?: Date
  to?: Date
}

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/Scheduler.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component } from 'react'
import { defineMessages, InjectedIntlProps, injectIntl } from 'react-intl'
import { withRuntimeContext } from 'vtex.render-runtime'
import { Checkbox, DatePicker } from 'vtex.styleguide'

import { ConfigurationStatus } from '../..'
import {
  getFirstTime,
  getLastTime,
  getNextDay,
  getNextTime,
  getPreviousTime,
  isLastTime,
  isSameDay,
} from '../../../../../../utils/date'
import Typings from './typings'

interface CustomProps {
  initialValues?: Typings.DateRange
  onConditionUpdate: (dates: Typings.DateRange) => void
  status: ConfigurationStatus
}

type Props = CustomProps & InjectedIntlProps & RenderContextProps

interface State extends Typings.DateRange {
  fromMinTime: Date
  shouldDisplayFrom: boolean
  shouldDisplayTo: boolean
  toMinTime: Date
}

const messages = defineMessages({
  dateTitle: {
    defaultMessage: 'Custom date',
    id: 'admin/pages.editor.components.condition.date.title',
  },
  toggleEnd: {
    defaultMessage: 'Set an end date',
    id: 'admin/pages.editor.components.condition.date.toggle.end',
  },
  toggleStart: {
    defaultMessage: 'Set a start date',
    id: 'admin/pages.editor.components.condition.date.toggle.start',
  },
})

class Scheduler extends Component<Props, State> {
  private currDate: Date
  private defaultMaxTime: Date
  private defaultMinTime: Date
  private minDate: Date

  private initialState: State

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

    this.currDate = new Date()

    this.defaultMaxTime = getLastTime(this.currDate)
    this.defaultMinTime = getFirstTime(this.currDate)

    const initialTimeLimit = this.currDate

    this.minDate = isLastTime(initialTimeLimit)
      ? getNextDay(this.currDate)
      : this.currDate

    const fromMinTime = getNextTime(initialTimeLimit)
    const toMinTime = getNextTime(fromMinTime)

    const from = props.initialValues && props.initialValues.from
    const to = props.initialValues && props.initialValues.to

    this.initialState = {
      from,
      fromMinTime,
      shouldDisplayFrom: !!from,
      shouldDisplayTo: !!to,
      to,
      toMinTime,
    }

    this.state = this.initialState
  }

  public render() {
    const { intl, runtime: iframeRuntime, status } = this.props

    return (
      <>
        <Checkbox
          checked={this.state.shouldDisplayFrom}
          disabled={status === ConfigurationStatus.ACTIVE}
          label={intl.formatMessage(messages.toggleStart)}
          onChange={this.handleFromVisibilityToggle}
        />

        {this.state.shouldDisplayFrom && (
          <div className="flex mt4">
            <DatePicker
              align="right"
              dateRangeStart={this.state.from}
              dateRangeEnd={this.state.to}
              direction="up"
              isRangeStart
              locale={iframeRuntime.culture.locale}
              maxTime={this.defaultMaxTime}
              minDate={this.minDate}
              minTime={this.state.fromMinTime}
              onChange={this.handleFromChange}
              positionFixed
              useTime
              value={this.state.from}
            />
          </div>
        )}

        <div className="mt6" />

        <Checkbox
          checked={this.state.shouldDisplayTo}
          label={intl.formatMessage(messages.toggleEnd)}
          onChange={this.handleToVisibilityToggle}
        />

        {this.state.shouldDisplayTo && (
          <div className="flex mt4">
            <DatePicker
              align="right"
              dateRangeStart={this.state.from}
              dateRangeEnd={this.state.to}
              direction="up"
              isRangeEnd
              locale={iframeRuntime.culture.locale}
              maxTime={this.defaultMaxTime}
              minDate={this.minDate}
              minTime={this.state.toMinTime}
              onChange={this.handleToChange}
              positionFixed
              useTime
              value={this.state.to}
            />
          </div>
        )}
      </>
    )
  }

  private getConditionUpdater = (dates: Typings.DateRange) => () => {
    this.props.onConditionUpdate({
      from: dates.from || this.state.from,
      to: dates.to || this.state.to,
    })
  }

  private handleFromChange = (from: Date) => {
    if (from < this.initialState.fromMinTime) {
      from.setTime(this.initialState.fromMinTime.getTime())
    }

    const to =
      this.state.to && from > this.state.to ? getNextTime(from) : this.state.to

    this.setState(
      {
        from,
        fromMinTime: isSameDay(from, this.currDate)
          ? this.initialState.fromMinTime
          : this.defaultMinTime,
        to,
      },
      this.getConditionUpdater({ from, to })
    )
  }

  private handleToChange = (to: Date) => {
    const isToToday = isSameDay(to, this.currDate)

    if (to < this.initialState.toMinTime) {
      to.setTime(this.initialState.toMinTime.getTime())
    }

    const from =
      this.state.from && to < this.state.from
        ? getPreviousTime(to)
        : this.state.from

    this.setState(
      {
        from,
        fromMinTime: isSameDay(from, this.currDate)
          ? this.initialState.fromMinTime
          : this.defaultMinTime,
        to,
        toMinTime: isToToday
          ? this.initialState.toMinTime
          : this.defaultMinTime,
      },
      this.getConditionUpdater({ from, to })
    )
  }

  private handleFromVisibilityToggle = () => {
    if (this.state.from) {
      const from = undefined

      this.setState(
        {
          from,
          shouldDisplayFrom: false,
        },
        this.getConditionUpdater({ from })
      )
    } else {
      this.handleFromChange(this.initialState.fromMinTime)

      this.setState({ shouldDisplayFrom: true })
    }
  }

  private handleToVisibilityToggle = () => {
    if (this.state.to) {
      const to = undefined

      this.setState(
        {
          shouldDisplayTo: false,
          to,
        },
        this.getConditionUpdater({ to })
      )
    } else {
      const initialValue = this.state.from
        ? getNextTime(this.state.from)
        : this.initialState.toMinTime

      this.handleToChange(initialValue)

      this.setState({ shouldDisplayTo: true })
    }
  }
}

export default injectIntl(withRuntimeContext(Scheduler))

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/Separator.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

const Separator: React.FunctionComponent = () => <div className="mv7" />

export default Separator

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/ConditionTitle.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

interface Props {
  labelId: string
}

const ConditionTitle: React.FunctionComponent<Props> = ({ labelId }) => (
  <FormattedMessage id={labelId}>
    {message => <div className="mb6">{message}</div>}
  </FormattedMessage>
)

export default React.memo(ConditionTitle)

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/ScopeSelector/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Fragment, useMemo } from 'react'
import { FormattedMessage, InjectedIntlProps, injectIntl } from 'react-intl'
import { RadioGroup } from 'vtex.styleguide'

import { getScopeStandardOptions } from './utils'

interface CustomProps {
  isDisabled: boolean
  isSitewide: boolean
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
  pageContext: PageContext
  scope: ConfigurationScope
}

type Props = CustomProps & InjectedIntlProps

const ScopeSelector: React.FunctionComponent<Props> = ({
  intl,
  isDisabled,
  isSitewide,
  onChange,
  pageContext,
  scope,
}) => {
  const standardOptions = getScopeStandardOptions(intl, pageContext)
  const options = useMemo(
    () =>
      isSitewide
        ? [
            {
              label: intl.formatMessage({
                id: 'admin/pages.editor.components.condition.scope.sitewide',
              }),
              value: 'sitewide',
            },
          ]
        : standardOptions,
    [intl, isSitewide, standardOptions]
  )

  return (
    <Fragment>
      <FormattedMessage id="admin/pages.editor.components.condition.scope.title">
        {message => <div className="mb5">{message}</div>}
      </FormattedMessage>
      <RadioGroup
        hideBorder
        disabled={isDisabled}
        name="scopes"
        onChange={onChange}
        options={options}
        value={scope}
      />
    </Fragment>
  )
}

export default React.memo(injectIntl(ScopeSelector))

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/ScopeSelector/ScopeSelector.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Fragment } from 'react'
import { InjectedIntlProps, injectIntl } from 'react-intl'
import { RadioGroup } from 'vtex.styleguide'

import ConditionTitle from '../ConditionTitle'
import { getScopeStandardOptions } from './utils'

interface CustomProps {
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
  pageContext: PageContext
  scope: ConfigurationScope
  isSitewide: boolean
}

type Props = CustomProps & InjectedIntlProps

const ScopeSelector: React.FunctionComponent<Props> = ({
  intl,
  isSitewide,
  onChange,
  pageContext,
  scope,
}) => {
  const standardOptions = getScopeStandardOptions(intl, pageContext)

  return (
    <Fragment>
      <ConditionTitle labelId="admin/pages.editor.components.condition.scope.title" />

      <RadioGroup
        disabled={isSitewide}
        name="scopes"
        onChange={onChange}
        options={
          isSitewide
            ? [
                {
                  label: intl.formatMessage({
                    id:
                      'admin/pages.editor.components.condition.scope.sitewide',
                  }),
                  value: 'sitewide',
                },
              ]
            : standardOptions
        }
        value={scope}
        hideBorder
      />
    </Fragment>
  )
}

export default injectIntl(ScopeSelector)

```


[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/BlockEditor/BlockConfigurationEditor/ConditionControls/ScopeSelector/utils.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

// Messages used in getScopeStandardOptions
defineMessages({
  brand: {
    defaultMessage: 'this brand',
    id: 'admin/pages.editor.components.condition.scope.entity.brand',
  },
  category: {
    defaultMessage: 'this category',
    id: 'admin/pages.editor.components.condition.scope.entity.category',
  },
  department: {
    defaultMessage: 'this department',
    id: 'admin/pages.editor.components.condition.scope.entity.department',
  },
  product: {
    defaultMessage: 'this product',
    id: 'admin/pages.editor.components.condition.scope.entity.product',
  },
  route: {
    defaultMessage: 'this URL',
    id: 'admin/pages.editor.components.condition.scope.entity.route',
  },
  search: {
    defaultMessage: 'this search',
    id: 'admin/pages.editor.components.condition.scope.entity.search',
  },
  sitewide: {
    defaultMessage: 'the entire site',
    id: 'admin/pages.editor.components.condition.scope.sitewide',
  },
  subcategory: {
    defaultMessage: 'this subcategory',
    id: 'admin/pages.editor.components.condition.scope.entity.subcategory',
  },
  template: {
    defaultMessage: 'this template',
    id: 'admin/pages.editor.components.condition.scope.template',
  },
  title: {
    defaultMessage: 'Apply to',
    id: 'admin/pages.editor.components.condition.scope.title',
  },
})

export const getScopeStandardOptions = (
  intl: IntlShape,
  pageContext: PageContext
) => [
  {
    label: intl.formatMessage({
      id: `admin/pages.editor.components.condition.scope.entity.${
        pageContext.type.startsWith('$') ? 'custom' : pageContext.type
      }`,
    }),
    value: 'entity',
  },
  {
    label: intl.formatMessage({
      id: 'admin/pages.editor.components.condition.scope.template',
    }),
    value: 'template',
  },
]

```


[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/Transitions/Enter/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { CSSTransition } from 'react-transition-group'

import { COMMON_PROPS } from '../consts'
import { EnterProps } from '../typings'
import styles from './styles.css'

const Enter: React.FC<EnterProps> = ({ children, condition, from }) => (
  <CSSTransition
    {...COMMON_PROPS}
    appear
    classNames={{
      appear: styles[`transition-editor-enter-${from}`],
      appearActive: styles[`transition-editor-enter-${from}-active`],
      enter: styles[`transition-editor-enter-${from}`],
      enterActive: styles[`transition-editor-enter-${from}-active`],
    }}
    in={condition}
    mountOnEnter
  >
    {children}
  </CSSTransition>
)

export default React.memo(Enter)

```


[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/Transitions/Enter/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

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

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

.transition-editor-enter-right-active {
  transition: transform 250ms ease-in;
  transform: translateX(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/EditorContainer/Sidebar/Transitions/Exit/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { CSSTransition } from 'react-transition-group'

import { COMMON_PROPS } from '../consts'
import { ExitProps } from '../typings'
import styles from './styles.css'

const Exit: React.FC<ExitProps> = ({ children, condition, to }) => (
  <CSSTransition
    {...COMMON_PROPS}
    classNames={{
      exit: styles[`transition-editor-exit-${to}`],
      exitActive: styles[`transition-editor-exit-${to}-active`],
      exitDone: styles[`transition-editor-exit-${to}-done`],
    }}
    in={!condition}
    unmountOnExit
  >
    {children}
  </CSSTransition>
)

export default React.memo(Exit)

```


[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/Transitions/Exit/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

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

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

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

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

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

```


[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/BlockSelector/__fixtures__/components.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

const COMPONENTS: ComponentsRegistry = {
  'vtex.carousel@2.10.2/Carousel': {
    getSchema: () => ({
      description: 'admin/editor.carousel.description',
      dependencies: {
        autoplay: {
          oneOf: [
            {
              properties: {
                autoplay: {
                  enum: [true],
                },
                autoplaySpeed: {
                  enum: ['2', '3', '4', '5', '6', '7', '8'],
                  isLayout: false,
                  title: 'admin/editor.carousel.autoplaySpeed.title',
                  type: 'string',
                },
              },
            },
          ],
        },
      },
      properties: {
        banners: {
          items: {
            properties: {
              description: {
                default: '',
                title: 'admin/editor.carousel.banner.description.title',
                type: 'string',
              },
              externalRoute: {
                default: false,
                isLayout: false,
                title: 'admin/editor.carousel.banner.externalRoute.title',
                type: 'boolean',
              },
              url: {
                isLayout: false,
                title: 'admin/editor.carousel.bannerLink.url.title',
                type: 'string',
              },
              page: {
                enum: [
                  'store.lists',
                  'store.custom#about-us',
                  'store.home',
                  'store.account',
                  'store.login',
                  'store.product',
                  'store.search',
                  'store.search#brand',
                  'store.search#department',
                  'store.search#category',
                  'store.search#subcategory',
                  'store.search#subcategory-terms',
                  'store.search#custom',
                  'store.search#configurable',
                  'store.orderplaced',
                  'vtex.store@2.x:store.custom#foo',
                  'vtex.store@2.x:store.custom#renato',
                ],
                isLayout: false,
                title: 'admin/editor.carousel.bannerLink.page.title',
                type: 'string',
              },
              params: {
                description:
                  'admin/editor.carousel.bannerLink.params.description',
                isLayout: false,
                title: 'admin/editor.carousel.bannerLink.params.title',
                type: 'string',
              },
              image: {
                default: '',
                title: 'admin/editor.carousel.banner.image.title',
                type: 'string',
                widget: {
                  'ui:widget': 'image-uploader',
                },
              },
              mobileImage: {
                default: '',
                title: 'admin/editor.carousel.banner.mobileImage.title',
                type: 'string',
                widget: {
                  'ui:widget': 'image-uploader',
                },
              },
            },
            title: 'admin/editor.carousel.banner.title',
            type: 'object',
          },
          minItems: 1,
          title: 'admin/editor.carousel.banners.title',
          type: 'array',
        },
        height: {
          default: 420,
          enum: [420, 440],
          isLayout: true,
          title: 'admin/editor.carousel.height.title',
          type: 'number',
        },
        showArrows: {
          default: true,
          isLayout: true,
          title: 'admin/editor.carousel.showArrows.title',
          type: 'boolean',
        },
        showDots: {
          default: true,
          isLayout: true,
          title: 'admin/editor.carousel.showDots.title',
          type: 'boolean',
        },
        autoplay: {
          default: true,
          isLayout: false,
          title: 'admin/editor.carousel.autoplay.title',
          type: 'boolean',
        },
      },
      title: 'admin/editor.carousel.title',
      type: 'object',
    }),
  },
  'vtex.product-summary@2.31.0/ProductSummaryCustom': {
    getSchema: () => ({
      title: 'admin/editor.productSummary.title',
      description: 'admin/editor.productSummary.description',
    }),
  },
  'vtex.shelf@1.25.0/Shelf': {
    getSchema: () => ({
      title: 'admin/editor.shelf.title',
      description: 'admin/editor.shelf.description',
      type: 'object',
      properties: {
        category: {
          title: 'admin/editor.shelf.category.title',
          description: 'admin/editor.shelf.category.description',
          type: 'string',
          isLayout: false,
        },
        specificationFilters: {
          title: 'admin/editor.shelf.specificationFilters.title',
          type: 'array',
          items: {
            title: 'admin/editor.shelf.specificationFilters.item.title',
            type: 'object',
            properties: {
              id: {
                type: 'string',
                title: 'admin/editor.shelf.specificationFilters.item.id.title',
              },
              value: {
                type: 'string',
                title:
                  'admin/editor.shelf.specificationFilters.item.value.title',
              },
            },
          },
        },
        collection: {
          title: 'admin/editor.shelf.collection.title',
          type: 'number',
          isLayout: false,
        },
        orderBy: {
          title: 'admin/editor.shelf.orderBy.title',
          type: 'string',
          enum: [
            '',
            'OrderByTopSaleDESC',
            'OrderByPriceDESC',
            'OrderByPriceASC',
            'OrderByNameASC',
            'OrderByNameDESC',
            'OrderByReleaseDateDESC',
            'OrderByBestDiscountDESC',
          ],
          enumNames: [
            'admin/editor.shelf.orderType.relevance',
            'admin/editor.shelf.orderType.sales',
            'admin/editor.shelf.orderType.priceDesc',
            'admin/editor.shelf.orderType.priceAsc',
            'admin/editor.shelf.orderType.nameAsc',
            'admin/editor.shelf.orderType.nameDesc',
            'admin/editor.shelf.orderType.releaseDate',
            'admin/editor.shelf.orderType.discount',
          ],
          default: '',
          isLayout: false,
        },
        productList: {
          title: 'admin/editor.shelf.title',
          description: 'admin/editor.shelf.description',
          type: 'object',
          properties: {
            maxItems: {
              title: 'admin/editor.shelf.maxItems.title',
              type: 'number',
              default: 10,
              isLayout: true,
            },
            gap: {
              title: 'admin/editor.shelf.gap.title',
              type: 'string',
              enum: ['ph0', 'ph3', 'ph5', 'ph7'],
              enumNames: [
                'admin/editor.shelf.gapType.none',
                'admin/editor.shelf.gapType.small',
                'admin/editor.shelf.gapType.medium',
                'admin/editor.shelf.gapType.large',
              ],
              default: 'ph3',
              isLayout: true,
            },
            itemsPerPage: {
              title: 'admin/editor.shelf.itemsPerPage.title',
              type: 'number',
              enum: [3, 4, 5],
              default: 5,
              isLayout: true,
            },
            scroll: {
              title: 'admin/editor.shelf.scrollType.title',
              type: 'string',
              enum: ['BY_PAGE', 'ONE_BY_ONE'],
              enumNames: [
                'admin/editor.shelf.scrollType.byPage',
                'admin/editor.shelf.scrollType.oneByOne',
              ],
              default: 'BY_PAGE',
              isLayout: true,
            },
            arrows: {
              title: 'admin/editor.shelf.arrows.title',
              type: 'boolean',
              default: true,
              isLayout: true,
            },
            showTitle: {
              title: 'admin/editor.shelf.titleText.showTitle',
              type: 'boolean',
              default: true,
              isLayout: true,
            },
          },
        },
        hideUnavailableItems: {
          title: 'admin/editor.shelf.hideUnavailableItems',
          type: 'boolean',
          default: false,
          isLayout: false,
        },
      },
    }),
  },
}

export default COMPONENTS

```


[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/BlockSelector/BlockList/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

import { useEditorContext } from '../../../../EditorContext'
import { NormalizedBlock } from '../typings'
import BlockListItem from './BlockListItem'

interface Props {
  blocks: NormalizedBlock[]
  highlightHandler: (treePath: string | null) => void
  iframeRuntime: RenderContextProps['runtime']
  onMouseEnterBlock: (
    event: React.MouseEvent<HTMLDivElement | HTMLLIElement>
  ) => void
  onMouseLeaveBlock: () => void
}

const BlockList: React.FC<Props> = ({
  blocks,
  highlightHandler,
  onMouseEnterBlock,
  onMouseLeaveBlock,
}) => {
  const editor = useEditorContext()

  const handleEdit = React.useCallback(
    (block: NormalizedBlock) => {
      if (block.isEditable) {
        editor.editExtensionPoint(block.treePath)

        editor.setIsLoading(true)

        highlightHandler(null)
      }
    },
    [editor, highlightHandler]
  )

  return (
    <ul className="mv0 pl0 overflow-y-auto">
      {blocks.map((block, index) => (
        <BlockListItem
          block={block}
          key={`${block.treePath}-${index}`}
          onEdit={handleEdit}
          onMouseEnter={onMouseEnterBlock}
          onMouseLeave={onMouseLeaveBlock}
        />
      ))}
    </ul>
  )
}

export default BlockList

```


[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/BlockSelector/BlockList/BlockListItem/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

import { NormalizedBlock } from '../../typings'
import ExpandArrow from './ExpandArrow'
import Item from './Item'

interface Props {
  block: NormalizedBlock
  onEdit: (block: NormalizedBlock) => void
  onMouseEnter: (
    event: React.MouseEvent<HTMLDivElement | HTMLLIElement>
  ) => void
  onMouseLeave: () => void
}

const BlockListItem: React.FC<Props> = ({
  block,
  onEdit,
  onMouseEnter,
  onMouseLeave,
}) => {
  const [isExpanded, setIsExpanded] = React.useState(false)

  const handleClick = React.useCallback(() => {
    onEdit(block)
  }, [block, onEdit])

  const handleExpansionToggle = React.useCallback(() => {
    setIsExpanded(!isExpanded)
  }, [isExpanded])

  const subitems = block.components || []
  const hasSubitems = subitems.length > 0

  return (
    <>
      <div
        className="flex items-center bb bg-white b--light-silver"
        data-tree-path={block.treePath}
        onMouseEnter={onMouseEnter}
        onMouseLeave={onMouseLeave}
      >
        {hasSubitems && (
          <ExpandArrow
            isExpanded={isExpanded}
            onClick={handleExpansionToggle}
          />
        )}

        <Item
          hasSubitems={hasSubitems}
          isEditable={block.isEditable}
          onEdit={handleClick}
          onMouseEnter={onMouseEnter}
          onMouseLeave={onMouseLeave}
          title={block.name}
          treePath={block.treePath}
        />
      </div>
      {isExpanded && subitems && (
        <div className="mv0 pl0">
          {subitems.map((item, index) => (
            <div
              className="flex bg-white hover-bg-light-silver list"
              data-tree-path={item.treePath}
              key={item.treePath}
              onMouseEnter={onMouseEnter}
              onMouseLeave={onMouseLeave}
            >
              <div className="bl bw2 b--light-blue" />

              <div
                className={`w-100 ${
                  index !== subitems.length - 1 ? 'bb b--light-silver ' : ''
                }`}
              >
                <BlockListItem
                  block={item}
                  onEdit={onEdit}
                  onMouseEnter={onMouseEnter}
                  onMouseLeave={onMouseLeave}
                />
              </div>
            </div>
          ))}

          <div className="bb b--light-silver" />
        </div>
      )}
    </>
  )
}

export default BlockListItem

```


[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/BlockSelector/BlockList/BlockListItem/Item.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import classnames from 'classnames'
import { useKeydownFromClick } from 'keydown-from-click'
import React from 'react'
import { defineMessages, useIntl } from 'react-intl'
import { formatIOMessage } from 'vtex.native-types'

import styles from './Item.css'

interface Props {
  hasSubitems?: boolean
  isEditable: boolean
  onEdit: () => void
  onMouseEnter: (event: React.MouseEvent<HTMLDivElement>) => void
  onMouseLeave: (event: React.MouseEvent<HTMLDivElement>) => void
  title: string
  treePath: string
}

const messages = defineMessages({
  untitledBlock: {
    defaultMessage: 'Untitled Block',
    id: 'admin/pages.editor.component-list.untitled',
  },
})

const Item: React.FunctionComponent<Props> = ({
  hasSubitems,
  isEditable,
  onEdit,
  onMouseEnter,
  onMouseLeave,
  title,
  treePath,
}) => {
  const intl = useIntl()
  const handleKeyDown = useKeydownFromClick(onEdit)

  const leftPaddingClassName = hasSubitems ? 'pl2' : 'pl8'

  return (
    <div
      className={classnames(
        'w-100 pv5 pr0 dark-gray bg-inherit tl outline-0',
        leftPaddingClassName,
        {
          'hover-bg-light-silver': isEditable,
        }
      )}
      data-tree-path={treePath}
      key={treePath}
      onClick={onEdit}
      onKeyDown={handleKeyDown}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
      role="treeitem"
      style={{
        ...{ animationDuration: '0.2s' },
        ...(!hasSubitems ? { marginLeft: 1 } : null),
        ...{ cursor: isEditable ? 'pointer' : 'default' },
      }}
      tabIndex={0}
    >
      <span className={`f6 fw4 ${styles['track-1']} pl2`}>
        {typeof title === 'string' ? (
          formatIOMessage({ id: title, intl })
        ) : (
          <i>{intl.formatMessage(messages.untitledBlock)}</i>
        )}
      </span>
    </div>
  )
}

export default Item

```


[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/BlockSelector/BlockList/BlockListItem/ExpandArrow/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import classnames from 'classnames'
import { useKeydownFromClick } from 'keydown-from-click'
import React from 'react'

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

interface Props {
  isExpanded: boolean
  onClick: () => void
}

const ExpandArrow: React.FC<Props> = ({ isExpanded, onClick }) => {
  const handleKeyDown = useKeydownFromClick(onClick)

  return (
    <div
      className="flex items-center ph3 pv5 bg-inherit c-muted-3 hover-bg-light-silver hover-black-90 outline-0 pointer"
      onClick={onClick}
      onKeyDown={handleKeyDown}
      role="button"
      tabIndex={0}
    >
      <div className="flex items-center ph4 color-inherit">
        <div
          className={classnames('color-inherit', styles.transition, {
            'rotate-90': isExpanded,
          })}
        >
          <ArrowIcon />
        </div>
      </div>
    </div>
  )
}

export default ExpandArrow

```


[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/BlockSelector/BlockList/BlockListItem/ExpandArrow/styles.css from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```css
.transition {
  transition-property: transform, color;
  transition-duration: 200ms;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 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/EditorContainer/Styles/StyleList/index.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { find, zip } from 'ramda'
import React, { useState } from 'react'
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'
import { ButtonWithIcon, Spinner, ToastConsumer } from 'vtex.styleguide'
import { useRuntime } from 'vtex.render-runtime'

import Operations from './Operations'
import CreateNewIcon from './icons/CreateNewIcon'
import StyleCard from './StyleCard'
import { createEventObject } from '../../../../utils/auditEvents'
import SendEventToAuditMutation from '../../mutations/SendEventToAudit'

interface Props {
  startEditing: (style: Style) => void
  setStyleAsset: (asset: StyleAssetInfo) => void
}

const compareStyles = (a: Style, b: Style) => {
  const toArray = ({ selected, editable, app, name, id }: Style) => {
    return [selected ? 0 : 1, editable ? 0 : 1, app, name, id]
  }
  return zip(toArray(a), toArray(b)).reduce((acc, [value1, value2]) => {
    if (acc !== 0) {
      return acc
    }
    if (value1 < value2) {
      return -1
    }
    if (value1 > value2) {
      return 1
    }
    return acc
  }, 0)
}

const messages = defineMessages({
  defaultName: {
    defaultMessage: 'Untitled',
    id: 'admin/pages.editor.styles.new.defaultName',
  },
  deleteFail: {
    defaultMessage: 'Failed to delete style.',
    id: 'admin/pages.editor.styles.card.menu.delete.fail',
  },
  deleteSuccess: {
    defaultMessage: `Style '{name}' was deleted.`,
    id: 'admin/pages.editor.styles.select.delete-success',
  },
  duplicateDefaultName: {
    defaultMessage: 'Copy of {name}',
    id: 'admin/pages.editor.styles.duplicate.defaultName',
  },
  duplicateFail: {
    defaultMessage: `Failed to duplicate style '{name}'.`,
    id: 'admin/pages.editor.styles.card.menu.duplicate.fail',
  },
  duplicateSuccess: {
    defaultMessage: `Style '{name}' was duplicated.`,
    id: 'admin/pages.editor.styles.card.menu.duplicate.success',
  },
  newFail: {
    defaultMessage: 'Failed to create new style.',
    id: 'admin/pages.editor.styles.new.fail',
  },
  newSuccess: {
    defaultMessage: 'New style created.',
    id: 'admin/pages.editor.styles.new.success',
  },
  saveFail: {
    defaultMessage: `Failed to select style '{name}'.`,
    id: 'admin/pages.editor.styles.select.save-fail',
  },
  saveSuccess: {
    defaultMessage: `Style '{name}' was selected.`,
    id: 'admin/pages.editor.styles.select.save-success',
  },
  undo: {
    defaultMessage: 'Undo',
    id: 'admin/pages.editor.styles.select.delete.toast.undo',
  },
})

const StyleList: React.FunctionComponent<Props> = ({
  startEditing,
  setStyleAsset,
}) => {
  const intl = useIntl()
  const [isCreatingStyle, setIsCreatingStyle] = useState(false)
  const { account, workspace } = useRuntime()

  return (
    <Operations>
      {({
        listStyles: { data, loading },
        saveSelectedStyle,
        createStyle,
        deleteStyle,
      }) => {
        const unsortedStyles = data && data.listStyles
        const listStyles = unsortedStyles && unsortedStyles.sort(compareStyles)

        const selected = listStyles && find(style => style.selected, listStyles)
        if (selected && !loading) {
          setStyleAsset({ type: 'path', selected: true, value: selected.path })
        }

        return loading ? (
          <div className="pt7 flex justify-around">
            <Spinner />
          </div>
        ) : (
          <SendEventToAuditMutation>
            {sendEventToAudit => (
              <ToastConsumer>
                {({ showToast }) => (
                  <section className="flex flex-column ph3 h-100 overflow-x-hidden">
                    <header className="flex justify-between pv5 pl5 items-center flex-shrink-0 bg-white z-1">
                      <h1 className="f3 fw4">
                        <FormattedMessage
                          id="admin/pages.editor.styles.header.title"
                          defaultMessage="Styles"
                        />
                      </h1>
                      <ButtonWithIcon
                        icon={<CreateNewIcon />}
                        variation="tertiary"
                        isLoading={isCreatingStyle}
                        onClick={() => {
                          setIsCreatingStyle(true)
                          createStyle({
                            variables: {
                              name: intl.formatMessage(messages.defaultName),
                            },
                          })
                            .then(() => {
                              showToast({
                                horizontalPosition: 'left',
                                message: intl.formatMessage(
                                  messages.newSuccess
                                ),
                              })
                              const event = createEventObject(
                                'Create new style',
                                'style',
                                account,
                                workspace
                              )
                              sendEventToAudit({
                                variables: { input: event },
                              })
                            })
                            .catch(e => {
                              console.error(e)
                              showToast({
                                horizontalPosition: 'left',
                                message: intl.formatMessage(messages.newFail),
                              })
                            })
                            .finally(() => setIsCreatingStyle(false))
                        }}
                      >
                        <FormattedMessage
                          id="admin/pages.editor.styles.new-button.text"
                          defaultMessage="new"
                        />
                      </ButtonWithIcon>
                    </header>
                    <div className="flex flex-column flex-grow-1 overflow-y-auto">
                      {listStyles &&
                        listStyles.map(style => (
                          <StyleCard
                            key={style.id}
                            style={style}
                            selectStyle={({ id, name }: Style) =>
                              saveSelectedStyle({ variables: { id } })
                                .then(async () => {
                                  showToast({
                                    horizontalPosition: 'left',
                                    message: intl.formatMessage(
                                      messages.saveSuccess,
                                      { name }
                                    ),
                                  })
                                  const event = createEventObject(
                                    'Select main style',
                                    'style',
                                    account,
                                    workspace,
                                    id
                                  )
                                  await sendEventToAudit({
                                    variables: { input: event },
                                  })
                                })
                                .catch(e => {
                                  console.error(e)
                                  showToast({
                                    horizontalPosition: 'left',
                                    message: intl.formatMessage(
                                      messages.saveFail,
                                      {
                                        name,
                                      }
                                    ),
                                  })
                                })
                            }
                            deleteStyle={({ config, name, id }: Style) =>
                              deleteStyle({ variables: { id } })
                                .then(async () => {
                                  showToast({
                                    action: {
                                      label: intl.formatMessage(messages.undo),
                                      onClick: () => {
                                        createStyle({
                                          variables: { name, config },
                                        })
                                      },
                                    },
                                    duration: Infinity,
                                    horizontalPosition: 'left',
                                    message: intl.formatMessage(
                                      messages.deleteSuccess,
                                      { name }
                                    ),
                                  })
                                  const event = createEventObject(
                                    'Delete style',
                                    'style',
                                    account,
                                    workspace,
                                    id
                                  )
                                  await sendEventToAudit({
                                    variables: { input: event },
                                  })
                                })
                                .catch(e => {
                                  console.error(e)
                                  showToast({
                                    horizontalPosition: 'left',
                                    message: intl.formatMessage(
                                      messages.deleteFail
                                    ),
                                  })
                                  throw e
                                })
                            }
                            duplicateStyle={({ name, config }: Style) =>
                              createStyle({
                                variables: {
                                  config,
                                  name: intl.formatMessage(
                                    messages.duplicateDefaultName,
                                    { name }
                                  ),
                                },
                              })
                                .then(async () => {
                                  showToast({
                                    horizontalPosition: 'left',
                                    message: intl.formatMessage(
                                      messages.duplicateSuccess,
                                      { name }
                                    ),
                                  })
                                  const event = createEventObject(
                                    'Create new style',
                                    'style',
                                    account,
                                    workspace
                                  )
                                  await sendEventToAudit({
                                    variables: { input: event },
                                  })
                                })
                                .catch(e => {
                                  console.error(e)
                                  showToast({
                                    horizontalPosition: 'left',
                                    message: intl.formatMessage(
                                      messages.duplicateFail,
                                      { name }
                                    ),
                                  })
                                })
                            }
                            startEditing={startEditing}
                          />
                        ))}
                    </div>
                  </section>
                )}
              </ToastConsumer>
            )}
          </SendEventToAuditMutation>
        )
      }}
    </Operations>
  )
}

export default StyleList

```