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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Mutation, MutationFn, Query, QueryResult } from 'react-apollo'

import AvailableTemplates from '../../../../queries/AvailableTemplates.graphql'
import DeleteRoute from '../../../../queries/DeleteRoute.graphql'
import SaveRoute from '../../../../queries/SaveRoute.graphql'
import {
  DeleteMutationResult,
  DeleteRouteVariables,
  SaveMutationResult,
  SaveRouteVariables,
  TemplateMutationResult,
} from './typings'
import { updateStoreAfterDelete, updateStoreAfterSave } from './utils'

interface TemplateVariables {
  interfaceId: string
}

interface Props {
  interfaceId: string
  binding?: string
  children: (mutations: OperationsResults) => React.ReactNode
}

export interface OperationsResults {
  deleteRoute: MutationFn<DeleteMutationResult['data'], DeleteRouteVariables>
  saveRoute: MutationFn<SaveMutationResult['data'], SaveRouteVariables>
  templatesResults: QueryResult<
    TemplateMutationResult['data'],
    TemplateVariables
  >
}

const Operations = ({ interfaceId, children, binding }: Props) => (
  <Query<TemplateMutationResult['data'], TemplateVariables>
    query={AvailableTemplates}
    variables={{ interfaceId }}
  >
    {templatesResults => (
      <Mutation<DeleteMutationResult['data'], DeleteRouteVariables>
        mutation={DeleteRoute}
        update={updateStoreAfterDelete(binding)}
      >
        {deleteRoute => (
          <Mutation<SaveMutationResult['data'], SaveRouteVariables>
            mutation={SaveRoute}
            update={updateStoreAfterSave}
          >
            {saveRoute =>
              children({
                deleteRoute,
                saveRoute,
                templatesResults,
              })
            }
          </Mutation>
        )}
      </Mutation>
    )}
  </Query>
)

export default Operations

```


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

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import {
  defineMessages,
  FormattedMessage,
  WrappedComponentProps as ComponentWithIntlProps,
} from 'react-intl'
import { Dropdown } from 'vtex.styleguide'
import { PagesFormData, RouteFormData } from 'pages'

import {
  ConditionalTemplatePicker,
  ConditionalTemplatePickerProps,
} from './ConditionalTemplatePicker'
import SectionTitle from './SectionTitle'
import { FormErrors } from './typings'

type TemplatePickerCallbacks = Pick<
  ConditionalTemplatePickerProps,
  | 'onChangeOperatorConditionalTemplate'
  | 'onChangeStatementsConditionalTemplate'
  | 'onChangeTemplateConditionalTemplate'
  | 'onRemoveConditionalTemplate'
>

export interface ConditionalTemplateSectionProps
  extends TemplatePickerCallbacks {
  detailChangeHandlerGetter: (
    detailName: keyof RouteFormData
  ) => (
    event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => void
  formErrors: FormErrors
  onAddConditionalTemplate: () => void
  pages: PagesFormData[]
  blockId: string
  templates: Template[]
}

type Props = ConditionalTemplateSectionProps & ComponentWithIntlProps

const messages = defineMessages({
  defaultFieldLabel: {
    defaultMessage: 'Default',
    id: 'admin/pages.admin.pages.form.templates.field.default',
  },
  templateTitle: {
    defaultMessage: 'Templates',
    id: 'admin/pages.admin.pages.form.templates.title',
  },
})

export const ConditionalTemplateSection: React.FunctionComponent<Props> = ({
  detailChangeHandlerGetter,
  formErrors,
  intl,
  onAddConditionalTemplate,
  onChangeOperatorConditionalTemplate,
  onChangeStatementsConditionalTemplate,
  onChangeTemplateConditionalTemplate,
  onRemoveConditionalTemplate,
  pages,
  blockId,
  templates,
}) => (
  <React.Fragment>
    <SectionTitle textId="admin/pages.admin.pages.form.templates.title" />
    <Dropdown
      label={intl.formatMessage(messages.defaultFieldLabel)}
      options={templates.map(({ id }) => ({ value: id, label: id }))}
      onChange={detailChangeHandlerGetter('blockId')}
      value={blockId}
      errorMessage={
        formErrors.blockId && intl.formatMessage({ id: formErrors.blockId })
      }
    />
    <h2 className="mt7 f5 normal">
      <FormattedMessage
        id="admin/pages.admin.pages.form.templates.conditional.title"
        defaultMessage="Conditional"
      />
    </h2>
    <p className="f6 c-muted-2">
      <FormattedMessage
        id="admin/pages.admin.pages.form.templates.conditional.description"
        defaultMessage="Conditional template enables the use of a variant layout to your page. This layout will appear when it matches with the conditions set."
      />
    </p>
    {pages.map(page => (
      <ConditionalTemplatePicker
        key={page.uniqueId}
        condition={page.condition}
        intl={intl}
        onChangeTemplateConditionalTemplate={
          onChangeTemplateConditionalTemplate
        }
        onChangeOperatorConditionalTemplate={
          onChangeOperatorConditionalTemplate
        }
        onChangeStatementsConditionalTemplate={
          onChangeStatementsConditionalTemplate
        }
        operator={page.operator}
        onRemoveConditionalTemplate={onRemoveConditionalTemplate}
        pageId={page.uniqueId}
        template={page.template}
        templates={templates}
        formErrors={formErrors}
      />
    ))}
    <button
      type="button"
      className="bg-transparent bn mt4 pl0 pointer"
      onClick={onAddConditionalTemplate}
    >
      <span className="c-action-primary f4 mr2 v-mid">+</span>
      <span className="f6 v-mid">
        <FormattedMessage
          id="admin/pages.admin.pages.form.templates.conditional.addButton"
          defaultMessage="Add conditional template"
        />
      </span>
    </button>
  </React.Fragment>
)

export default ConditionalTemplateSection

```


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

[Assistant]
Here's the implementation:

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

interface Props {
  textId: string
}

const SectionTitle: React.FunctionComponent<Props> = ({ textId }) => (
  <FormattedMessage id={textId}>
    {text => <h2 className="mv7 f5 normal">{text}</h2>}
  </FormattedMessage>
)

export default SectionTitle

```


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

[Assistant]
Here's the implementation:

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

export const messages = defineMessages({
  addCondition: {
    defaultMessage: 'Add new condition',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.add-button',
  },
  dateEquals: {
    defaultMessage: 'is',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.date.equals',
  },
  dateFrom: {
    defaultMessage: 'starts on',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.date.from',
  },
  dateLabel: {
    defaultMessage: 'Date',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.date',
  },
  dateRange: {
    defaultMessage: 'is between',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.date.range',
  },
  dateTo: {
    defaultMessage: 'ends on',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.date.to',
  },
  delete: {
    defaultMessage: 'Delete',
    id: 'admin/pages.admin.pages.form.button.delete',
  },
  headerPrefix: {
    defaultMessage: 'Matching',
    id:
      'admin/pages.admin.pages.form.templates.simple.conditions.header-prefix',
  },
  headerSuffix: {
    defaultMessage: 'following conditions',
    id:
      'admin/pages.admin.pages.form.templates.simple.conditions.header-suffix',
  },
  noConditions: {
    defaultMessage: 'No conditions selected',
    id:
      'admin/pages.admin.pages.form.templates.simple.conditions.no-conditions',
  },
  operatorAll: {
    defaultMessage: 'all',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.operator-all',
  },
  operatorAnd: {
    defaultMessage: 'and',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.operator-and',
  },
  operatorAny: {
    defaultMessage: 'any',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.operator-any',
  },
  operatorOr: {
    defaultMessage: 'or',
    id: 'admin/pages.admin.pages.form.templates.simple.conditions.operator-or',
  },
  subjectPlaceholder: {
    defaultMessage: 'Select condition type',
    id:
      'admin/pages.admin.pages.form.templates.simple.conditions.category-placeholder',
  },
  emptyConditionsOptions: {
    defaultMessage: 'No options',
    id:
      'admin/pages.admin.pages.form.templates.simple.conditions.empty-conditions-options',
  },
})

```


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

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo } from 'react'
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'
import {
  Button,
  Checkbox,
  Dropdown,
  EXPERIMENTAL_Select as Select,
  Input,
  Textarea,
} from 'vtex.styleguide'
import { Binding } from 'vtex.tenant-graphql'
import { KeywordsFormData, RouteFormData } from 'pages'

import FormFieldSeparator from '../../FormFieldSeparator'
import SeparatorWithLine from '../SeparatorWithLine'
import SectionTitle from './SectionTitle'
import { FormErrors } from './typings'
import {
  ConditionalTemplateSection,
  ConditionalTemplateSectionProps,
} from './ConditionalTemplateSection'
import { isNewRoute } from '../utils'
import { DropdownChangeInput } from '../../../../utils/bindings/typings'
import { getBindingSelectorOptions } from '../../../../utils/bindings'

type TemplateSectionProps = Omit<
  ConditionalTemplateSectionProps,
  'pages' | 'blockId'
