[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 render-runtime/react/components/ExtensionPoint/LegacyExtensionContainer.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactPortal, FC, useState, useEffect, Fragment } from 'react'

import { createPortal } from '../../utils/dom'
import { getDirectChildren, useTreePath } from '../../utils/treePath'
import ExtensionPoint from '.'
import { useRuntime } from '../RenderContext'

interface Props {
  query: any
  params: any
}

const LegacyExtensionContainer: FC<Props> = ({ query, params }) => {
  const [hydrate, setHydrate] = useState(false)
  useEffect(() => {
    setHydrate(true)
  }, [])
  const { extensions } = useRuntime()
  const { treePath } = useTreePath()
  return (
    <Fragment>
      {getDirectChildren(extensions, treePath).map(
        (id) =>
          createPortal(
            <ExtensionPoint id={id} query={query} params={params} />,
            `${treePath}/${id}`,
            hydrate
          ) as ReactPortal
      )}
    </Fragment>
  )
}

export default LegacyExtensionContainer

```


[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 render-runtime/react/components/ExtensionPoint/SiteEditorWrapper.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import ReactDOM from 'react-dom'
import React from 'react'
import { getImplementation } from '../../utils/assets'
import { isSiteEditorIframe } from '../../utils/dom'
import type { RenderContext } from '../RenderContext'
import type { Extension } from '../../typings/runtime'

interface Props {
  component: string | null
  props: Record<string, any>
  treePath: string
  runtime: RenderContext
  hydration: Extension['hydration']
}

class SiteEditorWrapper extends React.Component<Props> {
  public componentDidMount() {
    this.addDataToElementIfEditable()
  }

  public componentDidUpdate() {
    this.addDataToElementIfEditable()
  }

  public componentWillUnmount() {
    this.removeDataFromElement()
  }

  private addDataToElementIfEditable = () => {
    const {
      component,
      treePath,
      runtime: {
        extensions: { [treePath]: extension },
      },
    } = this.props

    const ComponentImpl = component && getImplementation(component)

    const isEditable =
      extension?.hasContentSchema ||
      ComponentImpl?.hasOwnProperty('schema') ||
      ComponentImpl?.hasOwnProperty('getSchema')

    if (!isEditable) {
      return
    }

    // eslint-disable-next-line react/no-find-dom-node
    const element = ReactDOM.findDOMNode(this) as Element

    if (element && element.setAttribute) {
      element.setAttribute('data-extension-point', treePath)
    }
  }

  private removeDataFromElement = () => {
    if (!isSiteEditorIframe) {
      return
    }
    // eslint-disable-next-line react/no-find-dom-node
    const element = ReactDOM.findDOMNode(this) as Element

    if (element && element.removeAttribute) {
      element.removeAttribute('data-extension-point')
    }
  }

  public render() {
    return <>{this.props.children}</>
  }
}

export default SiteEditorWrapper

```


[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 render-runtime/react/components/Prefetch/PrefetchLink.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FunctionComponent, useRef, AnchorHTMLAttributes } from 'react'
import { usePrefetchAttempt } from '../../hooks/prefetch'
import { NavigateOptions } from '../../utils/pages'

interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
  waitToPrefetch?: number
  href: string
  page?: string
  options: NavigateOptions
}

const PrefetchLink: FunctionComponent<Props> = ({
  waitToPrefetch,
  children,
  onFocus,
  onMouseOver,
  options,
  page,
  ...linkElementProps
}) => {
  const { href } = linkElementProps
  const ref = useRef<HTMLAnchorElement | null>(null)

  const executePrefetch = usePrefetchAttempt({
    ref,
    page,
    href,
    options,
    waitToPrefetch,
  })

  return (
    <a
      ref={ref}
      {...linkElementProps}
      onMouseOver={(event) => {
        onMouseOver && onMouseOver(event)
        executePrefetch()
      }}
      onFocus={(event) => {
        onFocus && onFocus(event)
        executePrefetch()
      }}
    >
      {children}
    </a>
  )
}

export default PrefetchLink

```


[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 render-runtime/react/components/Prefetch/LRUCache.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
class Node<T> {
  public next: Node<T> | null
  public prev: Node<T> | null
  public key: string
  public value: T
  public time: number
  constructor(
    key: string,
    value: T,
    next: Node<T> | null = null,
    prev: Node<T> | null = null,
    time?: number
  ) {
    this.next = next
    this.value = value
    this.prev = prev
    this.key = key
    this.time = time ?? Date.now()
  }
}

interface Options {
  max?: number
  maxSize?: number
  maxAge?: number
  disposeFn?: (key: string) => void
}

class LRU<T> {
  private map: Map<string, Node<T>>
  private maxSize = Infinity
  private maxAge = 0
  private disposeFn: ((key: string) => void) | undefined

  private head: Node<T> | null = null
  private tail: Node<T> | null = null

  constructor(options: Options) {
    this.map = new Map() as Map<string, Node<T>>
    const n = typeof options === 'number'
    this.maxSize =
      (n ? (options as number) : options.max || options.maxSize) || Infinity
    this.maxAge = n ? 0 : options.maxAge || 0
    this.disposeFn = options.disposeFn
  }

  private isExpired(value: Node<T>) {
    if (this.maxAge <= 0) {
      return false
    }
    const expiration = Date.now() - this.maxAge
    return value.time < expiration
  }

  private ensureLimit() {
    if (this.map.size === this.maxSize && this.tail) {
      this.disposeFn && this.disposeFn(this.tail.key)
      this.remove(this.tail.key)
    }
  }

  private remove(key: string) {
    const node = this.map.get(key)
    if (!node) {
      return
    }
    if (node.prev !== null) {
      node.prev.next = node.next
    } else {
      this.head = node.next
    }

    if (node.next !== null) {
      node.next.prev = node.prev
    } else {
      this.tail = node.prev
    }

    this.map.delete(key)
  }

  public get(key: string) {
    const entry = this.map.get(key)
    if (entry && this.isExpired(entry)) {
      this.map.delete(key)
      this.disposeFn && this.disposeFn(key)
      return undefined
    }
    if (entry) {
      // node removed from it's position and cache
      this.remove(key)
      // write node again to the head of LinkedList to make it most recently used
      this.set(key, entry.value, entry.time)

      return entry.value
    }
    // console.log('teste ')
    return undefined
  }

  public has(key: string) {
    const entry = this.map.get(key)
    if (entry && this.isExpired(entry)) {
      this.map.delete(key)
      this.disposeFn && this.disposeFn(key)
      return false
    }
    return !!entry
  }

  public set(key: string, value: T, nodeTime?: number) {
    this.ensureLimit()

    if (!this.head) {
      //set new node to head and tail
      this.head = this.tail = new Node(key, value)
    } else {
      const node = new Node(key, value, this.head, null, nodeTime)
      //set new node to head
      this.head.prev = node
      this.head = node
    }

    this.map.set(key, this.head)
  }
}

export default LRU

```