>
interface Props extends TemplateSectionProps {
  data: RouteFormData
  detailChangeHandlerGetter: (
    detailName: keyof RouteFormData
  ) => (
    event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => void
  formErrors: FormErrors
  isCustomPage: boolean
  isDeletable: boolean
  isInfoEditable: boolean
  isLoading: boolean
  onDelete: () => void
  onExit: () => void
  onLoginToggle: () => void
  onSave: (event: React.FormEvent) => void
  onAddConditionalTemplate: () => void
  onChangeTemplateConditionalTemplate: (
    uniqueId: number,
    template: string
  ) => void
  onRemoveConditionalTemplate: (uniqueId: number) => void
  templates: Template[]
  onChangeKeywords: (values: KeywordsFormData[]) => void
  storeBindings: Binding[]
  onChangeBinding: (input: DropdownChangeInput) => void
}

interface BindingSelectorWrapper {
  visible: boolean
}

const messages = defineMessages({
  createKeywordsMessage: {
    defaultMessage: 'Create keyword "{keyword}"',
    id: 'admin/pages.admin.pages.form.field.meta.keywords.create',
  },
  detailsTitle: {
    defaultMessage: 'Page details',
    id: 'admin/pages.admin.pages.form.details.title',
  },
  fieldLogin: {
    defaultMessage: 'Requires authentication',
    id: 'admin/pages.admin.pages.form.field.login',
  },
  fieldPath: {
    defaultMessage: 'URL',
    id: 'admin/pages.admin.pages.form.field.path',
  },
  fieldTitle: {
    defaultMessage: 'Title',
    id: 'admin/pages.admin.pages.form.field.title',
  },
  noOptionsKeywordsMessage: {
    defaultMessage: 'Type your keyword and press ENTER to add it.',
    id: 'admin/pages.admin.pages.form.field.meta.description.no-options',
  },
  pathHint: {
    defaultMessage: '/my-custom-page',
    id: 'admin/pages.admin.pages.form.details.path-hint',
  },
  seoDescription: {
    defaultMessage: 'Description',
    id: 'admin/pages.admin.pages.form.field.meta.description',
  },
  seoKeywords: {
    defaultMessage: 'Keywords',
    id: 'admin/pages.admin.pages.form.field.meta.keywords',
  },
  seoRobots: {
    defaultMessage: 'Robots',
    id: 'admin/store.metaTagRobots.title',
  },
  seoRobotsHelp: {
    defaultMessage: 'Robots',
    id: 'admin/store.metaTagRobots.description',
  },
  bindingSelectorTitle: {
    defaultMessage: 'Binding',
    id: 'admin/pages.admin.pages.form.binding-selector.title',
  },
})

const BindingSelectorWrapper: React.FunctionComponent<BindingSelectorWrapper> = props => {
  const { children, visible } = props
  return visible ? (
    <div>
      <FormFieldSeparator />
      {children}
      <div className="mb7 pb7 bb bw1 b--light-silver f3 normal" />
      <FormFieldSeparator />
    </div>
  ) : null
}

const Form: React.FunctionComponent<Props> = ({
  data,
  detailChangeHandlerGetter,
  formErrors,
  isCustomPage,
  isDeletable,
  isInfoEditable,
  isLoading,
  onAddConditionalTemplate,
  onChangeKeywords,
  onChangeOperatorConditionalTemplate,
  onChangeStatementsConditionalTemplate,
  onChangeTemplateConditionalTemplate,
  onDelete,
  onExit,
  onLoginToggle,
  onRemoveConditionalTemplate,
  onSave,
  templates,
  storeBindings,
  onChangeBinding,
}) => {
  const intl = useIntl()
  const path = data.path || ''
  const shouldDisablePathChange = !isNewRoute(data)

  const bindingOptions = useMemo(
    () => getBindingSelectorOptions(storeBindings),
    [storeBindings]
  )

  return (
    <form onSubmit={onSave}>
      <BindingSelectorWrapper visible={storeBindings.length > 1}>
        <Dropdown
          label={intl.formatMessage(messages.bindingSelectorTitle)}
          disabled={storeBindings.length === 1}
          onChange={onChangeBinding}
          options={bindingOptions}
          value={data.binding || storeBindings[0]}
        />
      </BindingSelectorWrapper>
      <SectionTitle textId="admin/pages.admin.pages.form.details.title" />
      <Input
        disabled={!!data.context}
        label={intl.formatMessage(messages.fieldTitle)}
        onChange={detailChangeHandlerGetter('title')}
        required
        value={data.title}
        errorMessage={
          formErrors.title &&
          intl.formatMessage({
            id: formErrors.title,
          })
        }
      />
      <FormFieldSeparator />
      <Input
        disabled={shouldDisablePathChange}
        label={intl.formatMessage(messages.fieldPath)}
        onChange={detailChangeHandlerGetter('path')}
        placeholder={intl.formatMessage(messages.pathHint)}
        required
        value={path}
        errorMessage={
          formErrors.path &&
          intl.formatMessage({
            id: formErrors.path,
          })
        }
      />
      <FormFieldSeparator />
      <Checkbox
        checked={!!data.auth}
        disabled={!isInfoEditable}
        label={intl.formatMessage(messages.fieldLogin)}
        name="checkbox-login"
        onChange={onLoginToggle}
        value="option-0"
      />
      {isCustomPage && (
        <>
          <FormFieldSeparator />
          <Textarea
            disabled={!!data.context}
            label={intl.formatMessage(messages.seoDescription)}
            onChange={detailChangeHandlerGetter('metaTagDescription')}
            resize="vertical"
            value={data.metaTagDescription}
          />
          <FormFieldSeparator />
          <Select
            creatable
            disabled={!!data.context}
            formatCreateLabel={(keyword: string) =>
              intl.formatMessage(messages.createKeywordsMessage, { keyword })
            }
            label={intl.formatMessage(messages.seoKeywords)}
            noOptionsMessage={() =>
              intl.formatMessage(messages.noOptionsKeywordsMessage)
            }
            onChange={onChangeKeywords}
            placeholder=""
            value={data.metaTagKeywords}
          />
          <FormFieldSeparator />
          <Input
            disabled={!!data.context}
            label={intl.formatMessage(messages.seoRobots)}
            onChange={detailChangeHandlerGetter('metaTagRobots')}
            value={data.metaTagRobots}
            helpText={intl.formatMessage(messages.seoRobotsHelp)}
          />
        </>
      )}
      <SeparatorWithLine />
      <ConditionalTemplateSection
        intl={intl}
        detailChangeHandlerGetter={detailChangeHandlerGetter}
        pages={data.pages}
        templates={templates}
        blockId={data.blockId}
        onAddConditionalTemplate={onAddConditionalTemplate}
        onRemoveConditionalTemplate={onRemoveConditionalTemplate}
        onChangeTemplateConditionalTemplate={
          onChangeTemplateConditionalTemplate
        }
        onChangeOperatorConditionalTemplate={
          onChangeOperatorConditionalTemplate
        }
        onChangeStatementsConditionalTemplate={
          onChangeStatementsConditionalTemplate
        }
        formErrors={formErrors}
      />
      <SeparatorWithLine />
      <FormFieldSeparator />
      <div className={isDeletable ? 'flex justify-between' : ''}>
        {isDeletable && (
          <Button
            disabled={isLoading}
            onClick={onDelete}
            size="small"
            variation="danger"
          >
            <FormattedMessage
              id="admin/pages.admin.pages.form.button.delete"
              defaultMessage="Delete"
            />
          </Button>
        )}
        <div className="flex justify-end">
          <div className="mr6">
            <Button
              disabled={isLoading}
              onClick={onExit}
              size="small"
              variation="tertiary"
            >
              <FormattedMessage
                id="admin/pages.admin.pages.form.button.cancel"
                defaultMessage="Cancel"
              />
            </Button>
          </div>
          <Button
            disabled={isLoading}
            isLoading={isLoading}
            onClick={onSave}
            size="small"
            variation="primary"
          >
            <FormattedMessage
              id="admin/pages.admin.pages.form.button.save"
              defaultMessage="Save"
            />
          </Button>
        </div>
      </div>
    </form>
  )
}

export default Form

```


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

[Assistant]
Here's the implementation:

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

import Section from './Section'
import SectionSeparator from './SectionSeparator'
import { CategorizedRoutes } from './typings'
import { sortRoutes } from './utils'

interface Props {
  categorizedRoutes: CategorizedRoutes
}

defineMessages({
  product: {
    defaultMessage: 'Product',
    id: 'admin/pages.admin.pages.list.section.product',
  },
  productCollections: {
    defaultMessage: 'Product collections',
    id: 'admin/pages.admin.pages.list.section.productCollections',
  },
  standard: {
    defaultMessage: 'Standard',
    id: 'admin/pages.admin.pages.list.section.standard',
  },
})

const List: React.FunctionComponent<Props> = ({ categorizedRoutes }) => (
  <Fragment>
    <Section
      hasCreateButton
      routes={sortRoutes(categorizedRoutes.noProducts)}
      titleId="admin/pages.admin.pages.list.section.standard"
    />
    <SectionSeparator />
    <Section
      routes={sortRoutes(categorizedRoutes.singleProduct)}
      titleId="admin/pages.admin.pages.list.section.product"
    />
    <SectionSeparator />
    <Section
      routes={sortRoutes(categorizedRoutes.multipleProducts)}
      titleId="admin/pages.admin.pages.list.section.productCollections"
    />
    <SectionSeparator />
    <Section
      routes={sortRoutes(categorizedRoutes.notFoundSection)}
      titleId="admin/pages.admin.pages.list.section.notFound"
    />
  </Fragment>
)

export default List

```


[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/admin/pages/List/SectionSeparator.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

const SectionSeparator = () => <div className="mt7" />

export default SectionSeparator

```


[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/admin/pages/List/Section.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Fragment } from 'react'
import { FormattedMessage } from 'react-intl'
import { withRuntimeContext } from 'vtex.render-runtime'
import { Box, Button } from 'vtex.styleguide'

import { NEW_ROUTE_ID, ROUTES_FORM } from '../consts'
import SeparatorWithLine from '../SeparatorWithLine'

import Entry from './Entry'

interface Props {
  hasCreateButton?: boolean
  routes: Route[]
  runtime: RenderContext
  titleId: string
}

const Section = ({ hasCreateButton, routes, runtime, titleId }: Props) => (
  <Box>
    <div className="relative flex items-center">
      <FormattedMessage id={titleId}>
        {title => <div className="b">{title}</div>}
      </FormattedMessage>
      {hasCreateButton && (
        <div className="absolute right-0">
          <Button
            onClick={() => {
              runtime.navigate({
                page: ROUTES_FORM,
                params: { id: NEW_ROUTE_ID },
              })
            }}
            size="small"
            variation="primary"
          >
            <FormattedMessage
              id="admin/pages.admin.pages.list.button.create"
              defaultMessage="Create New"
            />
          </Button>
        </div>
      )}
    </div>
    {routes.map(route => (
      <Fragment key={route.path}>
        <SeparatorWithLine />
        <Entry route={route} />
      </Fragment>
    ))}
  </Box>
)

export default withRuntimeContext(Section)

```


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

[Assistant]
Here's the implementation:

```typescript
export const sortRoutes = (routes: Route[]) =>
  routes.sort((a, b) => a.interfaceId.localeCompare(b.interfaceId))

```


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

[Assistant]
Here's the implementation:

```typescript
export interface CategorizedRoutes {
  multipleProducts: Route[]
  noProducts: Route[]
  singleProduct: Route[]
  notFoundSection: Route[]
}

```


[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/admin/pages/List/Entry.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { useKeydownFromClick } from 'keydown-from-click'
import React from 'react'
import { withRuntimeContext } from 'vtex.render-runtime'
import { IconEdit } from 'vtex.styleguide'

import { ROUTES_FORM } from '../consts'
import { getRouteTitle } from '../utils'

interface Props {
  route: Route
  runtime: RenderContext
}

const Entry = ({ route, runtime }: Props) => {
  const handleClick = React.useCallback(() => {
    runtime.navigate({
      page: ROUTES_FORM,
      params: { id: encodeURIComponent(route.routeId) },
    })
  }, [route.routeId, runtime])

  const handleKeyDown = useKeydownFromClick(handleClick)

  return (
    <div className="flex justify-between items-center">
      <div className="f6">{getRouteTitle(route)}</div>
      <div
        className="flex pointer outline-0"
        onClick={handleClick}
        onKeyDown={handleKeyDown}
        role="button"
        tabIndex={0}
      >
        <IconEdit color="silver" />
      </div>
    </div>
  )
}

export default withRuntimeContext(Entry)

```


[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/admin/pages/Form/stateHandlers/getLoginToggleState.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { State } from '../index'

export const getLoginToggleState = (prevState: State) => ({
  ...prevState,
  data: {
    ...prevState.data,
    auth: !!prevState.data && !prevState.data.auth,
  },
})

```


[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/admin/pages/Form/stateHandlers/getChangeTemplateConditionalTemplateState.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { State } from '../index'

export const getChangeTemplateConditionalTemplateState = (
  uniqueId: number,
  template: string
) => (prevState: State) => {
  const newPages = prevState.data.pages.map(page => {
    if (page.uniqueId === uniqueId) {
      return {
        ...page,
        template,
      }
    }
    return page
  })

  return {
    ...prevState,
    data: {
      ...prevState.data,
      pages: newPages,
    },
    formErrors: {},
  }
}

```


[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/admin/pages/Form/stateHandlers/getChangeStatementsConditionalTemplate.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Statements } from 'pages'

import { State } from '../index'

export const getChangeStatementsConditionalTemplate = (
  uniqueId: number,
  statements: Statements[]
) => (prevState: State) => {
  const newPages = prevState.data.pages.map(page => {
    if (page.uniqueId === uniqueId) {
      return {
        ...page,
        condition: {
          ...page.condition,
          statements,
        },
      }
    }
    return page
  })

  return {
    ...prevState,
    data: {
      ...prevState.data,
      pages: newPages,
    },
    formErrors: {},
  }
}

```


[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/admin/pages/Form/stateHandlers/getChangeOperatorConditionalTemplateState.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ConditionsProps } from 'vtex.styleguide'

import { State } from '../index'

export const getChangeOperatorConditionalTemplateState = (
  uniqueId: number,
  operator: NonNullable<ConditionsProps['operator']>
) => (prevState: State) => {
  const newPages = prevState.data.pages.map(page => {
    if (page.uniqueId === uniqueId) {
      return {
        ...page,
        condition: {
          ...page.condition,
          allMatches: operator === 'all',
        },
        operator,
      }
    }
    return page
  })

  return {
    ...prevState,
    data: {
      ...prevState.data,
      pages: newPages,
    },
    formErrors: {},
  }
}

```


[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/admin/pages/Form/stateHandlers/getChangeOperatorConditionalTemplateState.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import NEW_PAGE from './__fixtures__/newPage'
import setupDate from './__fixtures__/setupDate'
import BASE_STATE from './__fixtures__/state'
import { getChangeOperatorConditionalTemplateState } from './getChangeOperatorConditionalTemplateState'

describe('getChangeOperatorConditionalTemplateState', () => {
  setupDate()

  it('should modify operator given a unique ID', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      isInfoEditable: false,
    }

    expect(
      getChangeOperatorConditionalTemplateState(3, 'all')(mockState)
    ).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            operator: 'all',
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    })
  })

  it('should set allMatches boolean to true given "all" as operator', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      isInfoEditable: false,
    }

    expect(
      getChangeOperatorConditionalTemplateState(3, 'all')(mockState)
    ).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            condition: expect.objectContaining({
              allMatches: true,
            }),
            operator: 'all',
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    })
  })

  it('should set allMatches boolean to false given "any" as operator', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      isInfoEditable: false,
    }

    expect(
      getChangeOperatorConditionalTemplateState(3, 'any')(mockState)
    ).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            condition: expect.objectContaining({
              allMatches: false,
            }),
            operator: 'any',
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    })
  })

  it('should clear formError', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      formErrors: {
        title: 'oi',
      },
      isInfoEditable: false,
    }

    expect(
      getChangeOperatorConditionalTemplateState(3, 'all')(mockState)
    ).toEqual(
      expect.objectContaining({
        formErrors: {},
      })
    )
  })
})

```


[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/admin/pages/Form/stateHandlers/getValidateFormState.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { RouteFormData } from 'pages'

import { State } from '../index'

const REQUIRED_MESSAGE = 'admin/pages.admin.pages.form.templates.field.required'

const validateFalsyPath = (path: keyof RouteFormData) => (
  data: RouteFormData
) => !data[path] && { [path]: REQUIRED_MESSAGE }

const validateUrlBeginning = (path: string) => {
  if (path.startsWith('/')) {
    return {}
  }
  return {
    path: 'admin/pages.admin.pages.form.templates.path.validation-error',
  }
}

const validateConditionalTemplates: (data: RouteFormData) => { pages?: {} } = (
  data: RouteFormData
) => {
  return data.pages.reduce<Record<string, any>>(
    (acc, { uniqueId, condition, template }) => {
      const templateError = !template && { template: REQUIRED_MESSAGE }
      const conditionError = !condition.statements.length && {
        condition: REQUIRED_MESSAGE,
      }

      if (templateError || conditionError) {
        acc.pages = {
          ...acc.pages,
          [uniqueId]: {
            ...templateError,
            ...conditionError,
          },
        }
      }
      return acc
    },
    {}
  )
}

export const getValidateFormState = (prevState: State) => {
  return {
    ...prevState,
    formErrors: {
      ...prevState.formErrors,
      ...(validateUrlBeginning(prevState.data.path) as Record<string, string>),
      ...validateFalsyPath('path')(prevState.data),
      ...validateFalsyPath('blockId')(prevState.data),
      ...(prevState.isInfoEditable
        ? validateFalsyPath('title')(prevState.data)
        : {}),
      ...validateConditionalTemplates(prevState.data),
    },
  }
}

```


[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/admin/pages/Form/stateHandlers/getAddConditionalTemplateState.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import NEW_PAGE from './__fixtures__/newPage'
import setupDate from './__fixtures__/setupDate'
import BASE_STATE from './__fixtures__/state'
import { getAddConditionalTemplateState } from './getAddConditionalTemplateState'

describe('getAddConditionalTemplateState', () => {
  setupDate()

  it(`should add empty page with uniqueId if data.pages is empty`, () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [],
      },
    }

    expect(getAddConditionalTemplateState(mockState)).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 0,
          },
        ],
      },
    })
  })

  it(`should add empty page with uniqueId === highest uniqueId + 1`, () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    }

    expect(getAddConditionalTemplateState(mockState)).toMatchObject({
      data: {
        pages: [
          ...mockState.data.pages,
          {
            ...NEW_PAGE,
            uniqueId: 11,
          },
        ],
      },
    })
  })

  it(`should clear form errors`, () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [],
      },
      formErrors: {
        title: 'oi',
      },
    }

    expect(getAddConditionalTemplateState(mockState)).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 0,
          },
        ],
      },
      formErrors: {},
    })
  })
})

```


[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/admin/pages/Form/stateHandlers/getLoginToggleState.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import BASE_STATE from './__fixtures__/state'
import { getLoginToggleState } from './getLoginToggleState'

describe('getLoginToggleState', () => {
  it('should negate data.login value', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        auth: true,
      },
    }

    expect(getLoginToggleState(mockState)).toMatchObject({
      data: { auth: false },
    })
  })
})

```


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

[User] Show me the implementation of admin-pages/react/components/admin/pages/Form/stateHandlers/getAddConditionalTemplateState.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { PagesFormData } from 'pages'

import { State } from '../index'

const getMaxUniqueId: (pages: PagesFormData[]) => number = pages => {
  return pages.reduce((acc, { uniqueId: currentValue }) => {
    if (acc < currentValue) {
      return currentValue
    }
    return acc
  }, -1)
}

export const getAddConditionalTemplateState = (prevState: State) => {
  const maxUniqueId = getMaxUniqueId(prevState.data.pages)
  const now = new Date()
  const newPage: PagesFormData = {
    condition: {
      allMatches: true,
      id: '',
      statements: [
        {
          error: '',
          object: { date: now },
          subject: 'date',
          verb: 'is',
        },
      ],
    },
    operator: 'all',
    pageId: '',
    template: '',
    uniqueId: maxUniqueId + 1,
  }

  return {
    ...prevState,
    data: { ...prevState.data, pages: prevState.data.pages.concat(newPage) },
    formErrors: {},
  }
}

```


[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/admin/pages/Form/stateHandlers/getRemoveConditionalTemplateState.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import NEW_PAGE from './__fixtures__/newPage'
import BASE_STATE from './__fixtures__/state'
import { getRemoveConditionalTemplateState } from './getRemoveConditionalTemplateState'

describe('getRemoveConditionalTemplateState', () => {
  it('should remove the given page with the given uniqueId from "data.pages"', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    }

    expect(getRemoveConditionalTemplateState(10)(mockState)).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    })
  })

  it(`should clear form errors`, () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      formErrors: {
        title: 'oi',
      },
    }

    expect(getRemoveConditionalTemplateState(10)(mockState)).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      formErrors: {},
    })
  })
})

```


[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/admin/pages/Form/stateHandlers/index.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
export {
  getAddConditionalTemplateState,
} from './getAddConditionalTemplateState'
export {
  getChangeOperatorConditionalTemplateState,
} from './getChangeOperatorConditionalTemplateState'
export {
  getChangeStatementsConditionalTemplate,
} from './getChangeStatementsConditionalTemplate'
export {
  getChangeTemplateConditionalTemplateState,
} from './getChangeTemplateConditionalTemplateState'
export { getLoginToggleState } from './getLoginToggleState'
export {
  getRemoveConditionalTemplateState,
} from './getRemoveConditionalTemplateState'
export { getValidateFormState } from './getValidateFormState'

```


[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/admin/pages/Form/stateHandlers/getChangeStatementsConditionalTemplate.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import NEW_PAGE from './__fixtures__/newPage'
import BASE_STATE from './__fixtures__/state'
import { getChangeStatementsConditionalTemplate } from './getChangeStatementsConditionalTemplate'

describe('getChangeStatementsConditionalTemplate', () => {
  it('should change statement inside condition given a page uniqueId', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            condition: {
              allMatches: false,
              statements: [],
            },
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    }

    expect(
      getChangeStatementsConditionalTemplate(3, [
        { error: '', object: {}, subject: 'Date', verb: '=' },
      ])(mockState)
    ).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            condition: {
              allMatches: false,
              statements: [{ subject: 'Date', verb: '=' }],
            },
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 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/admin/pages/Form/stateHandlers/getRemoveConditionalTemplateState.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { State } from '../index'

export const getRemoveConditionalTemplateState = (uniqueId: number) => (
  prevState: State
) => {
  const newPages = prevState.data.pages.filter(
    page => page.uniqueId !== uniqueId
  )

  return {
    ...prevState,
    data: { ...prevState.data, pages: newPages },
    formErrors: {},
  }
}

```


[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/admin/pages/Form/stateHandlers/getChangeTemplateConditionalTemplateState.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import NEW_PAGE from './__fixtures__/newPage'
import BASE_STATE from './__fixtures__/state'
import { getChangeTemplateConditionalTemplateState } from './getChangeTemplateConditionalTemplateState'

describe('getChangeTemplateConditionalTemplateState', () => {
  it('should modify template given a unique ID', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    }

    expect(
      getChangeTemplateConditionalTemplateState(3, 'store/test')(mockState)
    ).toMatchObject({
      data: {
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            template: 'store/test',
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
    })
  })

  it('should clear formError', () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            ...NEW_PAGE,
            uniqueId: 10,
          },
          {
            ...NEW_PAGE,
            uniqueId: 3,
          },
          {
            ...NEW_PAGE,
            uniqueId: 5,
          },
        ],
      },
      formErrors: {
        title: 'oi',
      },
    }

    expect(
      getChangeTemplateConditionalTemplateState(3, 'store/test')(mockState)
    ).toEqual(
      expect.objectContaining({
        formErrors: {},
      })
    )
  })
})

```


[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/admin/pages/Form/stateHandlers/getValidateFormState.test.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { State } from '../index'

import { getValidateFormState } from './getValidateFormState'
import BASE_STATE from './__fixtures__/state'

describe('getValidateFormState', () => {
  it('should return empty object if there are no errors', () => {
    const mockState: State = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            condition: {
              allMatches: true,
              id: '1',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-01'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page1',
            template: 'myTemplate2',
            uniqueId: 10,
          },
          {
            condition: {
              allMatches: true,
              id: '34',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-02'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page2',
            template: 'myTemplate2',
            uniqueId: 5,
          },
        ],
        path: '/test',
        title: 'test',
      },
    }

    expect(getValidateFormState(mockState)).toEqual(
      expect.objectContaining({ formErrors: {} })
    )
  })

  it('should return error if path is falsy', () => {
    const mockState: State = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        blockId: '',
        pages: [
          {
            condition: {
              allMatches: true,
              id: '1',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-01'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page1',
            template: 'myTemplate1',
            uniqueId: 10,
          },
          {
            condition: {
              allMatches: true,
              id: '34',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-02'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page2',
            template: 'myTemplate2',
            uniqueId: 5,
          },
        ],
        path: '',
        title: 'test',
      },
    }

    expect(getValidateFormState(mockState)).toEqual(
      expect.objectContaining({
        formErrors: expect.objectContaining({
          path: 'admin/pages.admin.pages.form.templates.field.required',
        }),
      })
    )
  })

  it(`should return error if path doesn't begin with '/'`, () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        path: 'lalala',
        title: 'test',
      },
    }

    expect(getValidateFormState(mockState)).toEqual(
      expect.objectContaining({
        formErrors: expect.objectContaining({
          path: 'admin/pages.admin.pages.form.templates.path.validation-error',
        }),
      })
    )
  })

  it('should return error if pageId is falsy', () => {
    const mockState: State = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        blockId: '',
        pages: [
          {
            condition: {
              allMatches: true,
              id: '1',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-01'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page1',
            template: 'myTemplate1',
            uniqueId: 10,
          },
          {
            condition: {
              allMatches: true,
              id: '34',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-02'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page2',
            template: 'myTemplate2',
            uniqueId: 5,
          },
        ],
        path: '/test',
        title: 'test',
      },
    }

    expect(getValidateFormState(mockState)).toEqual(
      expect.objectContaining({
        formErrors: expect.objectContaining({
          blockId: 'admin/pages.admin.pages.form.templates.field.required',
        }),
      })
    )
  })

  it('should return error if title is falsy', () => {
    const mockState: State = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        pages: [
          {
            condition: {
              allMatches: true,
              id: '1',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-01'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page1',
            template: 'myTemplate1',
            uniqueId: 10,
          },
          {
            condition: {
              allMatches: true,
              id: '34',
              statements: [
                {
                  error: '',
                  object: {
                    date: new Date('2019-02-02'),
                  },
                  subject: 'date',
                  verb: 'is',
                },
              ],
            },
            operator: 'any',
            pageId: 'page2',
            template: 'myTemplate2',
            uniqueId: 5,
          },
        ],
        path: '/test',
        title: '',
      },
    }

    expect(getValidateFormState(mockState)).toEqual(
      expect.objectContaining({
        formErrors: expect.objectContaining({
          title: 'admin/pages.admin.pages.form.templates.field.required',
        }),
      })
    )
  })

  it(`shouldn't return error if title is falsy and field isn't editable`, () => {
    const mockState = {
      ...BASE_STATE,
      data: {
        ...BASE_STATE.data,
        path: '/test',
        template: 'defaultTemplate',
        title: '',
      },
      isInfoEditable: false,
    }

    expect(getValidateFormState(mockState)).toEqual(
      expect.objectContaining({
        formErrors: {},
      })
    )
  })

  describe('pages[] field errors', () => {
    it('should return error with if template of conditional template is falsy', () => {
      const mockState: State = {
        ...BASE_STATE,
        data: {
          ...BASE_STATE.data,
          pages: [
            {
              condition: {
                allMatches: true,
                id: '1',
                statements: [
                  {
                    error: '',
                    object: {
                      date: new Date('2019-02-01'),
                    },
                    subject: 'date',
                    verb: 'is',
                  },
                ],
              },
              operator: 'any',
              pageId: 'page1',
              template: 'myTemplate1',
              uniqueId: 10,
            },
            {
              condition: {
                allMatches: true,
                id: '34',
                statements: [
                  {
                    error: '',
                    object: {
                      date: new Date('2019-02-02'),
                    },
                    subject: 'date',
                    verb: 'is',
                  },
                ],
              },
              operator: 'any',
              pageId: 'page2',
              template: '',
              uniqueId: 5,
            },
          ],
          path: '/test',
          title: 'defaultTemplate',
        },
      }

      expect(getValidateFormState(mockState)).toMatchObject({
        formErrors: expect.objectContaining({
          pages: {
            5: {
              template: 'admin/pages.admin.pages.form.templates.field.required',
            },
          },
        }),
      })
    })

    it('should return error with if template of conditional template is falsy', () => {
      const mockState: State = {
        ...BASE_STATE,
        data: {
          ...BASE_STATE.data,
          pages: [
            {
              condition: {
                allMatches: true,
                statements: [],
              },
              operator: 'any',
              pageId: 'page1',
              template: 'myTemplate1',
              uniqueId: 10,
            },
            {
              condition: {
                allMatches: true,
                id: '34',
                statements: [
                  {
                    error: '',
                    object: {
                      date: new Date('2019-02-02'),
                    },
                    subject: 'date',
                    verb: 'is',
                  },
                ],
              },
              operator: 'any',
              pageId: 'page2',
              template: 'myTemplate2',
              uniqueId: 5,
            },
          ],
          path: '/test',
          title: 'defaultTemplate',
        },
      }

      expect(getValidateFormState(mockState)).toMatchObject({
        formErrors: expect.objectContaining({
          pages: {
            10: {
              condition:
                'admin/pages.admin.pages.form.templates.field.required',
            },
          },
        }),
      })
    })

    it('should return error for more than one page and field', () => {
      const mockState: State = {
        ...BASE_STATE,
        data: {
          ...BASE_STATE.data,
          pages: [
            {
              condition: {
                allMatches: true,
                statements: [],
              },
              operator: 'any',
              template: 'myTemplate1',
              uniqueId: 10,
            },
            {
              condition: {
                allMatches: true,
                statements: [],
              },
              operator: 'any',
              template: 'myTemplate2',
              uniqueId: 5,
            },
          ],
          path: '/test',
          title: 'defaultTemplate',
        },
      }

      expect(getValidateFormState(mockState)).toMatchObject({
        formErrors: {
          pages: {
            5: {
              condition:
                'admin/pages.admin.pages.form.templates.field.required',
            },
            10: {
              condition:
                'admin/pages.admin.pages.form.templates.field.required',
            },
          },
        },
      })
    })
  })
})