[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 render-runtime/react/components/Prefetch/PQueue.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
type PromiseFn = () => Promise<any>

interface QueueObject {
  promise: PromiseFn
  priority: number
}

interface AddOptions {
  priority?: number
}

interface Options {
  concurrency?: number
  autoStart?: boolean
}

// Shifts the whole array in place one position to the right until a given index
function moveToRight<T>(array: T[], fromIndex: number) {
  for (let i = array.length - 1; i >= fromIndex; i--) {
    array[i + 1] = array[i]
  }
}

// Find first element where the given priority is bigger than it
// This could be a Binary Search if performance become an issue.
const findFirstSmallerElement = (array: QueueObject[], priority: number) => {
  return array.findIndex((obj) => priority > obj.priority)
}

class PQueue {
  queue: QueueObject[] = []
  concurrency = 0
  runningPromisesCount = 0
  isActive = true

  constructor(options?: Options) {
    this.concurrency = options?.concurrency ?? 0
    if (options?.autoStart === false) {
      this.isActive = false
    }
  }

  public pause() {
    this.isActive = false
  }
  public clear() {
    this.queue = []
    this.runningPromisesCount = 0
  }
  public add(promise: PromiseFn, options?: AddOptions) {
    if (!this.canStart()) {
      this.enqueue(promise, options)
      return
    }

    this.startPromise(promise)
  }
  public start() {
    this.isActive = true
    const diff =
      this.concurrency > 0
        ? this.concurrency - this.runningPromisesCount
        : this.queue.length
    if (diff <= 0 || this.queue.length === 0) {
      return
    }

    for (let i = 0; i < diff; i++) {
      this.dequeue()
    }
  }

  private isFull() {
    return this.concurrency > 0 && this.runningPromisesCount >= this.concurrency
  }

  private canStart() {
    return this.isActive && !this.isFull()
  }

  private startPromise(promise: PromiseFn) {
    this.runningPromisesCount += 1
    promise()
      .then(() => {
        this.runningPromisesCount -= 1
        this.dequeue()
      })
      .catch(() => {
        this.runningPromisesCount -= 1
        this.dequeue()
      })
  }

  private dequeue() {
    if (this.queue.length > 0 && this.canStart()) {
      const { promise } = this.queue.shift() as QueueObject
      this.startPromise(promise)
    }
  }

  private enqueue(promise: PromiseFn, options: AddOptions = {}) {
    const newItem = { promise, priority: options.priority ?? 0 }
    if (this.queue.length > 1) {
      const lastElem = this.queue[this.queue.length - 1]
      if (newItem.priority > lastElem.priority) {
        const correctPosition = findFirstSmallerElement(
          this.queue,
          newItem.priority
        )
        moveToRight(this.queue, correctPosition)
        this.queue[correctPosition] = newItem
        return
      }
    }

    this.queue.push(newItem)
  }
}

export default PQueue

```


[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 render-runtime/react/components/Prefetch/PrefetchContext.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, {
  useContext,
  createContext,
  FC,
  useEffect,
  useCallback,
  useRef,
  MutableRefObject,
} from 'react'
import LRUCache from './LRUCache'
import PQueue from './PQueue'
import { History, UnregisterCallback } from 'history'
import { useRuntime } from '../RenderContext'
import { isPrefetchEnabled } from '../../utils/routes'
import { RenderRuntime } from '../../typings/runtime'
import { PrefetchRouteData, ContentResponse } from '../../typings/global'

const MAX_CONCURRENCY = 5

const disposeFn = (key: string) => delete state.pathsState[key]

interface PathState {
  fetching: boolean
  page?: string | null
}

interface RoutePromise {
  promisePending: boolean
  promise: Promise<PrefetchRouteData> | null
}

interface PrefetchCacheObject {
  routeId: string
  matchingPage: RenderRuntime['route']
  contentResponse: ContentResponse | null
  queryData?: RenderRuntime['queryData']
}

export interface PrefetchState {
  routesCache: LRUCache<PrefetchRouteData>
  pathsCache: {
    other: LRUCache<PrefetchCacheObject>
    product: LRUCache<PrefetchCacheObject>
    search: LRUCache<PrefetchCacheObject>
  }
  pathsState: Record<string, PathState>
  routePromise: Record<string, RoutePromise | null>
  queue: PQueue
}

const HALF_HOUR_MS = 1000 * 60 * 30

const state: PrefetchState = {
  routesCache: new LRUCache({ max: 100, maxAge: HALF_HOUR_MS }),
  pathsCache: {
    product: new LRUCache({ max: 100, disposeFn, maxAge: HALF_HOUR_MS }),
    search: new LRUCache({ max: 75, disposeFn, maxAge: HALF_HOUR_MS }),
    other: new LRUCache({ max: 75, disposeFn, maxAge: HALF_HOUR_MS }),
  },
  pathsState: {},
  routePromise: {},
  queue: new PQueue({ autoStart: false, concurrency: MAX_CONCURRENCY }),
}

const PrefetchContext = createContext<PrefetchState>(state)

export const getCacheForPage = (page: string) => {
  if (page === 'store.product') {
    return state.pathsCache.product
  }

  if (page.startsWith('store.search')) {
    return state.pathsCache.search
  }

  return state.pathsCache.other
}

export const usePrefetch = () => useContext(PrefetchContext)

const getTimeout = (isMobile: boolean) => 3500 * (isMobile ? 2 : 1)

export const PrefetchContextProvider: FC<{ history: History<any> | null }> = ({
  children,
  history,
}) => {
  const { hints, getSettings } = useRuntime()
  const unlistenRef = useRef<UnregisterCallback>(null) as MutableRefObject<
    UnregisterCallback
  >

  const storeSettings = getSettings('vtex.store')

  const onPageChanged = useCallback(() => {
    state.queue.pause()
    state.queue.clear()
    setTimeout(() => {
      if (isPrefetchEnabled(storeSettings)) {
        state.queue.start()
      }
    }, 1000)
  }, [storeSettings])

  useEffect(() => {
    if (history) {
      unlistenRef.current = history.listen(onPageChanged)
    }

    if (isPrefetchEnabled(storeSettings)) {
      if (window?.document?.readyState === 'complete') {
        setTimeout(() => {
          state.queue.start()
        }, getTimeout(hints.mobile))
      } else {
        window?.document?.addEventListener(
          'load',
          () => {
            setTimeout(() => {
              state.queue.start()
            }, getTimeout(hints.mobile))
          },
          { once: true }
        )
      }
    }

    return () => {
      if (unlistenRef.current) {
        unlistenRef.current()
      }
    }
  }, [hints.mobile, history, onPageChanged, unlistenRef, storeSettings])

  return (
    <PrefetchContext.Provider value={state}>
      {children}
    </PrefetchContext.Provider>
  )
}

export const getPrefetechedData = (path: string) => {
  const destinationRouteId = state.pathsState[path]?.page
  if (!destinationRouteId) {
    return {
      routeData: null,
      prefetchedPathData: null,
      destinationRouteId: null,
    }
  }
  let prefetchedPathData = null
  const cache = getCacheForPage(destinationRouteId)
  prefetchedPathData = cache.get(path)

  const routeData = prefetchedPathData
    ? state.routesCache.get(destinationRouteId)
    : null
  return { routeData, prefetchedPathData, destinationRouteId }
}

export const clearQueue = () => {
  state.queue.clear()
}

```


[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 render-runtime/react/components/Preview/index.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactElement, RefObject } from 'react'

import Box from './Box'
import Circle from './Circle'
import Grid from './Grid'
import Spinner from './Spinner'
import Text from './Text'
import { Extension, PreviewDimension } from '../../typings/runtime'

interface Props {
  extension: Extension
}
interface State {
  containerWidth?: number | null
}

export const TEST_ID = 'loading-preview'

export default class Preview extends React.PureComponent<Props, State> {
  private container: RefObject<HTMLDivElement>

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

    this.container = React.createRef()
    this.state = {
      containerWidth: null,
    }
  }

  private renderPreviewGraphic = (
    width: number | string,
    height: number | string,
    type: string,
    options: any = {}
  ): ReactElement<any> | null => {
    if (!type || type === 'none') {
      return null
    }

    switch (type) {
      case 'box':
      /** TODO: deprecate block in favor of box */
      // eslint-disable-next-line no-fallthrough
      case 'block':
        return <Box width={width} height={height} />
      case 'text':
        return (
          <Text
            width={width}
            height={height}
            fontSize={options.fontSize}
            lineHeight={options.lineHeight}
          />
        )
      case 'grid':
        return <Grid width={width} height={height} />
      case 'circle':
        return <Circle width={width} height={height} />
      case 'spinner':
        return <Spinner width={width} height={height} />
      case 'transparent':
        return <div style={{ width, height }} />
      default:
        return null
    }
  }

  public componentDidMount() {
    /** Fixes a bug on react-content-loader related to limiting
     * the width of the component
     */
    const containerElement = this.container.current
    if (!containerElement) {
      return
    }

    this.setState({
      containerWidth: containerElement.offsetWidth,
    })
  }

  private getDimension = (dimension: PreviewDimension) => {
    if (typeof dimension === 'number') {
      return dimension
    }

    if (!dimension) {
      return null
    }

    const { extension } = this.props

    // TODO: support mobile
    const dimensionObject = dimension.desktop
    if (!dimensionObject) {
      return null
    }

    const { defaultValue } = dimensionObject

    const valueFromProp =
      dimensionObject.fromProp && extension.props[dimensionObject.fromProp]

    if (typeof valueFromProp === 'number') {
      return valueFromProp
    }

    return defaultValue
  }

  private getDimensions = () => {
    const { extension } = this.props

    if (!extension.preview) {
      return { width: null, height: null }
    }

    const { width, height } = extension.preview

    return {
      height: this.getDimension(height),
      width: this.getDimension(width),
    }
  }

  public render() {
    const { extension } = this.props

    if (!extension.preview) {
      return null
    }

    const { type, options = {}, fullWidth } = extension.preview

    const { width: initialWidth, height: initialHeight } = this.getDimensions()

    const { containerWidth } = this.state

    const maxWidth =
      containerWidth || (window && window.innerWidth) || initialWidth || 0

    const padding = options.padding == null ? 20 : options.padding
    const width = Math.max(
      (typeof initialWidth === 'number'
        ? Math.min(maxWidth, initialWidth)
        : maxWidth) -
        padding * 2,
      0
    )
    const height =
      initialHeight && initialHeight > padding * 2
        ? initialHeight - padding * 2
        : 0

    if (height === 0) {
      return null
    }

    return (
      /** TODO: remove this div in favor of the Container component,
       * currently on store-components
       * @author: lbebber
       */
      <div
        ref={this.container}
        className={fullWidth ? '' : 'mw9 center w-100'}
        data-testid={TEST_ID}
        style={{ padding }}
      >
        {this.renderPreviewGraphic(width || '100%', height, type, options)}
      </div>
    )
  }
}

```


[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 render-runtime/react/components/Preview/Circle.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'

interface Props {
  width: number | string
  height: number | string
}

const Circle = ({ width, height }: Props) => (
  <ContentLoader width={width} height={height}>
    <Rect width={width} height={height} borderRadius="100%" />
  </ContentLoader>
)

export default Circle

```