```


[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/admin/pages/Form/stateHandlers/__fixtures__/newPage.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ConditionsOperator } from 'vtex.styleguide'

const newPage = {
  condition: {
    allMatches: true,
    id: '',
    statements: [
      {
        error: '',
        object: {
          date: new Date('2019-02-01'),
        },
        subject: 'date',
        verb: 'is',
      },
    ],
  },
  operator: 'all' as ConditionsOperator,
  pageId: '',
  template: '',
}

export default newPage

```


[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/admin/pages/Form/stateHandlers/__fixtures__/state.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
export default {
  data: {
    auth: false,
    blockId: 'test.app@1.x:store.home#cool-home',
    context: null,
    declarer: 'user',
    domain: 'store',
    interfaceId: 'test.app@1.x:store.home',
    pages: [],
    path: '/',
    routeId: 'store.home#cool-home',
    title: null,
    uuid: undefined,
  },
  formErrors: {},
  isDeletable: false,
  isInfoEditable: true,
  isLoading: false,
}

```


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

[User] Show me the implementation of admin-pages/react/components/admin/pages/Form/stateHandlers/__fixtures__/setupDate.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
import MockDate from 'mockdate'

const setupDate = () => {
  beforeEach(() => {
    MockDate.set('2019-02-01')
  })

  afterEach(() => {
    MockDate.reset()
  })
}

export default setupDate

```


[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/admin/store/utils/utils.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { QueryResult } from 'react-apollo'
import { FormattedMessage, useIntl } from 'react-intl'
import { Button, EmptyState, Spinner } from 'vtex.styleguide'

const isRefetching = (status: number): boolean => status === 4

const Loading = (): React.ReactElement => (
  <div className="flex justify-center items-center h5">
    <Spinner />
  </div>
)

interface ErrorMessageProps {
  title: string
  description: string
  refetch: () => unknown
  refetching: boolean
}

const ErrorMessage: React.FunctionComponent<ErrorMessageProps> = ({
  title,
  description,
  refetch,
  refetching,
}) => {
  const intl = useIntl()
  return (
    <div className="flex flex-column justify-center">
      <EmptyState
        title={intl.formatMessage({
          id: title,
        })}
      >
        <FormattedMessage id={description} />
      </EmptyState>
      <Button
        size="small"
        variation="tertiary"
        onClick={() => refetch()}
        isLoading={refetching}
      >
        <FormattedMessage id="admin/pages.editor.store.settings.refetch" />
      </Button>
    </div>
  )
}

export function handleCornerCases<TData, TVariables>(
  options: { error: { title: string; description: string } },
  fn: (
    x: Omit<QueryResult<TData, TVariables>, 'loading' | 'error'> & {
      data: TData // be sure data is not undefined
    }
  ) => JSX.Element
) {
  return ({
    loading,
    error,
    data,
    refetch,
    networkStatus,
    ...rest
  }: QueryResult<TData, TVariables>) => {
    if (loading) {
      return <Loading />
    }
    if (error || !data) {
      const { error: errorMessage } = options
      console.error('Error', error)
      return (
        <ErrorMessage
          {...errorMessage}
          refetch={refetch}
          refetching={isRefetching(networkStatus)}
        />
      )
    }

    return fn({ data, refetch, networkStatus, ...rest })
  }
}

```


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

[Assistant]
Here's the implementation:

```tsx
import { JSONSchema6 } from 'json-schema'
import { assoc } from 'ramda'
import React, { useContext, useEffect, useState } from 'react'
import { ChildMutateProps, withMutation } from 'react-apollo'
import { FormattedMessage, useIntl, IntlShape } from 'react-intl'
import Form, { UiSchema } from 'react-jsonschema-form'
import { formatIOMessage } from 'vtex.native-types'
import { Button, ToastContext } from 'vtex.styleguide'

import ArrayFieldTemplate from '../../../form/ArrayFieldTemplate'
import BaseInput from '../../../form/BaseInput'
import Toggle from '../../../form/Toggle'
import FieldTemplate from '../../../form/FieldTemplate'
import ObjectFieldTemplate from '../../../form/ObjectFieldTemplate'
import withStoreSettings, { FormProps } from './components/withStoreSettings'
import SaveAppSettings from './mutations/SaveAppSettings.graphql'
import { formatSchema, tryParseJson, removeObjectProperties } from './utils'
import { CustomWidgetProps } from '../../../form/typings'

interface MutationData {
  message: string
}

interface MutationVariables {
  app: string
  version: string
  settings: string
}

type Props = ChildMutateProps<FormProps, MutationData, MutationVariables>

const CheckboxWidget = (props: CustomWidgetProps) => (
  <div className="pv4">
    <Toggle {...props} />
    {props.schema.description && (
      <span className="t-small c-muted-1 pv3 relative">
        {props.schema.description}
      </span>
    )}
  </div>
)

const widgets = {
  BaseInput,
  CheckboxWidget,
}

function resolveSchemaForCurrentTab(
  tab: string | undefined,
  schema: JSONSchema6,
  intl: IntlShape
) {
  const advancedSettingsSchema = (schema.properties
    ?.advancedSettings as JSONSchema6) ?? {
    properties: {},
  }

  switch (tab) {
    case 'general':
      return assoc<JSONSchema6>(
        'properties',
        formatSchema({
          schema: schema.properties || {},
          intl,
          ignore: ['title', 'advancedSettings'],
        }),
        schema
      )
    case 'advanced':
      return assoc<JSONSchema6>(
        'properties',
        formatSchema({
          schema: advancedSettingsSchema.properties || {},
          intl,
          ignore: ['title'],
        }),
        advancedSettingsSchema
      )
    default:
      return assoc<JSONSchema6>(
        'properties',
        formatSchema({
          schema: removeObjectProperties(schema, ['title']).properties || {},
          intl,
        }),
        schema
      )
  }
}

const StoreForm: React.FunctionComponent<Props> = ({ store, mutate, tab }) => {
  const intl = useIntl()
  const [formData, setFormData] = useState(tryParseJson(store.settings))

  const [submitting, setSubmitting] = useState(false)

  const { showToast } = useContext(ToastContext)

  useEffect(() => {
    if (submitting) {
      const { slug: app, version } = store

      mutate({
        variables: { app, version, settings: JSON.stringify(formData) },
      })
        .then(() =>
          showToast(
            intl.formatMessage({
              id: 'admin/pages.admin.pages.form.save.success',
            })
          )
        )
        .catch(() =>
          showToast(
            intl.formatMessage({
              id: 'admin/pages.admin.pages.form.save.error',
            })
          )
        )
        .finally(() => setSubmitting(false))
    }
  }, [formData, intl, mutate, showToast, store, submitting])

  const shouldDisplayWarning = tab === 'advanced'
  const { settingsSchema, settingsUiSchema } = store

  const schema = tryParseJson<JSONSchema6>(settingsSchema)
  const uiSchema = tryParseJson<UiSchema>(settingsUiSchema)

  const schemas = {
    schema: resolveSchemaForCurrentTab(tab, schema, intl),
    title: formatIOMessage({ id: schema.title || '', intl }),
    ...(uiSchema && { uiSchema }),
  }

  return (
    <div className="flex flex-column justify-center">
      {shouldDisplayWarning && (
        <div className="pv3">
          <span className="c-emphasis">
            <FormattedMessage id="admin/pages.editor.store.settings.advanced.disclaimer" />
          </span>
        </div>
      )}
      <Form
        {...schemas}
        formData={formData}
        onSubmit={() => setSubmitting(true)}
        onError={e => console.error('Bad input numbers: ', e.length)}
        onChange={({ formData: newFormData }) => setFormData(newFormData)}
        showErrorList={false}
        FieldTemplate={FieldTemplate}
        ArrayFieldTemplate={ArrayFieldTemplate}
        ObjectFieldTemplate={ObjectFieldTemplate}
        widgets={widgets}
      >
        <div className="w-100 tr">
          <Button
            size="small"
            type="submit"
            variation="primary"
            onClick={() => setSubmitting(true)}
            isLoading={submitting}
          >
            <FormattedMessage id="admin/pages.admin.pages.form.button.save" />
          </Button>
        </div>
      </Form>
    </div>
  )
}

export default withMutation<{ tab?: string }, MutationData, MutationVariables>(
  SaveAppSettings
)(
  withStoreSettings<ChildMutateProps<{}, MutationData, MutationVariables>>(
    StoreForm
  )
)

```


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

[Assistant]
Here's the implementation:

```typescript
import { JSONSchema6, JSONSchema6Definition } from 'json-schema'
import { IntlShape } from 'react-intl'
import { formatIOMessage } from 'vtex.native-types'

interface FormatSchemaArgs {
  schema: JSONSchema6Definition
  intl: IntlShape
  ignore?: string[]
}

/**
 * Returns the original object without the received properties
 * @param object
 * @param properties
 */
export const removeObjectProperties = (
  object: Record<string, any>,
  properties: string[]
) => {
  let newObject = object

  properties.forEach(property => {
    const { [property]: deletedProperty, ...otherProperties } = newObject
    newObject = otherProperties
  })

  return newObject
}

export const formatSchema = ({
  schema,
  intl,
  ignore,
}: FormatSchemaArgs): JSONSchema6Definition => {
  if (typeof schema === 'boolean') {
    return schema
  }
  const filteredSchema = ignore
    ? removeObjectProperties(schema, ignore)
    : schema

  return Object.entries(filteredSchema).reduce<JSONSchema6>(
    (acc, [currKey, currValue]) => {
      let formattedValue: unknown

      if (
        typeof currValue === 'object' &&
        currValue !== null &&
        !Array.isArray(currValue)
      ) {
        formattedValue = formatSchema({ schema: currValue, intl })
      } else if (typeof currValue === 'string') {
        formattedValue = formatIOMessage({ id: currValue, intl })
      } else {
        formattedValue = currValue
      }

      return {
        ...acc,
        [currKey]: formattedValue,
      }
    },
    filteredSchema
  )
}

export const tryParseJson = <T>(str: string): T => {
  let parsed = null

  try {
    if (str) {
      parsed = JSON.parse(str)
    }
  } catch (e) {
    console.error(e)
  }

  return parsed
}

```


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

[Assistant]
Here's the implementation:

```tsx
import { useKeydownFromClick } from 'keydown-from-click'
import { equals, last, path, pick } from 'ramda'
import React, { useContext, useState } from 'react'
import { FormattedMessage, injectIntl, WrappedComponentProps } from 'react-intl'
import {
  Button,
  ColorPicker,
  Dropdown,
  IconCaretDown,
  IconCaretUp,
  Input,
  ToastContext,
  Toggle,
  Spinner,
} from 'vtex.styleguide'

import ImageUploader from '../../../form/ImageUploader'
import withPWAMutations, {
  ManifestMutationData,
  PWAMutationProps,
} from './components/withPWAMutations'
import withPWASettings, {
  Manifest,
  PWAImage,
  PWASettingsProps,
} from './components/withPWASettings'
import { messages } from './messages'
import {
  DISPLAY_OPTIONS,
  ORIENTATION_OPTIONS,
  TOAST_DURATION,
  INSTALL_PROMPT_OPTIONS,
} from './utils/constants'

const fillManifest = (manifest: Manifest): Manifest => ({
  ...manifest,
  display: manifest.display || 'standalone',
  orientation: manifest.orientation || 'portrait',
  ['start_url']: manifest.start_url || '/',
})

const isManifestValid = (manifest: Manifest): boolean =>
  Boolean(
    manifest.start_url &&
      manifest.background_color &&
      manifest.display &&
      manifest.orientation &&
      manifest.theme_color
  )

type Props = WrappedComponentProps & PWAMutationProps & PWASettingsProps

const PWAForm: React.FunctionComponent<Props> = ({
  manifest: pwaManifest,
  splashes,
  iOSIcons,
  pwaSettings,
  updateManifest,
  updateManifestIcon,
  updatePWASettings,
  intl,
  refetch,
}) => {
  const [manifest, setManifest] = useState(fillManifest(pwaManifest))
  const [settings, setSettings] = useState(pwaSettings)
  const [colorHistory, setColorHistory] = useState([
    pwaManifest.theme_color,
    pwaManifest.background_color,
  ])
  const [submitting, setSubmitting] = useState(false)
  const [showSpecific, setShowSpecific] = useState(false)
  const [splashLoading, setSplashLoading] = useState(true)

  const toggleSpecific = React.useCallback(
    () => setShowSpecific(!showSpecific),
    [showSpecific]
  )

  const toggleSpecificByKeyDown = useKeydownFromClick(toggleSpecific)

  const { showToast } = useContext(ToastContext)

  const [splash = null] = splashes || []
  const androidIcon = manifest.icons && last(manifest.icons)
  const iOSIcon = last(iOSIcons)

  async function uploadIcon({
    icon,
    iOS = false,
  }: {
    icon: File
    iOS?: boolean
  }): Promise<void> {
    setSubmitting(true)
    try {
      const result = await updateManifestIcon.mutate({
        variables: { icon, iOS },
      })
      // If the iOS icon changed, show the new iOS splash screen
      if (iOS) {
        await refetch()
      } else {
        const icons: PWAImage[] | undefined = path(
          ['data', 'updateManifestIcon', 'icons'],
          result || {}
        )
        setManifest({ ...manifest, icons })
      }
      showToast({
        duration: TOAST_DURATION,
        message: intl.formatMessage(messages.updateManifestIconSuccess),
      })
    } catch (err) {
      console.error('Error updating manifest icon: ', err)
      showToast({
        duration: Infinity,
        message: intl.formatMessage(messages.updateManifestIconError),
      })
    } finally {
      setSubmitting(false)
    }
  }

  async function saveSettings(): Promise<void> {
    await updatePWASettings.mutate({ variables: { settings } })
  }

  async function saveManifest(): Promise<ManifestMutationData | undefined> {
    const manifestData = pick(
      [
        'start_url',
        'theme_color',
        'background_color',
        'display',
        'orientation',
      ],
      manifest
    ) as ManifestMutationData
    const result = await updateManifest.mutate({
      variables: { manifest: manifestData },
    })
    return path(['data', 'updateManifest'], result || {})
  }

  async function handleSubmit() {
    setSubmitting(true)
    try {
      const mutations: Promise<ManifestMutationData | void>[] = [saveManifest()]
      if (!equals(settings, pwaSettings)) {
        mutations.push(saveSettings())
      }
      const [newManifest] = await Promise.all(mutations)
      // If background color changed, show the new iOS splash screen
      if (
        newManifest &&
        pwaManifest.background_color !== newManifest.background_color
      ) {
        await refetch()
      }
      showToast({
        duration: TOAST_DURATION,
        message: intl.formatMessage({
          id: 'admin/pages.admin.pages.form.save.success',
        }),
      })
    } catch (err) {
      console.error(err)
      showToast({
        duration: Infinity,
        message: intl.formatMessage({
          id: 'admin/pages.admin.pages.form.save.error',
        }),
      })
    } finally {
      setSubmitting(false)
    }
  }

  return (
    <div className="flex flex-column justify-center">
      <div className="flex flex-row items-center">
        <div className="t-heading-7 w-40">
          <FormattedMessage id="admin/pages.editor.store.settings.pwa.theme_color" />
        </div>
        <div className="w-100">
          <ColorPicker
            disabled={submitting}
            color={{ hex: manifest.theme_color }}
            colorHistory={colorHistory}
            label={intl.formatMessage({
              id: 'admin/pages.admin.pages.form.templates.field.default',
            })}
            onChange={(color: { hex: string }) => {
              setManifest({ ...manifest, ['theme_color']: color.hex })
              setColorHistory([...colorHistory, color.hex])
            }}
          />
        </div>
      </div>
      <div className="pt2">
        <div className="flex flex-row items-center">
          <div className="t-heading-7 w-40">
            <FormattedMessage id="admin/pages.editor.store.settings.pwa.background_color" />
          </div>
          <div className="w-100">
            <ColorPicker
              disabled={submitting}
              color={{ hex: manifest.background_color }}
              colorHistory={colorHistory}
              label={intl.formatMessage({
                id: 'admin/pages.admin.pages.form.templates.field.default',
              })}
              onChange={(color: { hex: string }) => {
                setManifest({ ...manifest, ['background_color']: color.hex })
                setColorHistory([...colorHistory, color.hex])
              }}
            />
          </div>
        </div>
      </div>
      <div className="flex flex-column items-center justify-center">
        <div className="w-100 pt4">
          <ImageUploader
            disabled={submitting}
            value={
              androidIcon
                ? new URL(`https://${location.hostname}/${androidIcon.src}`)
                    .href
                : ''
            }
            schema={{
              title: 'admin/pages.editor.store.settings.pwa.android-logo-icon',
            }}
            onFileDrop={(icon: File) => uploadIcon({ icon })}
          />
        </div>
        <div className="w-100 pt4">
          <ImageUploader
            disabled={submitting}
            value={
              iOSIcon
                ? new URL(`https://${location.hostname}/${iOSIcon.src}`).href
                : ''
            }
            schema={{
              title: 'admin/pages.editor.store.settings.pwa.ios-logo-icon',
            }}
            onFileDrop={(icon: File) => uploadIcon({ icon, iOS: true })}
          />
        </div>
      </div>
      {splash && (
        <div className="pt6">
          <div className="t-heading-7 mb4">
            <FormattedMessage id="admin/pages.editor.store.settings.pwa.splash-screen" />
          </div>
          <div className="w-100 flex justify-center items-center">
            {splashLoading && <Spinner />}
            <img
              alt={intl.formatMessage({
                id: 'admin/pages.editor.store.settings.pwa.splash-screen',
              })}
              className="h5 shadow-1 mb3"
              src={`${splash.src}?v=${Date.now()}`}
              onLoad={() => setSplashLoading(false)}
              style={{ display: splashLoading ? 'none' : 'block' }}
            />
          </div>
        </div>
      )}
      <div className="pv7">
        <div className="w-100 bb b--muted-4" />
      </div>
      <div
        aria-checked={showSpecific}
        className="pb3 link pointer c-muted-1 outline-0"
        onClick={toggleSpecific}
        onKeyDown={toggleSpecificByKeyDown}
        role="switch"
        tabIndex={0}
      >
        <span className="pr4">
          <FormattedMessage id="admin/pages.editor.store.settings.pwa.app-settings" />
        </span>
        {showSpecific ? <IconCaretUp /> : <IconCaretDown />}
      </div>
      {showSpecific && (
        <>
          <div className="pt4 w-100">
            <Input
              disabled={submitting}
              size="small"
              label={intl.formatMessage(messages.startUrl)}
              value={manifest.start_url}
              onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                setManifest({ ...manifest, ['start_url']: e.target.value })
              }
            />
          </div>
          <div className="pt4 w-100">
            <Dropdown
              disabled={submitting}
              value={manifest.orientation}
              label={intl.formatMessage(messages.screenOrientation)}
              options={ORIENTATION_OPTIONS.map(option => ({
                ...option,
                label: intl.formatMessage({ id: option.label }),
              }))}
              onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
                setManifest({
                  ...manifest,
                  orientation: e.target.value,
                })
              }
            />
          </div>
          <div className="pt4">
            <Dropdown
              disabled={submitting}
              value={manifest.display}
              label={intl.formatMessage(messages.pwaDisplay)}
              options={DISPLAY_OPTIONS.map(option => ({
                ...option,
                label: intl.formatMessage({ id: option.label }),
              }))}
              onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
                setManifest({
                  ...manifest,
                  display: e.target.value,
                })
              }
            />
          </div>
          <div className="pt6">
            <Toggle
              label={intl.formatMessage(messages.disablePrompt)}
              checked={!settings.disablePrompt}
              disabled={submitting}
              onChange={() =>
                setSettings({
                  ...settings,
                  disablePrompt: !settings.disablePrompt,
                })
              }
            />
          </div>
          {!settings.disablePrompt && (
            <div className="pt4">
              <Dropdown
                disabled={submitting}
                value={settings.promptOnCustomEvent}
                label={intl.formatMessage(messages.pwaPrompt)}
                options={INSTALL_PROMPT_OPTIONS.map(option => ({
                  ...option,
                  label: intl.formatMessage({ id: option.label }),
                }))}
                onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
                  setSettings({
                    ...settings,
                    promptOnCustomEvent: e.target.value,
                  })
                }
              />
            </div>
          )}
        </>
      )}
      <div className="w-100 mt7 tr">
        <Button
          size="small"
          type="submit"
          variation="primary"
          onClick={handleSubmit}
          disabled={!isManifestValid(manifest)}
          isLoading={submitting}
        >
          <FormattedMessage id="admin/pages.admin.pages.form.button.save" />
        </Button>
      </div>
    </div>
  )
}

export default injectIntl(
  withPWASettings<WrappedComponentProps>(
    withPWAMutations<WrappedComponentProps & PWASettingsProps>(PWAForm)
  )
)

```


[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/admin/store/PWAForm/messages.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

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

export const messages = defineMessages({
  androidLogoIcon: {
    defaultMessage: 'Android Logo Icon (512x512)',
    id: 'admin/pages.editor.store.settings.pwa.android-logo-icon',
  },
  disablePrompt: {
    defaultMessage: 'Add to Home Screen',
    id: 'admin/pages.editor.store.settings.pwa.disable-prompt',
  },
  iosLogoIcon: {
    defaultMessage: 'iOS Logo Icon (512x512)',
    id: 'admin/pages.editor.store.settings.pwa.ios-logo-icon',
  },
  // ORIENTATION_OPTIONS messages
  orientationAny: {
    defaultMessage: 'Any',
    id: 'admin/pages.editor.store.settings.pwa.orientation.any',
  },
  orientationLandscape: {
    defaultMessage: 'Landscape',
    id: 'admin/pages.editor.store.settings.pwa.orientation.landscape',
  },
  orientationLandscapePrimary: {
    defaultMessage: 'Landscape (Primary)',
    id: 'admin/pages.editor.store.settings.pwa.orientation.landscape-primary',
  },
  orientationLandscapeSecondary: {
    defaultMessage: 'Landscape (Secondary)',
    id: 'admin/pages.editor.store.settings.pwa.orientation.landscape-secondary',
  },
  orientationNatural: {
    defaultMessage: 'Natural',
    id: 'admin/pages.editor.store.settings.pwa.orientation.natural',
  },
  orientationPortrait: {
    defaultMessage: 'Portrait',
    id: 'admin/pages.editor.store.settings.pwa.orientation.portrait',
  },
  orientationPortraitPrimary: {
    defaultMessage: 'Portrait (Primary)',
    id: 'admin/pages.editor.store.settings.pwa.orientation.portrait-primary',
  },
  orientationPortraitSecondary: {
    defaultMessage: 'Portrait (Secondary)',
    id: 'admin/pages.editor.store.settings.pwa.orientation.portrait-secondary',
  },

  // DISPLAY_OPTIONS messages
  pwaDisplay: {
    defaultMessage: 'Display',
    id: 'admin/pages.editor.store.settings.pwa.display',
  },
  pwaDisplayBrowser: {
    defaultMessage: 'Browser',
    id: 'admin/pages.editor.store.settings.pwa.display.browser',
  },
  pwaDisplayFullscreen: {
    defaultMessage: 'Fullscreen',
    id: 'admin/pages.editor.store.settings.pwa.display.fullscreen',
  },
  pwaDisplayMinimalUi: {
    defaultMessage: 'Minimal-UI (Not supported by Chrome)',
    id: 'admin/pages.editor.store.settings.pwa.display.minimal-ui',
  },
  pwaDisplayStandalone: {
    defaultMessage: 'Standalone (Add to Home Screen)',
    id: 'admin/pages.editor.store.settings.pwa.display.standalone',
  },

  screenOrientation: {
    defaultMessage: 'Screen Orientation',
    id: 'admin/pages.editor.store.settings.pwa.screen-orientation',
  },
  startUrl: {
    defaultMessage: 'Start URL',
    id: 'admin/pages.editor.store.settings.pwa.start_url',
  },
  updateManifestIconError: {
    defaultMessage: 'Something wrong occurred while updating the App icon…',
    id: 'admin/pages.editor.store.settings.pwa.update-manifest-icon.error',
  },
  updateManifestIconSuccess: {
    defaultMessage: 'App icon successfuly updated!',
    id: 'admin/pages.editor.store.settings.pwa.update-manifest-icon.success',
  },

  // Install prompt
  pwaPrompt: {
    defaultMessage: 'Prompt "Add to Home Screen"',
    id: 'admin/pages.editor.store.settings.pwa.prompt-custom-event',
  },
  addToCartPrompt: {
    defaultMessage: 'On the first item added to cart',
    id: 'admin/pages.editor.store.settings.pwa.prompt-custom-event.addToCart',
  },
  customEventDefault: {
    defaultMessage: 'On the first visit',
    id: 'admin/pages.editor.store.settings.pwa.prompt-custom-event.default',
  },
})

```