[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 render-runtime/react/components/Preview/Grid.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'
import Box from './Box'
import { useSSR } from '../../core/main'

interface Props {
  width: number | string
  height: number | string
}

const Grid = ({ width, height }: Props) => {
  const isSSR = useSSR()

  if (isSSR || typeof width === 'string' || typeof height === 'string') {
    return <Box width={width} height={height} />
  }

  // TODO: make these values configurable
  const itemWidth = 250
  const itemHeight = 400
  const minSpacingX = 10
  const minSpacingY = 30
  const itemsNumX = Math.floor(width / (itemWidth + minSpacingX))
  const itemsNumY = Math.floor(height / (itemHeight + minSpacingY))
  // distributes the remaining available space between each item of the grid
  const spacingX =
    (width - itemsNumX * itemWidth) / (itemsNumX > 1 ? itemsNumX - 1 : 2)
  const spacingY =
    (height - itemsNumY * itemHeight) / (itemsNumY > 1 ? itemsNumY - 1 : 2)

  return (
    <ContentLoader width={width} height={height}>
      {Array.from({ length: itemsNumX }).map((_, x) =>
        Array.from({ length: itemsNumY }).map((__, y) => (
          <Rect
            key={`${x}-${y}`}
            x={x * (itemWidth + spacingX)}
            y={y * (itemHeight + spacingY)}
            width={itemWidth}
            height={itemHeight}
          />
        ))
      )}
    </ContentLoader>
  )
}

export default Grid

```


[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 render-runtime/react/components/Preview/ContentLoader.css from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```css
@keyframes slide {
  0% {
    transform: translate3d(-50%, 0, 0);
  }
  100% {
    transform: translate3d(0, 0, 0);
  }
}

.slide {
  animation: slide 1.5s infinite linear;
}

```


[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 render-runtime/react/components/Preview/Box.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'

interface Props {
  width: number | string
  height: number | string
}

const Box = ({ width, height }: Props) => (
  <ContentLoader width={width} height={height}>
    <Rect x={0} y={0} width={width} height={height} />
  </ContentLoader>
)

export default Box

```


[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 render-runtime/react/components/Preview/ContentLoader.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FunctionComponent } from 'react'
import styles from './ContentLoader.css'

// TODO: make these colors dynamic, probably based on
// muted colors from the color theme
const PRIMARY_COLOR = '#e8e8e8'
const SECONDARY_COLOR = '#e0e0e0'

interface RectProps {
  x?: number
  y?: number
  width: number | string
  height: number | string
  preserveAspectRatio?: string
  borderRadius?: number | string
}

const Rect: FunctionComponent<RectProps> = ({
  x = 0,
  y = 0,
  width,
  height,
  borderRadius = 5,
}) => (
  <div
    style={{
      width,
      height,
      overflow: 'hidden',
      position: 'absolute',
      top: y,
      left: x,
      borderRadius,
    }}
  >
    <div
      className={styles.slide}
      style={{
        width: '300vw',
        height: '100%',
        position: 'relative',
        left: -x,
        backgroundColor: SECONDARY_COLOR,
        backgroundImage: `linear-gradient(90deg, ${SECONDARY_COLOR}, ${SECONDARY_COLOR} 50%, ${PRIMARY_COLOR} 60%, ${SECONDARY_COLOR} 65%, ${SECONDARY_COLOR})`,
        backgroundSize: '50% 100%',
        backgroundRepeat: 'repeat-x',
      }}
    />
  </div>
)

interface ContentLoaderProps {
  width: number | string
  height: number | string
}

const ContentLoader: FunctionComponent<ContentLoaderProps> = ({
  width,
  height,
  children,
}) => (
  <div style={{ width, height, position: 'relative' }} suppressHydrationWarning>
    {children}
  </div>
)

export { ContentLoader, Rect }

```


[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 render-runtime/react/components/Preview/GenericPreview.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import Box from './Box'

const GenericPreview = () => {
  const padding = 20
  const height = (window && window.innerHeight) || 1400

  return (
    <div className="center w-100 mw9" style={{ padding }}>
      <Box height={height} width="100%" />
    </div>
  )
}

export default GenericPreview

```


[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 render-runtime/react/components/Preview/Text.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'
import Box from './Box'

interface Props {
  width: number | string
  height: number | string
  lineHeight?: number
  fontSize?: number
}

const Text = ({ width, height, fontSize = 16, lineHeight = 1.5 }: Props) => {
  // Height needs to be a value in pixels in order to be able to split it properly into lines.
  // Falls back to `Box` if it's e.g. `100%`
  if (typeof height === 'string') {
    return <Box width={width} height={height} />
  }

  // TODO: make the line height configurable
  const lineSize = fontSize * lineHeight
  const lines = Math.round(height / lineSize)

  return (
    <ContentLoader width={width} height={height}>
      {Array.from({ length: lines }).map((_, i) => {
        const lineWidth = width
        return (
          <Rect
            key={i}
            x={0}
            y={Math.round(i * lineSize)}
            width={lineWidth}
            height={fontSize}
          />
        )
      })}
    </ContentLoader>
  )
}

export default Text

```


[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 render-runtime/react/components/Preview/Spinner.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface Props {
  width: number | string
  height: number | string
}

const Spinner = ({ width, height }: Props) => (
  <div className="flex items-center justify-center" style={{ width, height }}>
    <svg
      width="26px"
      height="26px"
      viewBox="0 0 100 100"
      preserveAspectRatio="xMidYMid"
      xmlns="http://www.w3.org/2000/svg"
      xmlnsXlink="http://www.w3.org/1999/xlink"
    >
      <use xlinkHref="#sti-loading" />
    </svg>
  </div>
)

export default Spinner

```


[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 render-runtime/react/components/ErrorPage/ErrorIcon.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

export default function ErrorIcon() {
  return (
    <svg
      width="160"
      height="160"
      viewBox="0 0 160 160"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <g clipPath="url(#clip0_514_6551)">
        <path
          d="M80 140C113.137 140 140 113.137 140 80C140 46.8629 113.137 20 80 20C46.8629 20 20 46.8629 20 80C20 113.137 46.8629 140 80 140Z"
          stroke="#EBEBEB"
          strokeWidth="16"
          strokeLinecap="round"
          strokeLinejoin="round"
        />
        <path
          d="M80 51V86"
          stroke="#EBEBEB"
          strokeWidth="16"
          strokeLinecap="round"
          strokeLinejoin="round"
        />
        <path
          d="M80 116C84.4183 116 88 112.418 88 108C88 103.582 84.4183 100 80 100C75.5817 100 72 103.582 72 108C72 112.418 75.5817 116 80 116Z"
          fill="#EBEBEB"
        />
      </g>
      <defs>
        <clipPath id="clip0_514_6551">
          <rect width="160" height="160" fill="white" />
        </clipPath>
      </defs>
    </svg>
  )
}

```


[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 render-runtime/react/components/ErrorPage/shoreline.css from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```css
@layer sl-tokens {
  :root {
    --sl-space-0: 0rem;
    --sl-space-1: 0.25rem;
    --sl-space-2: 0.5rem;
    --sl-space-3: 0.75rem;
    --sl-space-4: 1rem;
    --sl-space-5: 1.25rem;
    --sl-space-6: 1.5rem;
    --sl-space-7: 1.75rem;
    --sl-space-8: 2rem;
    --sl-space-10: 2.5rem;
    --sl-space-12: 3rem;
    --sl-space-16: 4rem;
    --sl-space-20: 5rem;
    --sl-space-24: 6rem;
    --sl-space-28: 7rem;
    --sl-space-32: 8rem;
    --sl-space-05: 0.125rem;
    --sl-space-gap: var(--sl-space-4);
    --sl-color-gray-0: #fff;
    --sl-color-gray-1: #f5f5f5;
    --sl-color-gray-2: #ebebeb;
    --sl-color-gray-3: #e0e0e0;
    --sl-color-gray-4: #d6d6d6;
    --sl-color-gray-5: #c2c2c2;
    --sl-color-gray-6: #adadad;
    --sl-color-gray-7: #999;
    --sl-color-gray-8: #858585;
    --sl-color-gray-9: #707070;
    --sl-color-gray-10: #5c5c5c;
    --sl-color-gray-11: #3d3d3d;
    --sl-color-gray-12: #1f1f1f;
    --sl-color-gray-13: #000;
    --sl-color-red-1: #fdf6f5;
    --sl-color-red-2: #ffedea;
    --sl-color-red-3: #ffdfd9;
    --sl-color-red-4: #ffd0c7;
    --sl-color-red-5: #ffbbad;
    --sl-color-red-6: #ff9e8b;
    --sl-color-red-7: #ff7f68;
    --sl-color-red-8: #f95d47;
    --sl-color-red-9: #ec3727;
    --sl-color-red-10: #d31a15;
    --sl-color-red-11: #b40202;
    --sl-color-red-12: #940303;
    --sl-color-red-13: #720000;
    --sl-color-orange-1: #fdf5e9;
    --sl-color-orange-2: #ffedcd;
    --sl-color-orange-3: #ffe0ae;
    --sl-color-orange-4: #fed392;
    --sl-color-orange-5: #febc64;
    --sl-color-orange-6: #ffa138;
    --sl-color-orange-7: #f78612;
    --sl-color-orange-8: #e57001;
    --sl-color-orange-9: #cc5e01;
    --sl-color-orange-10: #b24d01;
    --sl-color-orange-11: #963e01;
    --sl-color-orange-12: #7b3001;
    --sl-color-orange-13: #622401;
    --sl-color-yellow-1: #fbf7d4;
    --sl-color-yellow-2: #fdf5ad;
    --sl-color-yellow-3: #faec6d;
    --sl-color-yellow-4: #fade1e;
    --sl-color-yellow-5: #e9c701;
    --sl-color-yellow-6: #d8b401;
    --sl-color-yellow-7: #c5a001;
    --sl-color-yellow-8: #b18d01;
    --sl-color-yellow-9: #9c7901;
    --sl-color-yellow-10: #866701;
    --sl-color-yellow-11: #715401;
    --sl-color-yellow-12: #5c4401;
    --sl-color-yellow-13: #493401;
    --sl-color-green-1: #e9fce3;
    --sl-color-green-2: #cefdc0;
    --sl-color-green-3: #aff79e;
    --sl-color-green-4: #97ef86;
    --sl-color-green-5: #74e26c;
    --sl-color-green-6: #4fd051;
    --sl-color-green-7: #28bc37;
    --sl-color-green-8: #08a822;
    --sl-color-green-9: #019213;
    --sl-color-green-10: #017d10;
    --sl-color-green-11: #016810;
    --sl-color-green-12: #01540e;
    --sl-color-green-13: #01410b;
    --sl-color-teal-1: #e9faf8;
    --sl-color-teal-2: #cff8f4;
    --sl-color-teal-3: #abf2eb;
    --sl-color-teal-4: #8deae3;
    --sl-color-teal-5: #66dbd3;
    --sl-color-teal-6: #40cac2;
    --sl-color-teal-7: #10b6af;
    --sl-color-teal-8: #01a29b;
    --sl-color-teal-9: #018d88;
    --sl-color-teal-10: #017873;
    --sl-color-teal-11: #016460;
    --sl-color-teal-12: #0d504d;
    --sl-color-teal-13: #133d3b;
    --sl-color-blue-1: #f1f8fd;
    --sl-color-blue-2: #e1f3ff;
    --sl-color-blue-3: #cbe9ff;
    --sl-color-blue-4: #b6dfff;
    --sl-color-blue-5: #97cffe;
    --sl-color-blue-6: #79bcfb;
    --sl-color-blue-7: #5aa8f7;
    --sl-color-blue-8: #3993f4;
    --sl-color-blue-9: #157bf4;
    --sl-color-blue-10: #0366dd;
    --sl-color-blue-11: #0155b7;
    --sl-color-blue-12: #014592;
    --sl-color-blue-13: #013672;
    --sl-color-purple-1: #f9f5fd;
    --sl-color-purple-2: #f5eafe;
    --sl-color-purple-3: #eddcfe;
    --sl-color-purple-4: #e5cffe;
    --sl-color-purple-5: #dabafd;
    --sl-color-purple-6: #cba3fc;
    --sl-color-purple-7: #bc8afb;
    --sl-color-purple-8: #ad71f8;
    --sl-color-purple-9: #9c56f3;
    --sl-color-purple-10: #883ce6;
    --sl-color-purple-11: #7225d2;
    --sl-color-purple-12: #5c12b6;
    --sl-color-purple-13: #460b93;
    --sl-color-pink-1: #fdf5f7;
    --sl-color-pink-2: #ffebf2;
    --sl-color-pink-3: #ffdfeb;
    --sl-color-pink-4: #ffc8dc;
    --sl-color-pink-5: #feb2cd;
    --sl-color-pink-6: #ff98bf;
    --sl-color-pink-7: #fe78ac;
    --sl-color-pink-8: #ef5997;
    --sl-color-pink-9: #de387f;
    --sl-color-pink-10: #ca226a;
    --sl-color-pink-11: #af0956;
    --sl-color-pink-12: #8f0246;
    --sl-color-pink-13: #74043b;
    --sl-color-cyan-1: #e6fafd;
    --sl-color-cyan-2: #c6f9ff;
    --sl-color-cyan-3: #a5f1ff;
    --sl-color-cyan-4: #89e8fb;
    --sl-color-cyan-5: #61d9f4;
    --sl-color-cyan-6: #34c6e9;
    --sl-color-cyan-7: #13b1db;
    --sl-color-cyan-8: #029dc9;
    --sl-color-cyan-9: #0187b5;
    --sl-color-cyan-10: #0172a0;
    --sl-color-cyan-11: #015e8a;
    --sl-color-cyan-12: #014b74;
    --sl-color-cyan-13: #013a5e;
    --sl-fg-base: var(--sl-color-gray-12);
    --sl-fg-base-soft: var(--sl-color-gray-9);
    --sl-fg-base-disabled: var(--sl-color-gray-7);
    --sl-fg-inverted: var(--sl-color-gray-0);
    --sl-fg-warning: var(--sl-color-yellow-9);
    --sl-fg-success: var(--sl-color-green-9);
    --sl-fg-informational: var(--sl-color-blue-9);
    --sl-fg-muted: var(--sl-color-gray-11);
    --sl-fg-muted-hover: var(--sl-color-gray-12);
    --sl-fg-muted-pressed: var(--sl-color-gray-13);
    --sl-fg-accent: var(--sl-color-blue-10);
    --sl-fg-accent-hover: var(--sl-color-blue-11);
    --sl-fg-accent-pressed: var(--sl-color-blue-12);
    --sl-fg-critical: var(--sl-color-red-10);
    --sl-fg-critical-hover: var(--sl-color-red-11);
    --sl-fg-critical-pressed: var(--sl-color-red-12);
    --sl-bg-base: var(--sl-color-gray-0);
    --sl-bg-base-disabled: color-mix(
      in srgb,
      var(--sl-color-gray-12) 5%,
      transparent
    );
    --sl-bg-base-strong: var(--sl-color-gray-3);
    --sl-bg-base-strong-disabled: var(--sl-color-gray-6);
    --sl-bg-base-soft: var(--sl-color-gray-1);
    --sl-bg-warning: var(--sl-color-yellow-1);
    --sl-bg-success: var(--sl-color-green-1);
    --sl-bg-informational: var(--sl-color-blue-1);
    --sl-bg-inverted: var(--sl-color-gray-12);
    --sl-bg-inverted-strong: color-mix(
      in srgb,
      var(--sl-color-gray-12) 50%,
      transparent
    );
    --sl-bg-muted: color-mix(in srgb, var(--sl-color-gray-12) 5%, transparent);
    --sl-bg-muted-hover: color-mix(
      in srgb,
      var(--sl-color-gray-12) 10%,
      transparent
    );
    --sl-bg-muted-pressed: color-mix(
      in srgb,
      var(--sl-color-gray-12) 15%,
      transparent
    );
    --sl-bg-muted-plain: color-mix(
      in srgb,
      var(--sl-color-gray-12) 0%,
      transparent
    );
    --sl-bg-muted-plain-hover: color-mix(
      in srgb,
      var(--sl-color-gray-12) 5%,
      transparent
    );
    --sl-bg-muted-plain-pressed: color-mix(
      in srgb,
      var(--sl-color-gray-12) 10%,
      transparent
    );
    --sl-bg-accent: var(--sl-color-blue-2);
    --sl-bg-accent-hover: var(--sl-color-blue-3);
    --sl-bg-accent-pressed: var(--sl-color-blue-4);
    --sl-bg-accent-plain: color-mix(
      in srgb,
      var(--sl-color-blue-10) 0%,
      transparent
    );
    --sl-bg-accent-plain-hover: color-mix(
      in srgb,
      var(--sl-color-blue-10) 5%,
      transparent
    );
    --sl-bg-accent-plain-pressed: color-mix(
      in srgb,
      var(--sl-color-blue-10) 10%,
      transparent
    );
    --sl-bg-accent-strong: var(--sl-color-blue-10);
    --sl-bg-accent-strong-hover: var(--sl-color-blue-11);
    --sl-bg-accent-strong-pressed: var(--sl-color-blue-12);
    --sl-bg-critical: var(--sl-color-red-1);
    --sl-bg-critical-plain: color-mix(
      in srgb,
      var(--sl-color-red-10) 0%,
      transparent
    );
    --sl-bg-critical-plain-hover: color-mix(
      in srgb,
      var(--sl-color-red-10) 5%,
      transparent
    );
    --sl-bg-critical-plain-pressed: color-mix(
      in srgb,
      var(--sl-color-red-10) 10%,
      transparent
    );
    --sl-bg-critical-strong: var(--sl-color-red-10);
    --sl-bg-critical-strong-hover: var(--sl-color-red-11);
    --sl-bg-critical-strong-pressed: var(--sl-color-red-12);
    --sl-border-base: 1px solid var(--sl-color-gray-3);
    --sl-border-base-disabled: 1px solid var(--sl-color-gray-6);
    --sl-border-base-strong: 1px solid var(--sl-color-gray-5);
    --sl-border-base-strong-hover: 1px solid var(--sl-color-gray-6);
    --sl-border-success: 1px solid var(--sl-color-green-3);
    --sl-border-informational: 1px solid var(--sl-color-blue-3);
    --sl-border-warning: 1px solid var(--sl-color-yellow-3);
    --sl-border-accent: 1px solid var(--sl-color-blue-3);
    --sl-border-accent-strong: 1px solid var(--sl-color-blue-10);
    --sl-border-accent-strong-hover: 1px solid var(--sl-color-blue-11);
    --sl-border-critical: 1px solid var(--sl-color-red-3);
    --sl-border-critical-strong: 1px solid var(--sl-color-red-8);
    --sl-border-critical-strong-hover: 1px solid var(--sl-color-red-9);
    --sl-radius-0: 0rem;
    --sl-radius-1: 0.25rem;
    --sl-radius-2: 0.5rem;
    --sl-radius-3: 0.75rem;
    --sl-radius-full: 9999rem;
    --sl-focus-ring-base: 0rem 0rem 0rem 0.0625rem var(--sl-color-gray-0),
      0rem 0rem 0rem 0.1875rem var(--sl-color-gray-5);
    --sl-focus-ring-critical: 0rem 0rem 0rem 0.0625rem var(--sl-color-gray-0),
      0rem 0rem 0rem 0.1875rem var(--sl-color-red-6);
    --sl-focus-ring-accent: 0rem 0rem 0rem 0.0625rem var(--sl-color-gray-0),
      0rem 0rem 0rem 0.1875rem var(--sl-color-blue-6);
    --sl-shadow-1: 0rem 0.25rem 1rem 0rem rgba(0, 0, 0, 0.16);
    --sl-shadow-2: 0rem 1.5rem 3rem 0rem rgba(0, 0, 0, 0.16);
    --sl-z-1: 0;
    --sl-z-2: 100;
    --sl-z-3: 200;
    --sl-z-4: 300;
    --sl-z-5: 400;
    --sl-z-6: 500;
    --sl-z-7: 600;
    --sl-z-8: 700;
    --sl-z-9: 800;
    --sl-z-10: 900;
    --sl-font-family-sans: 'Inter', -apple-system, system-ui, -apple-system,
      Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif,
      BlinkMacSystemFont, sans-serif;
    --sl-font-weight-regular: 400;
    --sl-font-weight-medium: 500;
    --sl-font-weight-semibold: 600;
    --sl-font-size-1: 0.75rem;
    --sl-font-size-2: 0.875rem;
    --sl-font-size-3: 1rem;
    --sl-font-size-4: 1.25rem;
    --sl-font-size-5: 1.5rem;
    --sl-letter-spacing-1: 0rem;
    --sl-letter-spacing-2: -0.00875rem;
    --sl-letter-spacing-3: -0.02rem;
    --sl-letter-spacing-4: -0.04rem;
    --sl-line-height-1: 1rem;
    --sl-line-height-2: 1.25rem;
    --sl-line-height-3: 1.5rem;
    --sl-line-height-4: 1.75rem;
    --sl-line-height-5: 2rem;
    --sl-text-caption-1-font: var(--sl-font-weight-medium) var(--sl-font-size-1) /
      var(--sl-line-height-1) var(--sl-font-family-sans);
    --sl-text-caption-1-letter-spacing: var(--sl-letter-spacing-1);
    --sl-text-caption-2-font: var(--sl-font-weight-regular)
      var(--sl-font-size-1) / var(--sl-line-height-1) var(--sl-font-family-sans);
    --sl-text-caption-2-letter-spacing: var(--sl-letter-spacing-1);
    --sl-text-action-font: var(--sl-font-weight-semibold) var(--sl-font-size-2) /
      var(--sl-line-height-2) var(--sl-font-family-sans);
    --sl-text-action-letter-spacing: var(--sl-letter-spacing-2);
    --sl-text-emphasis-font: var(--sl-font-weight-medium) var(--sl-font-size-2) /
      var(--sl-line-height-2) var(--sl-font-family-sans);
    --sl-text-emphasis-letter-spacing: var(--sl-letter-spacing-2);
    --sl-text-body-font: var(--sl-font-weight-regular) var(--sl-font-size-2) /
      var(--sl-line-height-2) var(--sl-font-family-sans);
    --sl-text-body-letter-spacing: var(--sl-letter-spacing-2);
    --sl-text-display-1-font: var(--sl-font-weight-semibold)
      var(--sl-font-size-5) / var(--sl-line-height-5) var(--sl-font-family-sans);
    --sl-text-display-1-letter-spacing: var(--sl-letter-spacing-4);
    --sl-text-display-2-font: var(--sl-font-weight-semibold)
      var(--sl-font-size-4) / var(--sl-line-height-4) var(--sl-font-family-sans);
    --sl-text-display-2-letter-spacing: var(--sl-letter-spacing-4);
    --sl-text-display-3-font: var(--sl-font-weight-semibold)
      var(--sl-font-size-3) / var(--sl-line-height-3) var(--sl-font-family-sans);
    --sl-text-display-3-letter-spacing: var(--sl-letter-spacing-3);
    --sl-text-display-4-font: var(--sl-font-weight-regular)
      var(--sl-font-size-3) / var(--sl-line-height-3) var(--sl-font-family-sans);
    --sl-text-display-4-letter-spacing: var(--sl-letter-spacing-3);
  }
}

[data-sl-text] {
  overflow-wrap: break-word;
  text-wrap: pretty;
}

[data-sl-text][data-variant='body'] {
  font: var(--sl-text-body-font);
  letter-spacing: var(--sl-text-body-letter-spacing);
}

[data-sl-text][data-variant='action'] {
  font: var(--sl-text-action-font);
  letter-spacing: var(--sl-text-action-letter-spacing);
}

[data-sl-text][data-variant='emphasis'] {
  font: var(--sl-text-emphasis-font);
  letter-spacing: var(--sl-text-emphasis-letter-spacing);
}

[data-sl-text][data-variant='caption1'] {
  font: var(--sl-text-caption-1-font);
  letter-spacing: var(--sl-text-caption-1-letter-spacing);
}

[data-sl-text][data-variant='caption2'] {
  font: var(--sl-text-caption-2-font);
  letter-spacing: var(--sl-text-caption-2-letter-spacing);
}

[data-sl-text][data-variant='display1'] {
  font: var(--sl-text-display-1-font);
  letter-spacing: var(--sl-text-display-1-letter-spacing);
}

[data-sl-text][data-variant='display2'] {
  font: var(--sl-text-display-2-font);
  letter-spacing: var(--sl-text-display-2-letter-spacing);
}

[data-sl-text][data-variant='display3'] {
  font: var(--sl-text-display-3-font);
  letter-spacing: var(--sl-text-display-3-letter-spacing);
}

[data-sl-text][data-variant='display4'] {
  font: var(--sl-text-display-4-font);
  letter-spacing: var(--sl-text-display-4-letter-spacing);
}

@keyframes sl-animation-dash {
  0% {
    stroke-dasharray: 1 150;
    stroke-dashoffset: 0;
  }

  50% {
    stroke-dasharray: 90 150;
    stroke-dashoffset: -35px;
  }

  100% {
    stroke-dasharray: 90 150;
    stroke-dashoffset: -124px;
  }
}

@keyframes sl-animation-rotate {
  100% {
    transform: rotate(360deg);
  }
}

[data-sl-spinner] > svg {
  animation: 1.5s linear infinite sl-animation-rotate;
}

[data-sl-spinner] > svg > circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 5px;
  stroke-linecap: round;
  animation: 1s ease-in-out infinite sl-animation-dash;
}

[data-sl-button] {
  padding: var(--sl-element-space-top) var(--sl-element-space-right)
    var(--sl-element-space-bottom) var(--sl-element-space-left);
  height: var(--sl-element-height);
  border-radius: var(--sl-radius-2);
  font: var(--sl-text-action-font);
  letter-spacing: var(--sl-text-action-letter-spacing);
  cursor: pointer;
  -ms-appearance: button;
  appearance: button;
  border: none;
  text-decoration: none;
  position: relative;
}

[data-sl-button]:focus {
  outline: none;
}

[data-sl-button] > [data-sl-button-content] {
  font: inherit;
  letter-spacing: inherit;
  gap: var(--sl-space-1);
  opacity: 1;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  width: 100%;
  transition: opacity 0.3s;
  display: flex;
}

[data-sl-button] > [data-sl-button-content] [data-sl-icon]:first-child {
  margin-left: calc(var(--sl-space-1) * -1);
}

[data-sl-button] > [data-sl-button-content] [data-sl-icon-small]:first-child {
  margin-left: calc(var(--sl-space-1) * -1);
}

[data-sl-button] > [data-sl-button-content] [data-sl-icon]:last-child {
  margin-left: calc(var(--sl-space-05) * -1);
}

[data-sl-button] > [data-sl-button-content] [data-sl-icon-small]:last-child {
  margin-left: calc(var(--sl-space-05) * -1);
}

[data-sl-button] > [data-sl-button-overlay] {
  color: inherit;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

[data-sl-button][data-loading='true'] > [data-sl-button-content] {
  opacity: 0;
}

[data-sl-button][data-size='normal'] {
  --sl-element-space-top: var(--sl-space-2);
  --sl-element-space-bottom: var(--sl-space-2);
  --sl-element-space-right: var(--sl-space-3);
  --sl-element-space-left: var(--sl-space-3);
  --sl-element-height: 2.25rem;
}

[data-sl-button][data-size='large'] {
  --sl-element-space-top: var(--sl-space-3);
  --sl-element-space-bottom: var(--sl-space-3);
  --sl-element-space-right: var(--sl-space-4);
  --sl-element-space-left: var(--sl-space-4);
  --sl-element-height: 2.75rem;
}

[data-sl-button][data-variant='secondary'] {
  background: var(--sl-bg-muted);
  color: var(--sl-fg-muted);
}

[data-sl-button][data-variant='secondary']:hover {
  background: var(--sl-bg-muted-hover);
  color: var(--sl-fg-muted-hover);
}

[data-sl-button][data-variant='secondary']:active {
  background: var(--sl-bg-muted-pressed);
  color: var(--sl-fg-muted-pressed);
}

[data-sl-button][data-variant='secondary']:focus-visible {
  box-shadow: var(--sl-focus-ring-base);
  background: var(--sl-bg-muted-hover);
  color: var(--sl-fg-muted-hover);
}

[data-sl-button][data-variant='secondary']:disabled {
  background: var(--sl-bg-base-disabled);
  color: var(--sl-fg-base-disabled);
}

[data-sl-button][data-variant='secondary']:disabled > [data-sl-button-overlay] {
  color: var(--sl-fg-base-soft);
}

[data-sl-button][data-variant='tertiary'] {
  background: var(--sl-bg-muted-plain);
  color: var(--sl-fg-muted);
}

[data-sl-button][data-variant='tertiary']:hover {
  background: var(--sl-bg-muted-plain-hover);
  color: var(--sl-fg-muted-hover);
}

[data-sl-button][data-variant='tertiary']:active {
  background: var(--sl-bg-muted-plain-pressed);
  color: var(--sl-fg-muted-pressed);
}

[data-sl-button][data-variant='tertiary']:focus-visible {
  box-shadow: var(--sl-focus-ring-base);
  background: var(--sl-bg-muted-plain-hover);
  color: var(--sl-fg-muted-hover);
}

[data-sl-button][data-variant='tertiary']:disabled {
  color: var(--sl-fg-base-disabled);
  background: none;
}

[data-sl-button][data-variant='tertiary']:disabled > [data-sl-button-overlay] {
  color: var(--sl-fg-base-soft);
}

[data-sl-button][data-variant='primary'] {
  background: var(--sl-bg-accent-strong);
  color: var(--sl-fg-inverted);
}

[data-sl-button][data-variant='primary']:hover {
  background: var(--sl-bg-accent-strong-hover);
}

[data-sl-button][data-variant='primary']:active {
  background: var(--sl-bg-accent-strong-pressed);
}

[data-sl-button][data-variant='primary']:focus-visible {
  box-shadow: var(--sl-focus-ring-accent);
}

[data-sl-button][data-variant='primary']:disabled {
  background: var(--sl-bg-base-strong-disabled);
}

[data-sl-button][data-variant='critical'] {
  background: var(--sl-bg-critical-strong);
  color: var(--sl-fg-inverted);
}

[data-sl-button][data-variant='critical']:hover {
  background: var(--sl-bg-critical-strong-hover);
}

[data-sl-button][data-variant='critical']:active {
  background: var(--sl-bg-critical-strong-pressed);
}

[data-sl-button][data-variant='critical']:focus-visible {
  box-shadow: var(--sl-focus-ring-critical);
  background: var(--sl-bg-critical-strong-hover);
}

[data-sl-button][data-variant='critical']:disabled {
  background: var(--sl-bg-base-strong-disabled);
}

[data-sl-button][data-variant='criticalTertiary'] {
  background: var(--sl-bg-critical-plain);
  color: var(--sl-fg-critical);
}

[data-sl-button][data-variant='criticalTertiary']:hover {
  background: var(--sl-bg-critical-plain-hover);
  color: var(--sl-fg-critical-hover);
}

[data-sl-button][data-variant='criticalTertiary']:active {
  background: var(--sl-bg-critical-plain-pressed);
  color: var(--sl-fg-critical-pressed);
}

[data-sl-button][data-variant='criticalTertiary']:focus-visible {
  box-shadow: var(--sl-focus-ring-critical);
  background: var(--sl-bg-critical-plain-hover);
  color: var(--sl-fg-critical-hover);
}

[data-sl-button][data-variant='criticalTertiary']:disabled {
  color: var(--sl-fg-base-disabled);
  background: none;
}

[data-sl-button][data-variant='criticalTertiary']:disabled
  > [data-sl-button-overlay] {
  color: var(--sl-fg-base-soft);
}

```


[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 render-runtime/react/components/ErrorPage/RefreshCounter.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useMemo, useState } from 'react'
import styles from './error-page.module.css'
import { useIntl } from 'react-intl'

const EXPIRATION_TIME = 10 * 60 * 1000 // 10 minutes in milliseconds

function RefreshCounter() {
  const [counter, setCounter] = useState<number>(10)
  const { formatMessage } = useIntl()

  const lastRefreshTime = useMemo(
    () => (localStorage.getItem('lastRefreshTime') || 0) as number,
    []
  )
  const currentTime = useMemo(() => new Date().getTime(), [])
  const shouldRefresh = useMemo(
    () => !lastRefreshTime || currentTime - lastRefreshTime > EXPIRATION_TIME,
    [currentTime, lastRefreshTime]
  )

  useEffect(() => {
    if (counter > 0) {
      const timer = setInterval(
        () => setCounter((prevCounter) => prevCounter - 1),
        1000
      )
      return () => clearInterval(timer)
    } else if (shouldRefresh) {
      localStorage.setItem(
        'lastRefreshTime',
        (currentTime as unknown) as string
      )

      window.location.reload()
    }
    return
  }, [counter, currentTime, shouldRefresh])

  if (!shouldRefresh) return null

  return (
    <div data-sl-text data-variant="caption1" className={styles.counter}>
      <div data-sl-spinner>
        <svg viewBox="0 0 50 50" width={16} height={16}>
          <circle cx={25} cy={25} r={20} />
        </svg>
      </div>

      {formatMessage({ id: 'render-runtime.error.counter' }, { counter })}
    </div>
  )
}

export default RefreshCounter

```


[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 render-runtime/react/components/ErrorPage/ErrorPage.tsx from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import './shoreline.css'

import styles from './error-page.module.css'
import ErrorIcon from './ErrorIcon'
import RefreshCounter from './RefreshCounter'
import { useIntl } from 'react-intl'

export default function ErrorPage({ errorCode }: { errorCode?: string }) {
  const { formatMessage, formatDate } = useIntl()
  const date = new Date()

  return (
    <div className={styles.layout}>
      <div className={styles.errorDetailsLayout}>
        <ErrorIcon />
        <div data-sl-text data-variant="display1" className={styles.title}>
          {formatMessage({ id: 'render-runtime.error.title' })}
        </div>
        <div data-sl-text data-variant="body" className={styles.description}>
          {formatMessage({ id: 'render-runtime.error.description' })}
        </div>
        {errorCode ? (
          <div
            data-sl-text
            data-variant="caption2"
            className={styles.errorCode}
          >
            {formatMessage({ id: 'render-runtime.error.error-id' })}:{' '}
            {errorCode}
            <br />
            {formatMessage({ id: 'render-runtime.error.error-date' })}:{' '}
            {formatDate(date, {
              day: '2-digit',
              month: 'short',
              year: 'numeric',
              hour: '2-digit',
              minute: '2-digit',
              timeZoneName: 'short',
            })}
          </div>
        ) : null}
        <button
          data-sl-button
          data-variant="primary"
          data-size="normal"
          className={styles.retryButton}
          onClick={() => window.location.reload()}
        >
          {formatMessage({ id: 'render-runtime.error.action.retry' })}
        </button>
        <RefreshCounter />
      </div>
    </div>
  )
}

```


[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 render-runtime/react/components/ErrorPage/error-page.module.css from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```css
.layout {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh;
  justify-content: center;
  align-items: center;
  text-align: center;
}

/* mobile media query */
@media only screen and (max-width: 768px) {
  .layout {
    padding: var(--sl-space-0) var(--sl-space-5);
  }
}

.errorDetailsLayout {
  max-width: 26.25rem;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.title {
  margin-top: var(--sl-space-10);
}

.description {
  margin-top: var(--sl-space-3);
}

.errorCode {
  margin-top: var(--sl-space-10);
  color: var(--sl-fg-base-soft);
}

.retryButton {
  margin-top: var(--sl-space-12);
  min-width: 7.5rem;
}

.counter {
  display: flex;
  gap: var(--sl-space-3);
  margin-top: var(--sl-space-24);
  color: var(--sl-fg-informational);
}

```


[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 render-runtime/react/components/ErrorPage/messages/nl.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Er is iets fout gegaan",
  "render-runtime.error.description": "We konden geen verbinding maken met de server. Als het probleem zich blijft voordoen, neem dan contact op met VTEX Support.",
  "render-runtime.error.error-id": "Id",
  "render-runtime.error.error-date": "Datum",
  "render-runtime.error.action.retry": "Probeer opnieuw",
  "render-runtime.error.counter": "Automatisch opnieuw proberen in {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/ja.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "エラーあり",
  "render-runtime.error.description": "サーバーに接続できませんでした。問題が解決しない場合、VTEX サポートにお問い合わせください。",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "日付",
  "render-runtime.error.action.retry": "もう一度やり直す",
  "render-runtime.error.counter": "{counter} で自動的にリトライ…"
}

```


[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 render-runtime/react/components/ErrorPage/messages/de.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Etwas ist schief gelaufen",
  "render-runtime.error.description": "Wir konnten keine Verbindung zum Server herstellen. Wenn das Problem weiterhin besteht, kontaktieren Sie VTEX-Support.",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "Datum",
  "render-runtime.error.action.retry": "Erneut versuchen",
  "render-runtime.error.counter": "Automatische Wiederholung in {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/pt.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Algo deu errado",
  "render-runtime.error.description": "Não conseguimos conexão com o servidor. Se o problema persistir, entre em contato com o suporte da VTEX.",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "Data",
  "render-runtime.error.action.retry": "Tentar novamente",
  "render-runtime.error.counter": "Nova tentativa em {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/en.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Something went wrong",
  "render-runtime.error.description": "We couldn't connect to the server. If the problem persists, contact VTEX Support.",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "Date",
  "render-runtime.error.action.retry": "Try again",
  "render-runtime.error.counter": "Automatic retry in {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/it.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Si è verificato un errore",
  "render-runtime.error.description": "Non è stato possibile connettersi al server. Se il problema persiste, contatta l'assistenza VTEX.",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "Data",
  "render-runtime.error.action.retry": "Prova di nuovo",
  "render-runtime.error.counter": "Nuovo tentativo automatico in {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/fr.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Un problème est survenu",
  "render-runtime.error.description": "Nous n'avons pas pu nous connecter au serveur. Si le problème persiste, contactez le support VTEX.",
  "render-runtime.error.error-id": "Identifiant",
  "render-runtime.error.error-date": "Date",
  "render-runtime.error.action.retry": "Veuillez réessayer",
  "render-runtime.error.counter": "Nouvelle tentative automatique dans {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/bg.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Нещо се обърка",
  "render-runtime.error.description": "Не успяхме да се свържем със сървъра. Ако проблемът продължава, се свържете с поддръжката на VTEX.",
  "render-runtime.error.error-id": "ИД",
  "render-runtime.error.error-date": "Дата",
  "render-runtime.error.action.retry": "Опитайте отново",
  "render-runtime.error.counter": "Автоматичен опит за повтаряне на действието след {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/ro.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Ceva nu a mers bine",
  "render-runtime.error.description": "Nu ne-am putut conecta la server. Dacă problema persistă, contactează Asistența VTEX.",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "Dată",
  "render-runtime.error.action.retry": "Încearcă din nou",
  "render-runtime.error.counter": "Reîncercare automată în {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/ko.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "문제 발생",
  "render-runtime.error.description": "서버에 연결할 수 없습니다. 문제가 지속되면 VTEX 지원팀에 문의하세요.",
  "render-runtime.error.error-id": "아이디",
  "render-runtime.error.error-date": "날짜",
  "render-runtime.error.action.retry": "다시 시도",
  "render-runtime.error.counter": "{counter}에서 자동 재시도..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/index.ts from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```typescript
import bg from './bg.json'
import de from './de.json'
import en from './en.json'
import es from './es.json'
import fr from './fr.json'
import it from './it.json'
import ja from './ja.json'
import ko from './ko.json'
import nl from './nl.json'
import pt from './pt.json'
import ro from './ro.json'
import th from './th.json'

export const messages: Record<string, Record<string, string>> = {
  'en-US': en,
  'es-AR': es,
  'fr-FR': fr,
  'pt-BR': pt,
  'ja-JP': ja,
  'ko-KR': ko,
  'it-IT': it,
  'nl-NL': nl,
  'ro-RO': ro,
  'bg-BG': bg,
  'th-TH': th,
  'de-DE': de,
}

export function getMessages(locale: string) {
  const localeMessages = (locale && messages[locale]) || {}
  const fallbackMessages = messages['en-US']

  return { ...fallbackMessages, ...localeMessages }
}

```


[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 render-runtime/react/components/ErrorPage/messages/th.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "มีบางอย่างผิดปกติ",
  "render-runtime.error.description": "เราไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ หากยังคงมีปัญหา โปรดติดต่อ VTEX Support",
  "render-runtime.error.error-id": "รหัส",
  "render-runtime.error.error-date": "วันที่",
  "render-runtime.error.action.retry": "ลองอีกครั้ง",
  "render-runtime.error.counter": "ลองอีกครั้งโดยอัตโนมัติใน {counter}..."
}

```


[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 render-runtime/react/components/ErrorPage/messages/es.json from the render-runtime VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "render-runtime.error.title": "Se produjo un error",
  "render-runtime.error.description": "No hemos podido conectarnos al servidor. Si el problema persiste, entra en contacto con el soporte de VTEX.",
  "render-runtime.error.error-id": "ID",
  "render-runtime.error.error-date": "Fecha",
  "render-runtime.error.action.retry": "Reintentar",
  "render-runtime.error.counter": "Reintento automático en {counter}..."
}

```


[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 my-account/messages/context.json from the my-account VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "vtex.store-messages@0.x::userInfo.greeting": "Hi",
  "vtex.store-messages@0.x::pages.addresses": "Addresses",
  "vtex.store-messages@0.x::pages.addressCreate": "Add address",
  "vtex.store-messages@0.x::pages.addressEdit": "Edit address",
  "vtex.store-messages@0.x::pages.profile": "Profile",
  "vtex.store-messages@0.x::pages.profileEdit": "Edit Profile",
  "vtex.store-messages@0.x::pages.logout": "Logout",
  "vtex.store-messages@0.x::logoutModal.cancel": "Cancel",
  "vtex.store-messages@0.x::logoutModal.title": "Do you really want to logout?",
  "vtex.store-messages@0.x::personalData.newsletterOptIn": "I want to receive the newsletter.",
  "vtex.store-messages@0.x::personalData.newsletter": "Newsletter",
  "vtex.store-messages@0.x::personalData.newsletterQuestion": "Do you want to receive promotional emails?",
  "vtex.store-messages@0.x::addresses.addAddress": "Add address",
  "vtex.store-messages@0.x::addresses.saveAddress": "Save address",
  "vtex.store-messages@0.x::addresses.deleteAddress": "Delete address",
  "vtex.store-messages@0.x::addresses.notFound": "You don't have any addresses yet!",
  "vtex.store-messages@0.x::addresses.notApplicable": "N/A",
  "vtex.store-messages@0.x::commons.edit": "Edit",
  "vtex.store-messages@0.x::alert.addressNotFound": "The selected address was not found.",
  "vtex.store-messages@0.x::alert.success": "Your information was successfully saved.",
  "vtex.store-messages@0.x::editor.defaultRoute.name": "My Account - Home",
  "vtex.store-messages@0.x::editor.defaultRoute.description": "My Account's default page",
  "vtex.store-messages@0.x::editor.defaultRoute.field": "My Account's default path",
  "vtex.store-messages@0.x::editor.menu.name": "My Account - Menu",
  "vtex.store-messages@0.x::editor.menu.description": "My Account's side menu",
  "vtex.store-messages@0.x::editor.menu.field": "Menu's Extension Point"
}

```


[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 my-account/my-account-extension-example/manifest.json from the my-account VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "my-account-extension-example",
  "vendor": "vtex",
  "version": "0.0.0",
  "title": "My Account Extension Example",
  "description": "",
  "mustUpdateAt": "2019-07-09",
  "dependencies": {
    "vtex.my-account": "1.x",
    "vtex.styleguide": "9.x",
    "vtex.my-account-commons": "1.x"
  },
  "builders": {
    "react": "3.x",
    "messages": "1.x",
    "store": "0.x"
  },
  "scripts": {
    "postreleasy": "vtex publish --verbose"
  },
  "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema"
}

```


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

[Assistant]
Here's the implementation:

```markdown
# My Account - StoreV2 version

> Notice: React: 3.x | Store: 0.x

[Portal](https://github.com/vtex-apps/my-account/tree/master 'Portal version')

## Intro

MyAccount is a canonical app built in all VTEX stores. This app serves as a hub of apps, meaning that it is the entry point for all apps that want to be available for the store's customers.

The app is responsible for handling customer's personal data such as: profile info, passwords, addresses, orders and credit cards. Orders and credit cards are responsibilities of other two apps that come per default with the MyAccount, respectively, these apps are: `vtex.my-orders-app` and `vtex.my-cards`.

## Features

This app provides a few extension points in order to allow apps to customize stores' experience as needed.

### Adding a new page to My Account

First, make sure you have the store-builder as a dependency in you `manifest.json`:

```diff
    "builders": {
      "messages": "1.x",
      "react": "3.x",
+     "store": "0.x"
    },
```

Now, create the file `store/interfaces.json` and define some interfaces:

```json
{
  "my-account-link.my-app-link": {
    "component": "MyAppLink"
  },
  "my-account-page.my-app-page": {
    "component": "MyAppPage"
  }
}
```

If you want to block the editing of the document in the my account form, use the props `blockDocument`

```json
"my-account": {
    "props": { "blockDocument": true },
    "blocks": [
    ]
  }
```

| Prop name       | Type      | Description                                                 | Default value |
| --------------- | --------- | ----------------------------------------------------------- | ------------- |
| `blockDocument` | `boolean` | Enables or disables editing the document field in MyAccount | `undefined`   |

---

**Usage:** To block the document field, follow these steps:

1. In the index.tsx in /react file, the `blockDocument` property is received from the main store. Pass this property on to AppRouter

```js
<Wrapper>

    <AppRouter blockDocument={this.props.blockDocument} />

</Wrapper>
```

2. Pass the property to the `ProfileEdit` component

```js
   component: ComponentClass<void, unknown> | FC

  }) => {
    return <Route exact key={path} path={path} component={component}/>
  }
  public render() {
    const routes = [
      { path: '/addresses', component: Addresses },
      { path: '/addresses/new', component: AddressCreate },
      { path: '/addresses/edit/:id', component: AddressEdit },
      { path: '/profile', component: Profile },
      { path: '/profile/edit', component: ()=><ProfileEdit blockDocument={this.props.blockDocument}/> },
    ]
```

3. In the `ProfileEdit` component, pass the property to the`ProfileFormBox` component

```js
  const { profile, handleError, blockDocument } = this.props
    return (
      <ProfileFormBox
        profile={profile}
        onDataSave={this.handleGoBack}
        onError={handleError}
        blockDocument={blockDocument}
      />
    )
  }
```

4. In the `ProfileFormBox` component, pass the property to the`ProfileContainer` component.
   Just remembering that this component is imported from the **vtex.profile-form** app

```js
    <ProfileContainer
      defaultProfile={profile}
      onSubmit={this.handleSubmit}
      shouldShowExtendedGenders={showGenders}
      blockDocument={blockDocument}
    >
```

5. Follow the steps below in the app ** vtex.profile-form **

The names `my-app-link`, `my-app-page`, `MyAppLink` and `MyAppPage` may be whatever it makes more sense for you app.

Lastly, create a `store/plugins.json` file like so:

```json
{
  "my-account-menu > my-account-link": "my-account-link.my-app-link",
  "my-account-pages > my-account-page": "my-account-page.my-app-page"
}
```

#### Creating a `my-account-page` component

Now create a new file in the root of the "react" folder with the name "MyAppPage.js".

```js
import React, { Fragment } from 'react'
import { Route } from 'vtex.my-account-commons/Router'
// Your component pages
import UserSupport from './components/UserSupport'
import UserPoints from './components/UserPoints'

const MyAppPage = () => (
  <Fragment>
    {/* This `path` will be added at the end of the URL */}
    <Route path="/support" exact component={UserSupport} />
    <Route path="/points" exact component={UserPoints} />
  </Fragment>
)

export default MyAppPage
```

In this example you will have two new pages `/account/#/support` and `/account/#/points`, rendering the UserSupport and UserPoints components respectively.

#### Creating a `my-account-link` component

This component will receive a prop called `render`. You **must** call it with an array of objects with the properties `name` and `path`. This will create the link given the `name` and the `path` provided.

Example of an MyAppLink implementation:

```jsx
import PropTypes from 'prop-types'
import { intlShape, injectIntl } from 'react-intl'

const MyAppLink = ({ render, intl }) => {
  return render([
    {
      name: intl.formatMessage({ id: 'userPoints.link' }),
      path: '/points',
    },
    {
      name: intl.formatMessage({ id: 'userSupport.link' }),
      path: '/support',
    },
  ])
}

MyAppLink.propTypes = {
  render: PropTypes.func.isRequired,
  intl: intlShape.isRequired,
}

export default injectIntl(MyAppLink)
```

### Defining the default home page of My Account

After [creating a new page](#adding-a-new-page-to-my-acccount), you can define the default path that will be rendered when the user opens the URL `/account/`.

1. Open the Site Editor admin (`/admin/cms/site-editor`).
2. Navigate to the My Account page
3. Click on the "My Account - Home" extension point on the Site Editor's menu
4. Fill the field "My Account's default path" to the new path

Following the previous examples, we could fill it with "/points", to open the UserPoints page.

### Display personal info

Inside the Profile page, right above the `edit` button, there is another extension point. This one is intended for stores that collect custom data from their customers (such as their hair color or their pet's name). This extension point allows your component to display such information without breaking the page layout.

**Usage:** Your component shall not render anything: you will simply call the `render` prop with the appropriate data and it will be displayed together with the user's default information. You should pass in an array of objects containing `label` and `value` props. `label` is the name of the field you which to display (such as `Hair color`) and `value` is the value for such field (such as `brown`). Keep in mind that you must run any necessary preprocessing in your data by yourself before displaying, such as masking or localizing your texts. Also, it is up to you to fetch the data from wherever it is.

**Example**

```js
const BeautyData = ({ render }) => {
  return render([
    {
      label: 'Hair color',
      value: 'Red',
    },
    {
      label: 'Skin color',
      value: 'White',
    },
  ])
}
```

### Edit personal info

If you are going to display tailored data inside your customer's profile, you probably want to edit that info too. The last extension point, `my-account/profile/input`, lets you do that. It will place whatever content you want inside the profile editing form, right above the 'toggle business fields' button, and also use functions provided by you to validate and submit that content.

**Usage:** Your component may render form components, texts or anything else as desired. We recommend sticking to VTEX's Styleguide or your own design guidelines to avoid breaking the style from the rest of the form. You also receive two props, `registerValidator` and `registerSubmitter`. As their names suggest, you must use them to register your validation and submission functions with the main component. You should use `componentDidMount` to do that. This way, when the user hits 'Submit', your validation function will be called. We then expect you to validate all of your fields and display messages to the user if necessary. If something is invalid, your function should return `false` in order to halt the submission process, and return `true` otherwise. The function may either return the boolean value directly or a `Promise` which will resolve to the appropriate boolean value. When all validation is passed, the form enters submission state. It will now send the default profile information to VTEX's databases and call your submit function so you can do the same. Do not place user interaction or anything related inside that function besides submitting, since the app will return to the display page as soon as all the submitter functions finish executing and anything you display will probably not be noticed by the user.

**Example**

```js
import React, { Component } from 'react'
import { Input } from 'vtex.styleguide'

class FavColor extends Component {
  constructor(props) {
    super(props)
    this.state = {
      color: '',
      error: null,
    }
  }

  componentDidMount() {
    this.props.registerValidator(this.validate)
    this.props.registerSubmitter(this.submit)
  }

  onChange = e => {
    this.setState({ color: e.target.value })
  }

  validate = () => {
    const { color } = this.state
    this.setState({ error: null })
    if (color !== 'yellow') {
      this.setState({ error: 'Your favorite color must be yellow.' })
      return false
    }
    return true
  }

  submit = () => {
    console.log('Success! Your information is saved.')
  }

  render() {
    const { error, color } = this.state
    return (

        <Input
          name="color"
          label="Favorite Color"
          value={color}
          errorMessage={error}
          onChange={this.onChange}
        />

    )
  }
}

export default FavColor
```

## Author

Gustavo Silva (@akafts) during a Winter Internship of 2018 at VTEX :)

Ft: Felipe Sales (@salesfelipe)

```


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

[Assistant]
Here's the implementation:

```graphql
type Query {
  appSettings: AppSettings
}

type AppSettings {
  cacheId: ID
  useMap: Boolean
  showGenders: Boolean
  showMyCards: Boolean
  showMyOrders: Boolean
  showMyAddresses: Boolean
  showMyAuthentication: Boolean
}

```


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

[User] Show me the implementation of my-account/node/service.json from the my-account VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "stack": "nodejs",
  "memory": 150,
  "ttl": 60,
  "timeout": 5,
  "minReplicas": 2,
  "maxReplicas": 4,
  "cpu": {
    "type": "shared",
    "value": 5,
    "scalingPercentage": 50
  }
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "lint": "tsc --noEmit && eslint --quiet --fix --ext ts,tsx ."
  },
  "devDependencies": {
    "@types/node": "^12.7.4",
    "eslint": "5.x",
    "eslint-config-vtex": "10.x",
    "prettier": "^1.18.2",
    "typescript": "3.9.7",
    "vtex.address-form": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.address-form@4.6.6/public/_types/react",
    "vtex.country-codes": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.country-codes@2.0.1/public/_types/react",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.my-account": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account@1.19.0/public/@types/vtex.my-account",
    "vtex.my-account-commons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account-commons@1.6.0/public/@types/vtex.my-account-commons",
    "vtex.my-cards": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-cards@1.10.0/public/@types/vtex.my-cards",
    "vtex.my-orders-app": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-orders-app@3.13.1/public/@types/vtex.my-orders-app",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.7.0/public/@types/vtex.pixel-manager",
    "vtex.profile-form": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.profile-form@3.5.1/public/@types/vtex.profile-form",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.139.1/public/@types/vtex.store-graphql",
    "vtex.store-messages": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-messages@0.3.2/public/_types/react",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide"
  },
  "dependencies": {
    "@vtex/api": "6.48.0"
  },
  "version": "1.29.0"
}

```


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

[User] Show me the implementation of my-account/node/index.ts from the my-account VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { Service, IOClients, ServiceContext, RecorderState } from '@vtex/api'

import settingsResolver from './resolvers/settings'

declare var process: {
  env: {
    VTEX_APP_ID: string
  }
}

declare global {
  type Context = ServiceContext
}

export default new Service<IOClients, RecorderState, Context>({
  graphql: {
    resolvers: {
      Query: {
        appSettings: settingsResolver,
      },
      AppSettings: {
        cacheId: () => process.env.VTEX_APP_ID,
      },
    },
  }
})

```


[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 my-account/react/index.tsx from the my-account VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component } from 'react'
import 'vtex.country-codes/locales'

import AppRouter from './components/AppRouter'
import Wrapper from './components/MyAccountWrapper'
import { logGeneralErrors } from './utils/logger'

interface Props {
  blockDocument?: boolean
}

class MyAccount extends Component<Props> {
  public componentDidCatch(error: unknown, info: unknown) {
    if (window.__RUNTIME__.workspace === 'master') {
      logGeneralErrors(error, info)
    }
  }

  public render() {
    return (
      <Wrapper>
        <div className="vtex-account helvetica flex justify-around">
          <AppRouter blockDocument={this.props.blockDocument} />
        </div>
      </Wrapper>
    )
  }
}

export default MyAccount

```


[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 my-account/react/DefaultRoute.tsx from the my-account VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { Component } from 'react'

class DefaultRoute extends Component<Props> {
  public componentDidMount() {
    this.props.onSetDefaultPath(this.props.defaultRoute || '/profile')
  }

  public static getSchema = () => {
    return {
      title: 'vtex.store-messages@0.x::editor.defaultRoute.name',
      description: 'vtex.store-messages@0.x::editor.defaultRoute.description',
      type: 'object',
      properties: {
        defaultRoute: {
          title: 'vtex.store-messages@0.x::editor.defaultRoute.field',
          type: 'string',
          default: '/profile',
        },
      },
    }
  }

  public render() {
    return null
  }
}

interface Props {
  defaultRoute: string
  onSetDefaultPath: (path: string) => void
}

export default DefaultRoute

```


[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 my-account/react/DefaultPage.tsx from the my-account VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { Component } from 'react'

class DefaultPage extends Component<Props> {
  public componentDidMount() {
    this.props.onSetDefaultPath(this.props.defaultRoute || '/profile')
  }

  public static getSchema() {
    return {
      title: 'vtex.store-messages@0.x::editor.defaultRoute.name',
      description: 'vtex.store-messages@0.x::editor.defaultRoute.description',
      type: 'object',
      properties: {
        defaultRoute: {
          title: 'vtex.store-messages@0.x::editor.defaultRoute.field',
          type: 'string',
          default: '/profile',
        },
      },
    }
  }

  public render() {
    return null
  }
}

interface Props {
  onSetDefaultPath: (args: string) => void
  defaultRoute: string
}

export default DefaultPage

```


[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 my-account/react/styles.css from the my-account VTEX app.

[Assistant]
Here's the implementation:

```css
.shimmer {
  width: 200%;
  height: 100%;
  position: absolute;
  top: 0;
  left: -100%;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 0.7),
    rgba(255, 255, 255, 0)
  );
  background-size: 50% 100%;
  animation: shimmer-anim 0.7s linear infinite;
}

/* Add tweakpoint inside m */
@media screen and (min-width: 57em) {
  .dn-m-2 {
    display: none;
  }

  .pv0-m-2 {
    padding-top: 0;
    padding-bottom: 0;
  }

  .pl0-m-2 {
    padding-left: 0;
  }
}

/* Skeleton animation */
@keyframes shimmer-anim {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(50%, 0, 0);
  }
}

```


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

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

[Assistant]
Here's the implementation:

```json
{
  "name": "my-account",
  "dependencies": {
    "apollo-client": "^2.6.4",
    "graphql": "^14.0.2",
    "query-string": "5.x",
    "ramda": "^0.26.1",
    "react": "^16.4.1",
    "react-apollo": "^2.3.2",
    "react-dom": "^16.9.0",
    "react-intl": "^2.4.0",
    "react-media": "^1.8.0",
    "recompose": "^0.27.1"
  },
  "devDependencies": {
    "@types/graphql": "^14.2.2",
    "@types/query-string": "5.x",
    "@types/ramda": "^0.26.21",
    "@types/react": "^16.8.22",
    "@types/react-intl": "^2.3.18",
    "@types/react-router-dom": "4.x",
    "@types/recompose": "^0.30.7",
    "@vtex/test-tools": "^0.3.2",
    "typescript": "3.9.7",
    "vtex.address-form": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.address-form@4.6.6/public/_types/react",
    "vtex.country-codes": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.country-codes@2.0.1/public/_types/react",
    "vtex.css-handles": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.css-handles@0.4.4/public/@types/vtex.css-handles",
    "vtex.my-account-commons": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-account-commons@1.6.0/public/@types/vtex.my-account-commons",
    "vtex.my-cards": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-cards@1.10.0/public/@types/vtex.my-cards",
    "vtex.my-orders-app": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.my-orders-app@3.13.1/public/@types/vtex.my-orders-app",
    "vtex.pixel-manager": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.pixel-manager@1.7.0/public/@types/vtex.pixel-manager",
    "vtex.profile-form": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.profile-form@3.5.1/public/@types/vtex.profile-form",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.128.2/public/@types/vtex.render-runtime",
    "vtex.store-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-graphql@2.139.1/public/@types/vtex.store-graphql",
    "vtex.store-messages": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.store-messages@0.3.2/public/_types/react",
    "vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.styleguide@9.138.0/public/@types/vtex.styleguide"
  },
  "scripts": {
    "lint": "tsc --noEmit && eslint --ext ts,tsx .",
    "test": "vtex-test-tools test"
  },
  "version": "1.29.0"
}

```


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

[User] Show me the implementation of my-account/react/Menu.tsx from the my-account VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Component } from 'react'
import { ExtensionPoint } from 'vtex.render-runtime'

class Menu extends Component<Props> {
  public componentDidMount() {
    this.props.hasExtension(!!this.props.extensionPoint)
  }

  public componentDidUpdate(prevProps: Props) {
    if (this.props.extensionPoint !== prevProps.extensionPoint) {
      this.props.hasExtension(!!this.props.extensionPoint)
    }
  }

  public static getSchema() {
    return {
      title: 'vtex.store-messages@0.x::editor.menu.name',
      description: 'vtex.store-messages@0.x::editor.menu.description',
      type: 'object',
      properties: {
        extensionPoint: {
          title: 'vtex.store-messages@0.x::editor.menu.field',
          type: 'string',
          default: '',
        },
      },
    }
  }

  public render() {
    return this.props.extensionPoint ? (
      <ExtensionPoint id={this.props.extensionPoint} />
    ) : null
  }
}

interface Props {
  extensionPoint: string
  hasExtension: (arg: boolean) => void
}

export default Menu

```


[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 my-account/react/MyProfileLink.tsx from the my-account VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FunctionComponent } from 'react'
import type { InjectedIntlProps } from 'react-intl'
import { injectIntl } from 'react-intl'

const MyProfileLink: FunctionComponent<Props> = ({ render, intl }) => {
  return render([
    {
      name: intl.formatMessage({
        id: 'vtex.store-messages@0.x::pages.profile',
      }),
      path: '/profile',
    },
  ])
}

interface Props extends InjectedIntlProps {
  render: (args: Array<{ name: string; path: string }>) => any
}

export default injectIntl(MyProfileLink)

```


[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 my-account/react/MyAddressesLink.tsx from the my-account VTEX app.

[Assistant]
Here's the implementation:

```tsx
import type { FunctionComponent } from 'react'
import type { InjectedIntlProps } from 'react-intl'
import { injectIntl } from 'react-intl'

const MyAddressesLink: FunctionComponent<Props> = ({ render, intl }) => {
  return render([
    {
      name: intl.formatMessage({
        id: 'vtex.store-messages@0.x::pages.addresses',
      }),
      path: '/addresses',
    },
  ])
}

interface Props extends InjectedIntlProps {
  render: (args: Array<{ name: string; path: string }>) => any
}

export default injectIntl(MyAddressesLink)

```


[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 my-account/store/blocks.json from the my-account VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "my-account": {
    "blocks": [
      "my-account-pages",
      "my-account-defaultPage",
      "my-account-menu",
      "profile-display-container",
      "profile-input-container"
    ]
  },
  "my-account-menu": {
    "blocks": [
      "my-profile-link",
      "my-addresses-link",
      "my-orders-link",
      "my-cards-link"
    ]
  },
  "my-account-pages": {
    "blocks": ["my-orders", "my-cards"]
  }
}

```


[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 my-account/store/interfaces.json from the my-account VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "my-account": {
    "component": "index",
    "required": [
      "my-account-pages",
      "my-account-defaultPage",
      "my-account-menu",
      "profile-display-container",
      "profile-input-container"
    ],
    "render": "client"
  },
  "my-account-defaultPage": {
    "component": "DefaultPage"
  },
  "my-account-pages": {
    "allowed": ["my-orders", "my-cards", "my-account-page"]
  },
  "my-account-page": {
    "component": "*",
    "extensibility": "public"
  },
  "my-account-menu": {
    "allowed": [
      "my-profile-link",
      "my-addresses-link",
      "my-orders-link",
      "my-cards-link",
      "my-account-link"
    ]
  },
  "my-account-link": {
    "component": "*",
    "extensibility": "public"
  },
  "my-addresses-link": {
    "component": "MyAddressesLink"
  },
  "my-profile-link": {
    "component": "MyProfileLink"
  },
  "profile-display-container": {
    "allowed": ["profile-display"]
  },
  "profile-display": {
    "component": "*",
    "extensibility": "public"
  },
  "profile-input-container": {
    "allowed": ["profile-input"]
  },
  "profile-input": {
    "component": "*",
    "extensibility": "public"
  }
}

```


[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 my-account/my-account-extension-example/react/BeautyData.js from the my-account VTEX app.

[Assistant]
Here's the implementation:

```javascript
const BeautyData = ({ render }) => {
  return render([
    { label: 'Hair color', value: 'Red' },
    { label: 'Skin color', value: 'White' },
  ])
}

export default BeautyData

```


[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 my-account/my-account-extension-example/react/package.json from the my-account VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "my-account-plugin",
  "dependencies": {
    "apollo-client": "^2.4.7",
    "exenv": "^1.2.2",
    "graphql": "^14.0.2",
    "moment": "^2.22.2",
    "query-string": "^6.3.0",
    "react": "^16.4.1",
    "react-apollo": "^2.3.2",
    "react-dropzone": "^5.0.1",
    "react-intl": "^2.4.0",
    "react-media": "^1.8.0",
    "react-router-dom": "^4.3.1",
    "recompose": "^0.27.1"
  }
}

```


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

[User] Show me the implementation of my-account/my-account-extension-example/react/MyAppPage.js from the my-account VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Fragment } from 'react'
import { Route } from 'vtex.my-account-commons/Router'
// Your component pages
import UserSupport from './components/UserSupport'

const MyAppPage = () => (
  <Fragment>
    <Route exact path="/support" component={UserSupport} />
  </Fragment>
)

export default MyAppPage

```


[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 my-account/my-account-extension-example/react/FavColor.js from the my-account VTEX app.

[Assistant]
Here's the implementation:

```javascript
import React, { Component } from 'react'
import { Input } from 'vtex.styleguide'

class FavColor extends Component {
  constructor(props) {
    super(props)
    this.state = {
      color: '',
      error: null,
    }
  }

  componentDidMount() {
    this.props.registerValidator(this.validate)
    this.props.registerSubmitter(this.submit)
  }

  onChange = e => {
    this.setState({ color: e.target.value })
  }

  validate = () => {
    const { color } = this.state
    this.setState({ error: null })
    if (color !== 'yellow') {
      this.setState({ error: 'Your favorite color must be yellow.' })
      return false
    }
    return true
  }

  submit = () => {
    console.log('Success! Your information is saved.')
  }

  render() {
    const { error, color } = this.state
    return (
      <div className="mb8">
        <Input
          name="color"
          label="Favorite Color"
          value={color}
          errorMessage={error}
          onChange={this.onChange}
        />
      </div>
    )
  }
}

export default FavColor

```