[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/admin/store/StoreForm/mutations/SaveAppSettings.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation saveAppSettings($app: String, $version: String, $settings: String) {
  saveAppSettings(app: $app, version: $version, settings: $settings) {
    message
  }
}

```


[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/admin/store/StoreForm/queries/InstalledApp.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
query installedApp($slug: String!) {
  installedApp(slug: $slug) {
    slug
    name
    vendor
    version
    settings
  }
}

```


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

[User] Show me the implementation of admin-pages/react/components/admin/store/StoreForm/queries/AvailableApp.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
query availableApp($id: String!) {
  availableApp(id: $id) {
    id
    title
    installed
    linked
    installedVersion
    settingsSchema
    settingsUiSchema
  }
}

```


[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/admin/store/StoreForm/components/withStoreSettings.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Query } from 'react-apollo'
import { defineMessages } from 'react-intl'

import { handleCornerCases } from '../../utils/utils'
import AvailableApp from '../queries/AvailableApp.graphql'
import InstalledApp from '../queries/InstalledApp.graphql'

export interface InstalledApp {
  slug: string
  name: string
  vendor: string
  version: string
  settings: string
}

interface InstalledAppData {
  installedApp: InstalledApp
}

interface InstalledAppVariables {
  slug: string
}

class InstalledAppQuery extends Query<
  InstalledAppData,
  InstalledAppVariables
> {}

export interface AvailableApp {
  id: string
  title: string
  installed: boolean
  linked: boolean
  installedVersion: string
  settingsSchema: string
  settingsUiSchema: string
}

interface AvailableAppData {
  availableApp: AvailableApp
}

interface AvailableAppVariables {
  id: string
}

class AvailableAppQuery extends Query<
  AvailableAppData,
  AvailableAppVariables
> {}

export interface FormProps {
  store: AvailableApp &
    InstalledApp & {
      settings: string
    }
  tab?: 'advanced' | 'general'
}

defineMessages({
  description: {
    defaultMessage: `Couldn't load store settings.`,
    id: 'admin/pages.editor.store.settings.error',
  },
  title: {
    defaultMessage: 'Something went wrong',
    id: 'admin/pages.editor.store.settings.error.title',
  },
})

const options = {
  error: {
    description: 'admin/pages.editor.store.settings.error',
    title: 'admin/pages.editor.store.settings.error.title',
  },
}

function withStoreSettings<T>(
  WrappedComponent: React.ComponentType<T & FormProps>
) {
  const ComponentWithStoreSettings = (props: T) => (
    <InstalledAppQuery query={InstalledApp} variables={{ slug: 'vtex.store' }}>
      {handleCornerCases<InstalledAppData, InstalledAppVariables>(
        options,
        ({ data: storeData }) => {
          const { installedApp: store } = storeData
          const { slug, version } = store
          return (
            <AvailableAppQuery
              query={AvailableApp}
              variables={{ id: `${slug}@${version}` }}
            >
              {handleCornerCases<AvailableAppData, AvailableAppVariables>(
                options,
                ({ data: { availableApp: schemasData } }) => (
                  <WrappedComponent
                    {...props}
                    store={{
                      ...store,
                      ...schemasData,
                    }}
                  />
                )
              )}
            </AvailableAppQuery>
          )
        }
      )}
    </InstalledAppQuery>
  )

  return ComponentWithStoreSettings
}

export default withStoreSettings

```


[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/admin/store/PWAForm/mutations/UpdateManifest.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updateManifest($manifest: ManifestInput) {
  updateManifest(manifest: $manifest) {
    start_url
    theme_color
    background_color
    display
    orientation
  }
}

```


[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/admin/store/PWAForm/mutations/UpdatePWASettings.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updatePWASettings($settings: PWASettingsInput) {
  updatePWASettings(settings: $settings) {
    disablePrompt
  }
}

```


[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/admin/store/PWAForm/mutations/UpdateManifestIcon.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updateManifest($icon: Upload!, $iOS: Boolean) {
  updateManifestIcon(icon: $icon, iOS: $iOS) {
    icons {
      src
      type
      sizes
    }
  }
}

```


[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/admin/store/PWAForm/queries/PWA.graphql from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```graphql
query PWA {
  # Manifest
  manifest {
    start_url
    theme_color
    background_color
    display
    orientation
    icons {
      src
      type
      sizes
    }
  }
  iOSIcons {
    src
    type
    sizes
  }
  splashes {
    src
    type
    sizes
  }
  pwaSettings {
    disablePrompt
    promptOnCustomEvent
  }

  # Styles
  selectedStyle {
    config {
      semanticColors {
        background {
          base
        }
      }
    }
  }
}

```


[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/admin/store/PWAForm/utils/constants.ts from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface DropdownOption {
  value: string
  label: string
}

export const ORIENTATION_OPTIONS: DropdownOption[] = [
  {
    value: 'any',
    label: 'admin/pages.editor.store.settings.pwa.orientation.any',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.orientation.natural',
    value: 'natural',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.orientation.landscape',
    value: 'landscape',
  },
  {
    label:
      'admin/pages.editor.store.settings.pwa.orientation.landscape-primary',
    value: 'landscape-primary',
  },
  {
    label:
      'admin/pages.editor.store.settings.pwa.orientation.landscape-secondary',
    value: 'landscape-secondary',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.orientation.portrait',
    value: 'portrait',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.orientation.portrait-primary',
    value: 'portrait-primary',
  },
  {
    label:
      'admin/pages.editor.store.settings.pwa.orientation.portrait-secondary',
    value: 'portrait-secondary',
  },
]

export const DISPLAY_OPTIONS: DropdownOption[] = [
  {
    label: 'admin/pages.editor.store.settings.pwa.display.fullscreen',
    value: 'fullscreen',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.display.standalone',
    value: 'standalone',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.display.minimal-ui',
    value: 'minimal-ui',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.display.browser',
    value: 'browser',
  },
]

export const INSTALL_PROMPT_OPTIONS: DropdownOption[] = [
  {
    label: 'admin/pages.editor.store.settings.pwa.prompt-custom-event.default',
    value: 'default',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.prompt-custom-event.addToCart',
    value: 'addToCart',
  },
  {
    label: 'admin/pages.editor.store.settings.pwa.prompt-custom-event.checkout',
    value: 'checkout',
  }
]

export const TOAST_DURATION = 4000

```


[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/admin/store/PWAForm/components/withPWASettings.tsx from the admin-pages VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { pathOr } from 'ramda'
import React from 'react'
import { Query, QueryResult } from 'react-apollo'
import { defineMessages } from 'react-intl'

import { handleCornerCases } from '../../utils/utils'
import PWA from '../queries/PWA.graphql'

export interface PWAImage {
  src: string
  type: string
  sizes: string
}

export interface PWASettings {
  disablePrompt: boolean
  promptOnCustomEvent: string
}

export interface Manifest {
  icons?: PWAImage[]
  background_color: string
  theme_color: string
  orientation?: string
  start_url?: string
  display?: string
}

interface PWAData {
  manifest: Manifest
  iOSIcons: PWAImage[]
  splashes: PWAImage[]
  pwaSettings: PWASettings
  selectedStyle: {
    config: {
      semanticColors: {
        background: {
          base: string
        }
      }
    }
  }
}

export type PWASettingsProps = PWAData & Pick<QueryResult<PWAData>, 'refetch'>

class PWAQuery extends Query<PWAData, {}> {}

defineMessages({
  description: {
    defaultMessage: `Couldn't load store settings.`,
    id: 'admin/pages.editor.store.settings.error',
  },
  title: {
    defaultMessage: `Couldn't load PWA settings.`,
    id: 'admin/pages.editor.store.settings.pwa.error',
  },
})

const options = {
  error: {
    description: 'admin/pages.editor.store.settings.error.title',
    title: 'admin/pages.editor.store.settings.pwa.error',
  },
}

function withPWASettings<T>(
  WrappedComponent: React.ComponentType<T & PWASettingsProps>
) {
  const ComponentWithPWASettings = (props: T) => (
    <PWAQuery query={PWA}>
      {handleCornerCases<PWAData, {}>(options, ({ data, refetch }) => {
        if (
          !data.manifest ||
          !data.manifest.background_color ||
          !data.manifest.theme_color
        ) {
          const color: string = pathOr(
            '',
            ['selectedStyle', 'config', 'semanticColors', 'background', 'base'],
            data
          )

          return (
            <WrappedComponent
              {...props}
              {...data}
              manifest={{
                ...(data.manifest || {}),
                ['background_color']: color,
                ['theme_color']: color,
              }}
              refetch={refetch}
            />
          )
        }
        return <WrappedComponent {...props} {...data} refetch={refetch} />
      })}
    </PWAQuery>
  )

  return ComponentWithPWASettings
}

export default withPWASettings

```