[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 b2b-quotes/react/components/QuoteDetails/QuoteDetails.tsx from the b2b-quotes VTEX app.

[Assistant]
Here's the implementation:

```tsx
/* eslint-disable react/display-name */
import type { ChangeEventHandler, FunctionComponent } from 'react'
import React, {
  Fragment,
  useCallback,
  useContext,
  useEffect,
  useState,
} from 'react'
import { useMutation, useQuery } from 'react-apollo'
import { FormattedMessage, useIntl } from 'react-intl'
import { useCheckoutURL } from 'vtex.checkout-resources/Utils'
import { OrderForm } from 'vtex.order-manager'
import { useRuntime } from 'vtex.render-runtime'
import {
  Alert,
  Button,
  DatePicker,
  Layout,
  PageBlock,
  PageHeader,
  Spinner,
  Textarea,
  ToastContext,
} from 'vtex.styleguide'

import CHECK_SELLER_QUOTES from '../../graphql/checkSellerQuotes.graphql'
import CLEAR_CART from '../../graphql/clearCartMutation.graphql'
import CREATE_QUOTE from '../../graphql/createQuote.graphql'
import GET_AUTH_RULES from '../../graphql/getDimension.graphql'
import GET_CHILDREN_QUOTES from '../../graphql/getFullChildrenQuotes.graphql'
import GET_PERMISSIONS from '../../graphql/getPermissions.graphql'
import GET_QUOTE from '../../graphql/getQuote.graphql'
import GET_ORDERFORM from '../../graphql/orderForm.gql'
import UPDATE_QUOTE from '../../graphql/updateQuote.graphql'
import USE_QUOTE from '../../graphql/useQuote.graphql'
import useCheckout from '../../modules/checkoutHook'
import {
  initQuoteFromOrderForm,
  isQuoteUsable,
  useSessionResponse,
} from '../../utils/helpers'
import { quoteMessages } from '../../utils/messages'
import { sendCreateQuoteMetric } from '../../utils/metrics/createQuote'
import type { UseQuoteMetricsParams } from '../../utils/metrics/useQuote'
import { sendUseQuoteMetric } from '../../utils/metrics/useQuote'
import { arrayShallowEqual } from '../../utils/shallowEquals'
import { Status } from '../../utils/status'
import storageFactory from '../../utils/storage'
import AlertMessage from './AlertMessage'
import PercentageDiscount from './PercentageDiscount'
import QuoteChildren from './QuoteChildren'
import QuoteDetailsNotAuthenticated from './QuoteDetailsNotAuthenticated'
import QuoteName from './QuoteName'
import QuoteTable from './QuoteTable'
import QuoteUpdateHistory from './QuoteUpdateHistory'
import SaveButtons from './SaveButtons'

const localStore = storageFactory(() => localStorage)
const MAX_DISCOUNT_PERCENTAGE = 99

let isAuthenticated =
  JSON.parse(String(localStore.getItem('b2bquotes_isAuthenticated'))) ?? false

const initialState = {
  id: '',
  costCenter: '',
  costCenterName: '',
  creationDate: '',
  creatorEmail: '',
  creatorRole: '',
  expirationDate: '',
  items: [],
  lastUpdate: '',
  organization: '',
  organizationName: '',
  referenceName: '',
  status: '',
  subtotal: 0,
  updateHistory: [],
  viewedByCustomer: false,
  viewedBySales: false,
  hasChildren: false,
}

const QuoteDetails: FunctionComponent = () => {
  /**
   * constants
   */
  const {
    route: { params },
    query,
    navigate,
    workspace,
    account,
  } = useRuntime()

  const isNewQuote = !params?.id
  const sessionResponse: any = useSessionResponse()
  const intl = useIntl()
  const { formatMessage } = intl
  const { url: checkoutUrl } = useCheckoutURL()
  const goToCheckout = useCheckout()
  const { setOrderForm }: OrderFormContext = OrderForm.useOrderForm()
  const { showToast } = useContext(ToastContext)

  const toastMessage = (message: MessageDescriptor) => {
    const translatedMessage = formatMessage(message)
    const action = undefined

    showToast({ message: translatedMessage, duration: 5000, action })
  }

  const [quoteState, setQuoteState] = useState<Quote>(initialState)
  const [formState, setFormState] = useState({
    isEditable: false,
    canAddNotes: false,
    errorMessage: '',
  })

  const [orderFormState, setOrderFormState] = useState('')
  const [noteState, setNoteState] = useState('')
  const [maxDiscountState, setMaxDiscountState] = useState(
    MAX_DISCOUNT_PERCENTAGE
  )

  const [discountState, setDiscountState] = useState(0)
  const [updatingQuoteState, setUpdatingQuoteState] = useState(false)
  const [usingQuoteState, setUsingQuoteState] = useState(false)
  const [usingQuoteChild, setUsingQuoteChild] = useState<string>()
  const [originalSubtotal, setOriginalSubtotal] = useState(0)
  const [updatingSubtotal, setUpdatingSubtotal] = useState(0)
  const [sentToSalesRep, setSentToSalesRep] = useState(false)
  const getQuoteVariables = { id: params?.id }

  /**
   * GraphQL Queries
   */
  const { data, loading, refetch } = useQuery(GET_QUOTE, {
    fetchPolicy: 'network-only',
    variables: getQuoteVariables,
    ssr: false,
    skip: isNewQuote,
  })

  const {
    data: childrenQuoteList,
    loading: childrenQuotesLoading,
    refetch: refetchChildrenQuotes,
  } = useQuery(GET_CHILDREN_QUOTES, {
    fetchPolicy: 'network-only',
    variables: getQuoteVariables,
    ssr: false,
    skip: isNewQuote || !data?.getQuote?.hasChildren,
  })

  const childrenQuotes = childrenQuoteList?.getChildrenQuotes

  const sellers = Array.from(
    new Set(quoteState.items.map((item: QuoteItem) => item.seller))
  )

  const externalSellers = sellers.filter((seller) => seller !== '1')

  const {
    data: checkSellerQuotesData,
    loading: checkSellerQuotesLoading,
  } = useQuery(CHECK_SELLER_QUOTES, {
    fetchPolicy: 'network-only',
    ssr: false,
    skip: !isNewQuote,
    variables: { sellers: externalSellers },
  })

  const checkedSellers = checkSellerQuotesData?.checkSellerQuotes

  const hasCheckedExternalSellers = !!checkedSellers?.some(
    (seller: Seller) => seller.id !== '1'
  )

  const {
    data: orderFormData,
    refetch: refetchOrderForm,
  } = useQuery(GET_ORDERFORM, { ssr: false, fetchPolicy: 'network-only' })

  const { data: orderAuthData } = useQuery(GET_AUTH_RULES, { ssr: false })
  const {
    data: permissionsData,
    loading: permissionsLoading,
  } = useQuery(GET_PERMISSIONS, { ssr: false })

  const {
    id = '',
    items = [],
    status = '',
    expirationDate,
    childrenQuantity,
    parentQuote,
    seller,
    sellerName,
  } = data?.getQuote ?? {}

  const { permissions = [] } = permissionsData?.checkUserPermission ?? {}
  const isSalesRep = permissions.some(
    (permission: string) => permission.indexOf('edit-quotes') >= 0
  )

  const quoteUsable = isQuoteUsable(permissions, status)

  const quoteDeclinable =
    permissions.includes('decline-quotes') &&
    (!seller || seller === '1') &&
    !quoteState.hasChildren &&
    status &&
    status !== Status.EXPIRED &&
    status !== Status.DECLINED

  /**
   *  GraphQL Mutations
   */
  const [createQuoteMutation] = useMutation(CREATE_QUOTE)
  const [updateQuote] = useMutation(UPDATE_QUOTE)
  const [mutationUseQuote] = useMutation(USE_QUOTE)
  const [clearCart] = useMutation(CLEAR_CART)
  /**
   * functions
   */
  const setEditable = useCallback(() => {
    let isEditable = true
    let canAddNotes = true

    if (parentQuote && seller && seller !== '1') {
      isEditable = false
    }

    if (isNewQuote && sellers.length > 1 && hasCheckedExternalSellers) {
      canAddNotes = false
    }

    setFormState((f) => {
      return {
        ...f,
        isEditable,
        canAddNotes,
      }
    })
  }, [
    hasCheckedExternalSellers,
    isNewQuote,
    parentQuote,
    seller,
    sellers.length,
  ])

  const handleClearCart = (orderFormId: string) => {
    return clearCart({
      variables: {
        orderFormId,
      },
    })
  }

  const handleCreateQuote = (sendToSalesRep: boolean) => {
    const { orderForm } = orderFormData

    setUpdatingQuoteState(true)
    const { referenceName, items: quoteItems } = quoteState
    const cart = {
      referenceName,
      items: quoteItems,
      subtotal: updatingSubtotal,
      note: noteState,
      sendToSalesRep,
    }

    createQuoteMutation({
      variables: cart,
    })
      .then((result: any) => {
        if (result.data.createQuote) {
          const metricsParam = {
            quoteId: result.data.createQuote,
            sessionResponse,
            workspace,
            sendToSalesRep,
            account,
          }

          sendCreateQuoteMetric(metricsParam)

          toastMessage(quoteMessages.createSuccess)
          handleClearCart(orderForm.orderFormId).then(() => {
            setQuoteState(initialState)
            setUpdatingSubtotal(0)
            setOriginalSubtotal(0)
            setTimeout(() => {
              refetchOrderForm().then((resp: any) => {
                if (resp?.data?.orderForm) {
                  setOrderForm(resp?.data?.orderForm)
                }

                setUpdatingQuoteState(false)
                navigate({
                  page: 'store.b2b-quotes',
                  fallbackToWindowLocation: true,
                  fetchPage: true,
                })

                return resp
              })
            }, 500)
          })
        } else {
          toastMessage(quoteMessages.createError)
          setUpdatingQuoteState(false)
        }
      })
      .catch(() => {
        toastMessage(quoteMessages.createError)
        setUpdatingQuoteState(false)
      })
  }

  const createQuote = (sendToSalesRep: boolean) => {
    setSentToSalesRep(sendToSalesRep)
    if (!quoteState.referenceName) {
      setFormState({
        ...formState,
        errorMessage: formatMessage(quoteMessages.required),
      })
    } else {
      handleCreateQuote(sendToSalesRep)
    }
  }

  const handleAfterSaveQuote = () => {
    if (parentQuote && query?.parent !== undefined) {
      navigate({
        page: 'store.b2b-quote-details',
        params: { id: parentQuote },
      })
    } else {
      refetch(getQuoteVariables)
      refetchChildrenQuotes(getQuoteVariables)
    }
  }

  const handleSaveQuote = () => {
    setUpdatingQuoteState(true)
    const {
      id: _id,
      items: _items,
      expirationDate: _expirationDate,
    } = quoteState

    const itemsChanged = !arrayShallowEqual(data.getQuote.items, _items)

    updateQuote({
      variables: {
        id: _id,
        ...(itemsChanged && { items: _items }),
        ...(itemsChanged && { subtotal: updatingSubtotal }),
        ...(noteState && { note: noteState }),
        decline: false,
        expirationDate: _expirationDate,
      },
    })
      .catch((error) => {
        console.error(error)
        toastMessage(quoteMessages.updateError)
        setUpdatingQuoteState(false)
      })
      .then(() => {
        setNoteState('')
        setDiscountState(0)
        setUpdatingQuoteState(false)
        toastMessage(quoteMessages.updateSuccess)
        handleAfterSaveQuote()
      })
  }

  const updateUseState = (quote: Quote, newState: boolean) => {
    if (quote.parentQuote) {
      if (newState) {
        setUsingQuoteChild(quote.id)

        return
      }

      setUsingQuoteChild(undefined)

      return
    }

    setUsingQuoteState(newState)
  }

  const handleUseQuote = (quote: Quote) => {
    updateUseState(quote, true)
    const { id: _id } = quote
    const variables = {
      id: _id,
      orderFormId: orderFormState,
    }

    mutationUseQuote({
      variables,
    })
      .catch((error) => {
        console.error(error)
        toastMessage(quoteMessages.useError)
        updateUseState(quote, false)
      })
      .then(() => {
        const metricsParam: UseQuoteMetricsParams = {
          quoteState: quote,
          orderFormId: variables.orderFormId,
          account,
          sessionResponse,
        }

        sendUseQuoteMetric(metricsParam)
        goToCheckout(checkoutUrl)
        updateUseState(quote, false)
      })
  }

  const handleDeclineQuote = () => {
    setUpdatingQuoteState(true)
    updateQuote({
      variables: {
        id,
        ...(noteState && { note: noteState }),
        decline: true,
      },
    })
      .catch((error) => {
        console.error(error)
        toastMessage(quoteMessages.updateError)
        setUpdatingQuoteState(false)
      })
      .then(() => {
        setNoteState('')
        setDiscountState(0)
        setUpdatingQuoteState(false)
        toastMessage(quoteMessages.updateSuccess)
        handleAfterSaveQuote()
      })
  }

  const handleUpdateSellingPrice: (
    id: string
  ) => ChangeEventHandler<HTMLInputElement> = (itemId) => (event) => {
    const newItems = quoteState.items.map((item: QuoteItem) => {
      if (item.id === itemId) {
        let newPrice = ((event.target.value as unknown) as number) * 100

        if (newPrice > item.price) {
          newPrice = item.price
        }

        return {
          ...item,
          sellingPrice: newPrice,
          error:
            !newPrice || newPrice / item.price < (100 - maxDiscountState) / 100
              ? true
              : undefined, // setting error to false will cause create/update mutation to error
        }
      }

      return item
    })

    setQuoteState({
      ...quoteState,
      items: newItems,
    })
  }

  const handleUpdateQuantity: (
    id: string
  ) => ChangeEventHandler<HTMLInputElement> = (itemId) => (event) => {
    let newSubtotal = 0
    const newItems = quoteState.items.map((item: QuoteItem) => {
      if (item.id === itemId) {
        let quantity =
          !new RegExp(/[^\d]/g).test(event.target.value) && event.target.value
            ? parseInt(event.target.value, 10)
            : 1

        if (quantity <= 0) {
          quantity = 1
        } else if (quantity > 50) {
          quantity = 50
        }

        newSubtotal += item.sellingPrice * quantity

        return {
          ...item,
          quantity,
        }
      }

      newSubtotal += item.sellingPrice * item.quantity

      return item
    })

    setUpdatingSubtotal(newSubtotal)
    setQuoteState({
      ...quoteState,
      items: newItems,
      subtotal: newSubtotal,
    })
  }

  const handlePercentageDiscount = (percent: number) => {
    setDiscountState(percent)
    let newItems = [] as QuoteItem[]
    let newSubtotal = 0

    if (percent === 0) {
      if (isNewQuote) {
        newItems = initQuoteFromOrderForm(orderFormData?.orderForm)
      } else {
        newItems = data.getQuote.items
      }
    } else {
      quoteState.items.forEach((item: QuoteItem) => {
        const newSellingPrice = Math.round(item.price * ((100 - percent) / 100))

        newSubtotal += newSellingPrice * item.quantity

        newItems.push({ ...item, sellingPrice: newSellingPrice })
      })
    }

    setUpdatingSubtotal(newSubtotal)
    setQuoteState({
      ...quoteState,
      items: newItems,
      subtotal: newSubtotal,
    })
  }

  /**
   * effects
   */
  useEffect(() => {
    if (!quoteState.items.find((item) => item.error)) {
      setUpdatingSubtotal(
        quoteState.items.reduce(
          (sum, item) => sum + item.sellingPrice * item.quantity,
          0
        )
      )
    }

    const price = quoteState.items.reduce(
      (sum: number, item: QuoteItem) => sum + item.price * item.quantity,
      0
    )

    setOriginalSubtotal(price)
  }, [quoteState])

  useEffect(() => {
    if (!orderFormData?.orderForm) return

    setOrderFormState(orderFormData.orderForm.orderFormId)
  }, [orderFormData])

  useEffect(() => {
    if (!orderAuthData?.getDimension?.ruleCollection?.length) return

    const { ruleCollection } = orderAuthData.getDimension

    const maxDiscountPercentage =
      ruleCollection.find(
        (collection: any) =>
          collection?.trigger?.effect?.description === 'DenyEffect'
      )?.trigger?.condition?.greatherThan ?? MAX_DISCOUNT_PERCENTAGE

    setMaxDiscountState(maxDiscountPercentage)
  }, [orderAuthData])

  useEffect(() => {
    if (!data?.getQuote) return

    const {
      getQuote: {
        id: _id,
        costCenter,
        costCenterName,
        creationDate,
        creatorEmail,
        creatorRole,
        expirationDate: _expirationDate,
        items: _items,
        lastUpdate,
        organization,
        organizationName,
        referenceName,
        status: _status,
        subtotal,
        updateHistory,
        viewedByCustomer,
        viewedBySales,
        hasChildren,
      },
    } = data

    setUpdatingSubtotal(subtotal)
    setQuoteState({
      id: _id,
      costCenter,
      costCenterName,
      creationDate,
      creatorEmail,
      creatorRole,
      expirationDate: _expirationDate,
      items: _items,
      lastUpdate,
      organization,
      organizationName,
      referenceName,
      status: _status,
      subtotal,
      updateHistory,
      viewedByCustomer,
      viewedBySales,
      hasChildren,
    })

    if (
      _status === Status.PENDING ||
      _status === Status.READY ||
      _status === Status.REVISED
    ) {
      setEditable()
    }
  }, [data, setEditable])

  useEffect(() => {
    // only run this function if this is a new quote and there is orderForm data
    if (!(isNewQuote && orderFormData?.orderForm?.items?.length)) return

    let subtotal = 0
    const itemsCopy = initQuoteFromOrderForm(orderFormData.orderForm)

    itemsCopy.forEach((item: QuoteItem) => {
      subtotal += item.sellingPrice * item.quantity
    })

    setEditable()
    setQuoteState((prevState) => {
      return { ...prevState, items: itemsCopy }
    })
    setUpdatingSubtotal(subtotal)
  }, [isNewQuote, orderFormData, setEditable])

  if (sessionResponse) {
    isAuthenticated =
      sessionResponse?.namespaces?.profile?.isAuthenticated?.value === 'true'

    localStore.setItem(
      'b2bquotes_isAuthenticated',
      JSON.stringify(isAuthenticated)
    )
  }

  if (
    !isAuthenticated ||
    !permissions?.length ||
    (!isNewQuote &&
      !permissions.some((permission: string) =>
        permission.includes('access-quotes')
      )) ||
    (isNewQuote && !permissions.includes('create-quotes'))
  ) {
    return (
      <QuoteDetailsNotAuthenticated
        isNewQuote={isNewQuote}
        permissionsLoading={permissionsLoading}
        isAuthenticated={isAuthenticated}
        onLinkClick={() => {
          navigate({
            page: 'store.b2b-quotes',
          })
        }}
      />
    )
  }

  return (
    <Layout fullWidth>

        <Layout
          fullWidth
          pageHeader={
            <PageHeader
              title={formatMessage(
                isNewQuote
                  ? quoteMessages.createPageTitle
                  : quoteMessages.updatePageTitle
              )}
              linkLabel={formatMessage(quoteMessages.back)}
              onLinkClick={() => {
                if (parentQuote && query?.parent !== undefined) {
                  navigate({
                    page: 'store.b2b-quote-details',
                    params: { id: parentQuote },
                  })
                } else {
                  navigate({
                    page: 'store.b2b-quotes',
                  })
                }
              }}
            />
          }
        >
          <PageBlock>
            {loading || childrenQuotesLoading || checkSellerQuotesLoading ? (
              <Spinner />
            ) : (
              <Fragment>
                <AlertMessage quoteState={quoteState} noteState={noteState} />

                    <QuoteName
                      childrenQuantity={childrenQuantity}
                      sellerName={sellerName || seller}
                      isNewQuote={isNewQuote}
                      quoteState={quoteState}
                      setQuoteState={setQuoteState}
                      formState={formState}
                      onChange={(e: any) => {
                        setQuoteState({
                          ...quoteState,
                          referenceName: e.target.value,
                        })
                      }}
                    />

                      <SaveButtons
                        isNewQuote={isNewQuote}
                        updatingQuoteState={updatingQuoteState}
                        sentToSalesRep={sentToSalesRep}
                        quoteState={quoteState}
                        onSaveForLater={() => {
                          createQuote(false)
                        }}
                        onSaveQuote={() => {
                          if (isNewQuote) {
                            createQuote(!isSalesRep)
                          } else {
                            handleSaveQuote()
                          }
                        }}
                        quoteItems={items}
                        expirationDate={expirationDate}
                        noteState={noteState}
                        isSalesRep={isSalesRep}
                      />
                      {quoteDeclinable && (

                          <Button
                            variation="danger"
                            onClick={() => handleDeclineQuote()}
                            disabled={
                              !formState.isEditable || updatingQuoteState
                            }
                          >
                            <FormattedMessage id="store/b2b-quotes.quote-details.decline" />
                          </Button>

                      )}

                      {quoteUsable && (

                          <Button
                            variation="primary"
                            onClick={() => handleUseQuote(quoteState)}
                            isLoading={usingQuoteState}
                          >
                            <FormattedMessage id="store/b2b-quotes.quote-details.use-quote" />
                          </Button>

                      )}

                {quoteState.hasChildren && !!childrenQuotes?.length ? (
                  childrenQuotes.map((quote: Quote) => (
                    <QuoteChildren
                      key={quote.id}
                      quote={quote}
                      isSalesRep={isSalesRep}
                      usingParentQuote={usingQuoteState}
                      usingQuoteChild={usingQuoteChild}
                      handleUseQuote={handleUseQuote}
                      permissions={permissions}
                    />
                  ))
                ) : (

                    <QuoteTable
                      isNewQuote={isNewQuote}
                      quoteState={quoteState}
                      updatingSubtotal={updatingSubtotal}
                      originalSubtotal={originalSubtotal}
                      isSalesRep={isSalesRep}
                      formState={formState}
                      maxDiscountState={maxDiscountState}
                      discountState={discountState}
                      onUpdateSellingPrice={handleUpdateSellingPrice}
                      onUpdateQuantity={handleUpdateQuantity}
                      checkedSellers={checkedSellers}
                    />
                    {formState.isEditable && isSalesRep && (

                          <FormattedMessage id="store/b2b-quotes.quote-details.apply-discount.title" />

                          <PercentageDiscount
                            updatingSubtotal={updatingSubtotal}
                            originalSubtotal={originalSubtotal}
                            maxDiscountState={maxDiscountState}
                            discountState={discountState}
                            handlePercentageDiscount={handlePercentageDiscount}
                          />
                          {maxDiscountState < 100 && (

                              <FormattedMessage
                                id="store/b2b-quotes.quote-details.apply-discount.maxDiscount-text"
                                values={{ maxDiscount: maxDiscountState }}
                              />

                          )}

                    )}

                    {quoteState.expirationDate &&
                      formState.isEditable &&
                      isSalesRep && (

                            <FormattedMessage id="store/b2b-quotes.quote-details.expiration-date-change.title" />

                            <DatePicker
                              label={formatMessage(quoteMessages.expiration)}
                              minDate={new Date()}
                              locale="en-US"
                              value={new Date(quoteState.expirationDate)}
                              onChange={(date: Date) =>
                                setQuoteState({
                                  ...quoteState,
                                  expirationDate: date.toISOString(),
                                })
                              }
                            />

                      )}

                    <QuoteUpdateHistory
                      updateHistory={quoteState.updateHistory}
                    />

                    {formState.canAddNotes && (

                        <Textarea
                          label={formatMessage(quoteMessages.addNote)}
                          value={noteState}
                          onChange={(
                            e: React.ChangeEvent<HTMLInputElement>
                          ) => {
                            setNoteState(e.target.value)
                          }}
                          characterCountdownText={
                            <FormattedMessage
                              id="store/b2b-quotes.create.characterLeft"
                              values={{ count: noteState.length }}
                            />
                          }
                          maxLength="500"
                          rows="4"
                        />

                    )}

                    {isNewQuote && !formState.canAddNotes && (

                        <Alert type="warning">
                          {formatMessage(
                            quoteMessages.notesAfterCreatedHelpText
                          )}
                        </Alert>

                    )}

                )}
              </Fragment>
            )}
          </PageBlock>
        </Layout>

    </Layout>
  )
}

export default QuoteDetails

```


[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 b2b-quotes/react/components/QuoteDetails/PercentageDiscount.tsx from the b2b-quotes VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { Fragment } from 'react'
import { Slider } from 'vtex.styleguide'
import { FormattedMessage } from 'react-intl'

const PercentageDiscount = ({
  updatingSubtotal,
  originalSubtotal,
  maxDiscountState,
  discountState,
  handlePercentageDiscount,
}: any) => {
  if (
    discountState === 0 ||
    (updatingSubtotal !== undefined &&
      originalSubtotal !== undefined &&
      Math.round(100 - (updatingSubtotal / originalSubtotal) * 100) <=
        maxDiscountState)
  ) {
    return (
      <Fragment>
        <div className="mt5">
          <Slider
            onChange={([value]: [number]) => {
              handlePercentageDiscount(value)
            }}
            min={0}
            max={maxDiscountState}
            step={1}
            disabled={false}
            defaultValues={[0]}
            alwaysShowCurrentValue
            formatValue={(a: number) => `${a}%`}
            value={discountState}
          />
        </div>

        <div className="mt1">
          <FormattedMessage id="store/b2b-quotes.quote-details.apply-discount.help-text" />
        </div>
      </Fragment>
    )
  }

  return (
    <div className="mt1">
      <FormattedMessage id="store/b2b-quotes.quote-details.apply-discount.disabled-message" />
    </div>
  )
}

export default PercentageDiscount

```


[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 seller-financial-commission/messages/en.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/navigation.section-title": "Financial commission",
  "admin/navigation.detail-title": "Detail"
}

```


[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 seller-financial-commission/messages/context.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin/navigation.section-title": "Admin section title",
  "admin/navigation.detail-title": "Admin title"
}

```


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

[User] Show me the implementation of seller-financial-commission/admin/navigation.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
[
  {
    "adminVersion": 4,
    "section": "orders",
    "titleId": "admin/navigation.section-title",
    "subSection": "commissionReport",
    "subSectionItems": [
      {
        "labelId": "admin/navigation.detail-title",
        "path": "/admin/commission-detail"
      }
    ]
  }
]

```


[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 seller-financial-commission/admin/routes.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "admin.app.detail": {
    "component": "commissionDetail",
    "path": "/admin/app/commission-detail"
  },
  "admin.app.invoiceDetail": {
    "component": "invoiceSellerDetail",
    "path": "/admin/app/commission-report/invoice/: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 seller-financial-commission/docs/README.md from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

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

# Seller financial commission

**Seller Financial commission** provides a way to list all orders and invoices created by a specific seller, filter them by status or by a specific period of time.
![seller-home](images/home-seller.png)

## **Install:**

Install `vtex.seller-financial-commission` in your account.

```powershell
vtex install vtex.seller-financial-commission
```

## **Features:**

- List All Seller Orders and Invoices at the end of the billing cycle. <br/>
  - Each order is listed with its respective ID, Creation Date, Total Ammount, Total Commission, Rate and Status.
  - Each invoice is listed with its respective status and with its creation date.
- Orders and Invoices can be filtered by Status or by creation date
- Visualize invoice detail.
  ![invoice-detail](images/image4.png)
- A copy of the invoice detail can be sent by e-mail. By default the e-mail will be sent to the vendor's address, but this value can be changed
  ![send-email](images/sendEmail.gif)

## **Components financial commission:**

This app allows you create the interface to show the information about the commissions of the sellers.

Add the components financial app in your new apps in the section dependencies of the manifest file.

```powershell
"dependencies":{
  "vtex.components-financial-commission": "0.x"
}
```

`⚠` See more details about this app related with the technical topics [Components financial](https://github.com/vtex-apps/components-financial-commission/)

### Important:

`🚫` Please, don't upload the file `yarn.lock`. Remove this file of the `commit`.

`✅` When you clone the project, create your work branch from `develop`.

`✅` Upload your changes by making a `pull request`.

`⚠` Not forget to update the version and documentation. This last only if this is necessary.

```


[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 seller-financial-commission/graphql/schema.graphql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
type Query {
  """
  Request the marketplace to retrieve current seller's invoices
  """
  sellerInvoices(sellerInvoiceParams: SellerInvoiceParams): ListInvoices
    @cacheControl(scope: PRIVATE, maxAge: LONG)
  """
  Request the marketplace to retrieve an Invoice
  """
  getInvoice(id: String!): Invoice @cacheControl(scope: PRIVATE, maxAge: SHORT)
  """
  Retrieve orders to seller
  """
  sellerOrders(searchOrdersParams: SearchOrdersParams): SearchOrdersResponse
    @cacheControl(scope: PRIVATE, maxAge: LONG)
  """
  Retrieve template for order detail
  """
  getTemplate: String @cacheControl(scope: PRIVATE, maxAge: LONG)
}

type Mutation {
  """
  Request the marketplace to create an Invoice
  """
  createInvoice(invoiceData: InvoiceDataInput!): String
  """
  Send invoice data to a specific email address
  """
  sendEmail(emailData: EmailDataInput!): String
}

```


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

[User] Show me the implementation of seller-financial-commission/node/service.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "memory": 256,
  "ttl": 30,
  "timeout": 5,
  "minReplicas": 2,
  "maxReplicas": 5
}

```


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

[User] Show me the implementation of seller-financial-commission/node/package.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "dependencies": {
    "@vtex/api": "6.45.12",
    "@vtex/clients": "^2.19.4"
  },
  "devDependencies": {
    "@types/node": "^12.0.0",
    "@vtex/api": "6.45.12",
    "@vtex/tsconfig": "^0.5.6",
    "tslint": "^5.0.0",
    "tslint-config-vtex": "^2.1.0",
    "typescript": "3.9.7"
  },
  "scripts": {
    "lint": "tsc --noEmit && tslint -c tslint.json './**/*.ts'"
  },
  "version": "0.2.2"
}

```


[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 seller-financial-commission/node/index.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ParamsContext, RecorderState } from '@vtex/api'
import { Service } from '@vtex/api'

import clients from './clients'
import type { Clients } from './clients'
import { queries, mutations } from './resolvers'

export default new Service<Clients, RecorderState, ParamsContext>({
  clients,
  graphql: {
    resolvers: {
      Query: {
        ...queries,
      },
      Mutation: {
        ...mutations,
      },
    },
  },
})

```


[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 seller-financial-commission/react/commissionDetail.tsx from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { useRuntime } from 'vtex.render-runtime'
import { detail as Detail } from 'vtex.components-financial-commission'

import SELLER_ORDERS from './graphql/sellerOrders.gql'
import CREATE_INVOICE from './graphql/createInvoice.gql'
import SELLER_INVOICES from './graphql/sellerInvoices.gql'

function CommissionDetail() {
  const { account } = useRuntime()

  return (
    <Detail
      account={account}
      ordersQuery={SELLER_ORDERS}
      invoiceMutation={CREATE_INVOICE}
      invoicesQuery={SELLER_INVOICES}
    />
  )
}

export default CommissionDetail

```


[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 seller-financial-commission/react/package.json from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "name": "seller-financial-commission",
  "version": "0.0.0",
  "scripts": {
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "apollo-client": "^2.6.8",
    "react": "^16.12.0",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.12.0",
    "react-intl": "^3.12.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "^3.1.3",
    "@types/jest": "^25.1.4",
    "@types/node": "^13.9.8",
    "@types/react": "^16.9.31",
    "@vtex/test-tools": "^3.3.2",
    "@vtex/tsconfig": "^0.4.4",
    "apollo-cache-inmemory": "^1.6.5",
    "graphql": "^14.6.0",
    "typescript": "3.9.7",
    "vtex.render-runtime": "http://vtex.vtexassets.com/_v/public/typings/v1/vtex.render-runtime@8.132.4/public/@types/vtex.render-runtime"
  }
}

```


[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 seller-financial-commission/react/invoiceSellerDetail.tsx from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { invoiceDetail as InvoiceDetail } from 'vtex.components-financial-commission'

import GET_INVOICE from './graphql/getInvoice.gql'
import SEND_EMAIL from './graphql/sendEmail.gql'
import GET_TEMPLATE from './graphql/getTemplate.gql'

const InvoiceSellerDetail = () => {
  return (
    <InvoiceDetail
      invoiceQuery={GET_INVOICE}
      getTemplate={GET_TEMPLATE}
      sendEmail={SEND_EMAIL}
    />
  )
}

export default InvoiceSellerDetail

```


[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 seller-financial-commission/graphql/types/global.graphql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
input SellerInvoiceParams {
  sellerName: String!
  pagination: Pagination
  dates: Dates!
}

input Pagination {
  page: Int
  pageSize: Int
}

input Dates {
  startDate: String
  endDate: String
}

type ListInvoices {
  data: [InvoiceList]
  pagination: PaginationInvoice
}

type InvoiceList {
  id: String
  status: String
  invoiceCreatedDate: String
  totalizers: Totalizers
}

type Totalizers {
  subTotal: Float
  fee: Float
  total: Float
}

type PaginationInvoice {
  total: Int
  page: Int
  pageSize: Int
}

scalar JSONData

type Invoice {
  status: String
  invoiceCreatedDate: String
  seller: SellerInvoiceData
  orders: [Order]
  totalizers: Totalizers
  comment: String
  jsonData: JSONData
}

type SellerInvoiceData {
  id: String
  name: String
  contact: SellerContact
}

type SellerContact {
  phone: String
  email: String
}

type Order {
  orderId: String
  sellerOrderId: String
  totalComission: Float
  totalOrderValue: Float
  totalOrderRate: Float
}

input SearchOrdersParams {
  dateStart: String!
  dateEnd: String!
  sellerName: String!
  page: Int!
  perpage: Int!
  status: String
}

type SearchOrdersResponse {
  data: [OrderSearch]
  paging: PagingOrders
}

type OrderSearch {
  orderId: String
  sellerOrderId: String
  marketplaceOrderId: String
  totalComission: Float
  totalOrderValue: Float
  status: String
  statusDescription: String
  creationDate: String
  rate: [ItemsRateOrdersSearch]
}

type ItemsRateOrdersSearch {
  itemId: String
  nameItem: String
  rate: RateOrders
}

type RateOrders {
  productCommissionPercentage: Float
  freightCommissionPercentage: Float
}

type PagingOrders {
  total: Int
  pages: Int
  currentPage: Int
  perPage: Int
}

input InvoiceDataInput {
  id: String
  name: String
  email: String
  startDate: String
  endDate: String
}

input EmailDataInput {
  email: String
  jsonData: String
}

```


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

[User] Show me the implementation of seller-financial-commission/node/clients/index.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ClientsConfig, IOClients, LRUCache } from '@vtex/api'

import MarketplaceAppClient from './marketplace'
import AffiliatesClient from './affiliates'

export class Clients extends IOClients {
  public get marketplace() {
    return this.getOrSet('marketplace', MarketplaceAppClient)
  }

  public get affiliate() {
    return this.getOrSet('affiliate', AffiliatesClient)
  }

  /* public marketplaceV2(marketplaceURL: string, context: IOContext): any {
    return new MarketplaceFinancialCommission(marketplaceURL, context)
  } */
}

const TIMEOUT_MS = 60000
const memoryCache = new LRUCache<string, any>({ max: 5000 })

metrics.trackCache('seller-financial-commission', memoryCache)

const clients: ClientsConfig<Clients> = {
  implementation: Clients,
  options: {
    default: {
      retries: 2,
      timeout: TIMEOUT_MS,
      memoryCache,
    },
  },
}

export default clients

```


[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 seller-financial-commission/node/typings/custom.d.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
export type Maybe<T> = T | void

export interface InvoiceFilterParams {
  sellerInvoiceParams: {
    pagination: {
      page: number
      pageSize: number
    } | null
    dates: {
      startDate: string
      endDate: string
    }
  }
}

export interface InvoiceData {
  id: string
  name: string
  email: string
  startDate: string
  endDate: string
}

export interface FlatFilters {
  page?: number
  pageSize?: number
  startDate: string
  endDate: string
}

export interface OrderFilterParams {
  searchOrdersParams: {
    dateStart: string
    dateEnd: string
    sellerName: string
    page: number
    perpage: number
    status?: string
  }
}

export interface EmailData {
  email: string
  jsonData: string
}

```


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

[User] Show me the implementation of seller-financial-commission/node/typings/global.d.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { ServiceContext } from '@vtex/api'
import type { Clients } from '../clients'

declare global {
  type Context = ServiceContext<Clients>
}

export {}

```


[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 seller-financial-commission/node/utils/toQueryString.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
export function toQueryString(params: Record<string, any>) {
  return Object.keys(params)
    .map(
      (key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`
    )
    .join('&')
}

```


[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 seller-financial-commission/node/resolvers/getInvoice.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
interface GetInvoiceInput {
  id: string
}

export const getInvoice = async (
  _: unknown,
  params: GetInvoiceInput,
  ctx: Context
) => {
  const {
    vtex: { account: sellerAccount, workspace },
    clients: { marketplace, affiliate },
  } = ctx

  const { id } = params

  const marketplaceAccount = await affiliate.getMarketplaceName()

  const marketplaceReference = {
    account: marketplaceAccount,
    workspace,
  }

  const invoice = await marketplace.getInvoice(
    sellerAccount,
    id,
    marketplaceReference
  )

  return invoice
}

```


[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 seller-financial-commission/node/resolvers/sellerInvoices.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { InvoiceFilterParams } from '../typings/custom'

export const sellerInvoices = async (
  _: unknown,
  params: InvoiceFilterParams,
  ctx: Context
) => {
  const {
    vtex: { account: sellerAccount, workspace },
    clients: { marketplace, affiliate },
  } = ctx

  const marketplaceAccount = await affiliate.getMarketplaceName()

  const marketplaceReference = {
    account: marketplaceAccount,
    workspace,
  }

  const filter = {
    ...params.sellerInvoiceParams.dates,
    ...params.sellerInvoiceParams.pagination,
  }

  const invoices = await marketplace.invoicesBySeller(
    sellerAccount,
    marketplaceReference,
    filter
  )

  return invoices
}

```


[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 seller-financial-commission/node/resolvers/createInvoice.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { InvoiceData } from '../typings/custom'

interface CreateInvoiceInput {
  invoiceData: InvoiceData
}

export const createInvoice = async (
  _: any,
  params: CreateInvoiceInput,
  ctx: Context
) => {
  const {
    vtex: { account: sellerAccount, workspace },
    clients: { marketplace, affiliate },
  } = ctx

  const marketplaceAccount = await affiliate.getMarketplaceName()

  const marketplaceReference = {
    account: marketplaceAccount,
    workspace,
  }

  const response = await marketplace.createInvoice(
    sellerAccount,
    marketplaceReference,
    params.invoiceData
  )

  return response
}

```


[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 seller-financial-commission/node/resolvers/sendEmail.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { EmailData } from '../typings/custom'

interface SendEmailInput {
  emailData: EmailData
}

export const sendEmail = async (
  _: unknown,
  params: SendEmailInput,
  ctx: Context
) => {
  const {
    vtex: { workspace },
    clients: { marketplace, affiliate },
  } = ctx

  const marketplaceAccount = await affiliate.getMarketplaceName()

  const marketplaceReference = {
    account: marketplaceAccount,
    workspace,
  }

  const response = await marketplace.sendEmail(marketplaceReference, {
    email: params.emailData.email,
    jsonData: JSON.parse(params.emailData.jsonData),
  })

  return response
}

```


[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 seller-financial-commission/node/resolvers/index.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { getInvoice } from './getInvoice'
import { getTemplate } from './getTemplate'
import { sendEmail } from './sendEmail'
import { createInvoice } from './createInvoice'
import { sellerInvoices } from './sellerInvoices'
import { sellerOrders } from './sellerOrders'

export const queries = {
  sellerInvoices,
  getInvoice,
  sellerOrders,
  getTemplate,
}

export const mutations = {
  createInvoice,
  sendEmail,
}

```


[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 seller-financial-commission/node/resolvers/sellerOrders.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { OrderFilterParams } from '../typings/custom'
import { toQueryString } from '../utils/toQueryString'

export const sellerOrders = async (
  _: unknown,
  params: OrderFilterParams,
  ctx: Context
) => {
  const {
    vtex: { workspace, account },
    clients: { marketplace, affiliate },
  } = ctx

  const marketplaceAccount = await affiliate.getMarketplaceName()

  const marketplaceReference = {
    account: marketplaceAccount,
    workspace,
  }

  const queryString = toQueryString({
    ...params.searchOrdersParams,
    sellerId: account,
  })

  const invoices = await marketplace.sellerOrders(
    marketplaceReference,
    queryString
  )

  return invoices
}

```


[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 seller-financial-commission/node/resolvers/getTemplate.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const getTemplate = async (_: unknown, __: unknown, ctx: Context) => {
  const {
    vtex: { workspace },
    clients: { marketplace, affiliate },
  } = ctx

  const marketplaceAccount = await affiliate.getMarketplaceName()

  const marketplaceReference = {
    account: marketplaceAccount,
    workspace,
  }

  const template = await marketplace.getTemplate(marketplaceReference)

  return template.template.Templates.email.Message
}

```


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

[User] Show me the implementation of seller-financial-commission/node/clients/marketplace/index.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { AuthType, InstanceOptions, IOClient, IOContext } from '@vtex/api'

import { FlatFilters, InvoiceData, EmailData } from '../../typings/custom'

const useHttps = !process.env.VTEX_IO

interface MarketplaceReference {
  account: string
  workspace: string
}

/**
 * Used to perform calls on the marketplace app installed in the marketplace account.
 */
export default class MarketplaceAppClient extends IOClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    const protocol = useHttps ? 'https' : 'http'
    const appName = 'marketplace-financial-commission'

    super(context, {
      ...options,
      authType: AuthType.bearer,
      baseURL: `${protocol}://app.io.vtex.com/vtex.${appName}/v0`,
      name: appName,
      headers: {
        ...options?.headers,
        ...(context.authToken
          ? { VtexIdclientAutCookie: context.authToken }
          : null),
        'Content-Type': 'application/json',
      },
    })
  }

  public async getInvoice(
    sellerId: string,
    id: string,
    marketplaceReference: MarketplaceReference
  ) {
    return this.http.get(
      this.routes.invoiceById(sellerId, id, marketplaceReference)
    )
  }

  public async createInvoice(
    sellerId: string,
    marketplaceReference: MarketplaceReference,
    invoiceData: InvoiceData
  ) {
    return this.http.post(
      this.routes.newInvoice(sellerId, marketplaceReference),
      invoiceData
    )
  }

  public async invoicesBySeller(
    sellerId: string,
    marketplaceReference: MarketplaceReference,
    filters: FlatFilters
  ) {
    return this.http.post(
      this.routes.invoices(sellerId, marketplaceReference),
      filters
    )
  }

  public async sellerOrders(
    marketplaceReference: MarketplaceReference,
    queryString: string
  ) {
    return this.http.get(this.routes.orders(marketplaceReference, queryString))
  }

  public async getTemplate(marketplaceReference: MarketplaceReference) {
    return this.http.get(this.routes.template(marketplaceReference))
  }

  public async sendEmail(
    marketplaceReference: MarketplaceReference,
    emailData: EmailData
  ) {
    return this.http.post(this.routes.email(marketplaceReference), emailData)
  }

  private get routes() {
    const baseRoute = `_v/policy/financial-commission`

    return {
      invoiceById: (
        sellerId: string,
        id: string,
        { account, workspace }: MarketplaceReference
      ) => `/${account}/${workspace}/${baseRoute}/${sellerId}/invoice/${id}`,
      newInvoice: (
        sellerId: string,
        { account, workspace }: MarketplaceReference
      ) => `/${account}/${workspace}/${baseRoute}/${sellerId}/invoice`,
      invoices: (
        sellerId: string,
        { account, workspace }: MarketplaceReference
      ) => `/${account}/${workspace}/${baseRoute}/${sellerId}/invoices`,
      orders: ({ account, workspace }: MarketplaceReference, query: string) =>
        `/${account}/${workspace}/_v/policy/private/orders?${query}`,
      template: ({ account, workspace }: MarketplaceReference) =>
        `/${account}/${workspace}/${baseRoute}/template`,
      email: ({ account, workspace }: MarketplaceReference) =>
        `/${account}/${workspace}/${baseRoute}/mail`,
    }
  }
}

```


[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 seller-financial-commission/node/clients/affiliates/index.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
import type { InstanceOptions, IOContext, IOResponse } from '@vtex/api'
import { JanusClient } from '@vtex/api'

export interface Affiliate {
  name: string
  id: string
  followUpEmail: string
  salesChannel: string
  searchURIEndpoint: string
  useSellerPaymentMethod: boolean
  searchURIEndpointVersion: string
  searchURIEndpointAvailableVersions: string[]
}

export default class AffiliatesClient extends JanusClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    super(context, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie:
          context.adminUserAuthToken ?? context.authToken ?? '',
        'x-vtex-user-agent': context.userAgent,
      },
    })
  }

  public async getMarketplaceName(): Promise<string> {
    // https://developers.vtex.com/vtex-rest-api/reference/affiliations
    const url = `/api/fulfillment/pvt/affiliates`

    const apiResponse = (await this.http.getRaw(url)) as IOResponse<Affiliate[]>

    const fulfillmentURL = apiResponse.data[0].searchURIEndpoint.split('/')
    const marketplaceAccountName = fulfillmentURL[fulfillmentURL.length - 2]

    return marketplaceAccountName
  }
}

```


[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 seller-financial-commission/react/typings/gql.d.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.gql' {
  import { DocumentNode } from 'graphql'

  const Schema: DocumentNode

  export default Schema
}

declare module '*.graphql' {
  import { DocumentNode } from 'graphql'

  const schema: DocumentNode

  export default 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 seller-financial-commission/react/typings/css.d.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  type Styles = {
    [selector: string]: string
  }

  const styles: Styles

  export default styles
}

```


[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 seller-financial-commission/react/utils/config.ts from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const config = {
  getUrl: (path?: string) => `https://${window.location.host}/${path ?? ''}`,
}

```


[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 seller-financial-commission/react/graphql/sellerInvoices.gql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
query SELLER_INVOICES($sellerInvoiceParams: SellerInvoiceParams) {
  invoicesBySeller: sellerInvoices(sellerInvoiceParams: $sellerInvoiceParams) {
    data {
      id
      status
      invoiceCreatedDate
      totalizers {
        subTotal
        fee
        total
      }
    }
    pagination {
      total
      page
      pageSize
    }
  }
}

```


[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 seller-financial-commission/react/graphql/getInvoice.gql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
query GET_INVOICE($id: String!) {
  getInvoice(id: $id) {
    status
    invoiceCreatedDate
    seller {
      id
      name
      contact {
        phone
        email
      }
    }
    orders {
      orderId
      sellerOrderId
      totalComission
      totalOrderValue
      totalOrderRate
    }
    totalizers {
      subTotal
      fee
      total
    }
    comment
    jsonData
  }
}

```


[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 seller-financial-commission/react/graphql/sendEmail.gql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation SEND_EMAIL($emailData: EmailDataInput!) {
  sendEmail(emailData: $emailData)
}

```


[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 seller-financial-commission/react/graphql/getTemplate.gql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
query GET_TEMPLATE($variables: String) {
  getTemplate
}

```


[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 seller-financial-commission/react/graphql/sellerOrders.gql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
query SELLER_ORDERS($searchOrdersParams: SearchOrdersParams) {
  orders: sellerOrders(searchOrdersParams: $searchOrdersParams) {
    data {
      orderId
      sellerOrderId
      marketplaceOrderId
      totalComission
      totalOrderValue
      status
      statusDescription
      creationDate
      rate {
        itemId
        nameItem
        rate {
          productCommissionPercentage
          freightCommissionPercentage
        }
      }
    }
    paging {
      total
      pages
      currentPage
      perPage
    }
  }
}

```


[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 seller-financial-commission/react/graphql/createInvoice.gql from the seller-financial-commission VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation CREATE_INVOICE($invoiceData: InvoiceDataInput!) {
  createInvoice(invoiceData: $invoiceData)
}

```


[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 seller-selector/messages/de.json from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "Postleitzahl zur Berechnung eingeben",
  "store/seller-list.shipping-label": "Versand berechnen",
  "store/seller-link.linkText": "{sellerQuantity, plural, one {1 weiterer Verkäufer} other {# weitere Verkäufer}} anzeigen",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "Verkäuferauswahl",
  "admin/editor.seller-selector.head-cell": "Kopfzelle",
  "admin/editor.seller-selector.head-cell-text": "Kopfzeilentext",
  "admin/editor.seller-selector.limitShippingInformation-title": "Wie viele Versandkosten sollen angezeigt werden?",
  "admin/editor.seller-selector.limitShippingInformation-description": "Legen Sie fest, wie viele Versandkosten angezeigt werden sollen. Diese Konfiguration wird auf alle Verkäufer dieser Seite angewendet",
  "admin/editor.seller-selector.add-to-cart": "Zum Einkaufswagen hinzufügen",
  "admin/editor.seller-selector.oneClickBuy-title": "Weiterleitung zur Kasse",
  "admin/editor.seller-link.title": "Verkäufer-Link",
  "admin/editor.seller-link.textLinkTitle": "Link-Text",
  "admin/editor.seller-link.textLinkDescription": "Verfügbare Werte für Interpolation: '{sellerQuantity}'"
}

```


[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 seller-selector/messages/pl.json from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "Wpisz kod pocztowy, aby obliczyć",
  "store/seller-list.shipping-label": "Oblicz wysyłkę",
  "store/seller-link.linkText": "Wyświetl {sellerQuantity, plural, one {1 sprzedawcę więcej} few {# sprzedawców więcej} many {# sprzedawców więcej} other {# sprzedawcy więcej}}",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "Wybór sprzedawcy",
  "admin/editor.seller-selector.head-cell": "Komórka nagłówka",
  "admin/editor.seller-selector.head-cell-text": "Tekst komórki nagłówka",
  "admin/editor.seller-selector.limitShippingInformation-title": "Ile ofert wysyłki ma zostać wyświetlonych?",
  "admin/editor.seller-selector.limitShippingInformation-description": "Skonfiguruj liczbę wyświetlonych ofert wysyłki; ta konfiguracja zostanie zastosowana do wszystkich sprzedawców na tej stronie",
  "admin/editor.seller-selector.add-to-cart": "Dodaj do koszyka",
  "admin/editor.seller-selector.oneClickBuy-title": "Przekieruj do kasy",
  "admin/editor.seller-link.title": "Łącze sprzedawcy",
  "admin/editor.seller-link.textLinkTitle": "Tekst łącza",
  "admin/editor.seller-link.textLinkDescription": "Wartości dostępne do interpolacji: „{sellerQuantity}”"
}
```


[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 seller-selector/messages/pt.json from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "Digite o CEP para calcular",
  "store/seller-list.shipping-label": "Calcular o frete",
  "store/seller-link.linkText": "Verificar {sellerQuantity, plural, one {uma outra loja} other {# outras lojas}}",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "Seletor de vendedor",
  "admin/editor.seller-selector.head-cell": "Cabeçalho",
  "admin/editor.seller-selector.head-cell-text": "Texto do cabeçalho",
  "admin/editor.seller-selector.limitShippingInformation-title": "Quantas cotações de frete devem aparecer?",
  "admin/editor.seller-selector.limitShippingInformation-description": "Configure quantas informações de frete devem ser exibidas na tela simultaneamente, esta configuração será aplicada a todos os vendedores nessa pagina",
  "admin/editor.seller-selector.add-to-cart": "Adicionar Ao Carrinho",
  "admin/editor.seller-selector.oneClickBuy-title": "Redirect to checkout",
  "admin/editor.seller-link.title": "Link de vendedor",
  "admin/editor.seller-link.textLinkTitle": "Texto do link",
  "admin/editor.seller-link.textLinkDescription": "Valores disponíveis para interpolação: '{sellerQuantity}'"
}

```


[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 seller-selector/messages/ar-SA.json from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "اكتب الرمز البريدي لاحتساب",
  "store/seller-list.shipping-label": "حساب الشحن",
  "store/seller-link.linkText": "View {sellerQuantity, plural, one {بائع إضافي} other {# باعة إضافيين}}",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "محدد البائع",
  "admin/editor.seller-selector.head-cell": "خانة الترويسة",
  "admin/editor.seller-selector.head-cell-text": "نص الخلية للترويسة",
  "admin/editor.seller-selector.limitShippingInformation-title": "كم عدد عروض الشحن التي ينبغي عرضها؟",
  "admin/editor.seller-selector.limitShippingInformation-description": "إعداد عدد عروض الشحن التي يجب عرضها، سيتم تطبيق هذا الإعداد على جميع البائعين في هذه الصفحة",
  "admin/editor.seller-selector.add-to-cart": "أضف لعربة التسوق",
  "admin/editor.seller-selector.oneClickBuy-title": "إعادة التوجيه إلى الدفع",
  "admin/editor.seller-link.title": "رابط البائع",
  "admin/editor.seller-link.textLinkTitle": "نص الرابط",
  "admin/editor.seller-link.textLinkDescription": "القيم المتاحة للاستقطاب: '{sellerQuantity}'"
}

```


[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 seller-selector/messages/en.json from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "Type postal code to calculate",
  "store/seller-list.shipping-label": "Calculate shipping",
  "store/seller-link.linkText": "View {sellerQuantity, plural, one {1 more seller} other {# more sellers}}",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "Seller Selector",
  "admin/editor.seller-selector.head-cell": "Header Cell",
  "admin/editor.seller-selector.head-cell-text": "Header Cell Text",
  "admin/editor.seller-selector.limitShippingInformation-title": "How many shipping quotes should be displayed?",
  "admin/editor.seller-selector.limitShippingInformation-description": "Configure how many shipping quotes should be displayed, this configuration will be applied to all sellers in this page",
  "admin/editor.seller-selector.add-to-cart": "Add To Cart",
  "admin/editor.seller-selector.oneClickBuy-title": "Redirect to checkout",
  "admin/editor.seller-link.title": "Seller Link",
  "admin/editor.seller-link.textLinkTitle": "Link text",
  "admin/editor.seller-link.textLinkDescription": "Values available for interpolation: '{sellerQuantity}'"
}

```


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

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "Type postal code to calculate",
  "store/seller-list.shipping-label": "Calculate shipping",
  "store/seller-link.linkText": "View {sellerQuantity, plural, one {1 more seller} other {# more sellers}}",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "Seller Selector",
  "admin/editor.seller-selector.head-cell": "Header Cell",
  "admin/editor.seller-selector.head-cell-text": "Header Cell Text",
  "admin/editor.seller-selector.limitShippingInformation-title": "How many shipping quotes should be displayed?",
  "admin/editor.seller-selector.limitShippingInformation-description": "Configure how many shipping quotes should be displayed, this configuration will be applied to all sellers in this page",
  "admin/editor.seller-selector.add-to-cart": "Add To Cart",
  "admin/editor.seller-selector.oneClickBuy-title": "Redirect to checkout",
  "admin/editor.seller-link.title": "Seller Link",
  "admin/editor.seller-link.textLinkTitle": "Link text",
  "admin/editor.seller-link.textLinkDescription": "Values available for interpolation: '{sellerQuantity}'"
}

```


[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 seller-selector/messages/es.json from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store/seller-list.pending": "Escriba el código postal para calcular",
  "store/seller-list.shipping-label": "Calcular el flete",
  "store/seller-link.linkText": "Verifique {sellerQuantity, plural, one {otro vendedor} other {# otros vendedores}}",
  "store/seller-list.shipping-estimate": "{name} {price} {estimate}",
  "admin/editor.seller-selector.title": "Selector de vendedor",
  "admin/editor.seller-selector.head-cell": "Celda de encabezado",
  "admin/editor.seller-selector.head-cell-text": "Texto de celda de encabezado",
  "admin/editor.seller-selector.limitShippingInformation-title": "¿Cuántas cotizaciones de envío se deben mostrar?",
  "admin/editor.seller-selector.limitShippingInformation-description": "Configure cuántas cotizaciones de envío deben mostrarse, esta configuración se aplicará a todos los vendedores en esta página",
  "admin/editor.seller-selector.add-to-cart": "Añadir al carrito",
  "admin/editor.seller-selector.oneClickBuy-title": "Redireccionar a pagar",
  "admin/editor.seller-link.title": "Enlace del vendedor",
  "admin/editor.seller-link.textLinkTitle": "Texto del enlace",
  "admin/editor.seller-link.textLinkDescription": "Valores disponibles para interpolación: '{sellerQuantity}'"
}

```


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

[Assistant]
Here's the implementation:

```markdown
# Seller Selector

Seller Selector displays the number of [**sellers**](https://help.vtex.com/tutorial/what-is-a-seller--5FkLvhZ3Few4CWWIuYOK2w) your marketplace has for each product. It enables users to compare prices from each seller and add the desired product to their cart.

![exampleLayout](https://user-images.githubusercontent.com/53904010/78715148-595eea00-78f3-11ea-90fa-dc38c37a80d8.png)

## Configuration

1. Install the Seller Selector app to your store with the following command:
```sh
vtex install vtex.seller-selector@0.x
```

2. Add the Seller Selector app to your theme's dependencies in the `manifest.json` as shown below:

```json
"dependencies": {
  "vtex.seller-selector": "0.x"
}
```

3. Add the `link-seller` block, exported by the `vtex.seller-selector` app, inside your product page (`store.product` template). When rendered, the block will create a link to the Seller Selector main page. For example:

```diff
 "flex-layout.col#right-col": {
    "props": {
      "preventVerticalStretch": true,
      "rowGap": 0
    },
    "children": [
      "product-name",
+     "link-seller"
      "product-price#product-details",
      "product-separator",
      "flex-layout.row#buy-button",
      "availability-subscriber",
      "shipping-simulator",
      "share#default"
    ]
  },
```

By declaring the `link-seller` block, a page containing all available sellers will be displayed automatically. However, you can configure the Seller Selector page layout, using props for each one of the blocks used to build it behind the scenes.

### Advanced Configuration
Behind the scenes, the Seller Selector page uses the following default implementation:

```json
{
  "store.sellers": {
    "blocks": [
      "seller-table"
    ]
  },
  "seller-table": {
    "children": [
      "vtex.store-components:product-name",
      "seller-simulate-shipping",
      "seller-head",
      "seller-body"
    ]
  },
  "seller-head": {
    "children": [
      "seller-head-cell#Seller",
      "seller-head-cell#Price",
      "seller-head-cell#Shipping",
      "seller-head-cell#PriceWithShipping",
      "seller-head-cell#BuyButton"
    ]
  },
  "seller-head-cell#Seller": {
    "props": {
      "title": "Seller"
    }
  },
  "seller-head-cell#Price": {
    "props": {
      "title": "Price"
    }
  },
  "seller-head-cell#Shipping": {
    "props": {
      "title": "Shipping"
    }
  },
  "seller-head-cell#PriceWithShipping": {
    "props": {
      "title": "Price With Shipping"
    }
  },
  "seller-head-cell#BuyButton": {
    "props": {
      "title": "Add To Cart"
    }
  },
  "seller-body": {
    "children": [
      "seller-row"
    ]
  },
  "seller-row": {
    "children": [
      "seller-name",
      "seller-price",
      "seller-shipping",
      "seller-price-with-shipping",
      "seller-add-to-cart"
    ]
  },
  "seller-add-to-cart":{
    "blocks":[
      "add-to-cart-button"
    ]
  }
}
```

| Block name   | Description  |
| -------- | ------------------------ |
| `seller-table`     |  Layout block that provides a table to build the Seller Selector page with other blocks. It is possible to build the page using three main blocks: `seller-simulate-shipping`, `seller-head` and `seller-body` (declared as children of `seller-head`).
| `seller-simulate-shipping`  | Builds a form so users can add a postal code and then simulate the shipping costs to the desired address. |
| `seller-head`  | Builds a header to be used on the Seller Selector table. You can pass to it the `seller-head-cell` block as children. |
| `seller-head-cell` | Defines a title for each column in the table header. |
| `seller-body`  | Defines the page main content. It is responsible for displaying all sellers' data in the table body.|
| `seller-row`  | Used inside the Seller Selector table to separate seller's data into columns. You can use the blocks listed below (`seller-name`, `seller-price`, `seller-shipping`, `seller-price-with-shipping`, `seller-add-to-cart`) as `seller-row`'s children in order to provide all needed seller's data. |
| `seller-name` | Displays the seller name. |
| `seller-price` | Displays the seller price for a given product. |
| `seller-shipping` | Displays shipping cost considering the sellers' data. |
| `seller-price-with-shipping` | Displays the purchase final cost (shipping cost + product price). |
| `seller-add-to-cart` | Displays a Buy button that adds a given seller's product to the shopping cart. It is possible to use two different blocks inside of it `buy-button` or `add-to-cart-button` |
|`buy-button`  | Default buy button, will be used if nothing is provided in the blocks section of `seller-add-to-cart`|
|`add-to-cart-button`  | Buy button to use with Minicart.V2 and GoCommerce Stores |

#### `link-seller` props

| Prop name              | Type      | Description                                                                                | Default value |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `message`     | `string`  | Text displayed on link counter | `store/seller-link.linkText`|

| Message variables | Type | Description | Example |
| --- | --- | --- | --- |
| `sellerQuantity` | `number` | Number of sellers sell this product | <code>View {**sellerQuantity**, plural, one {1 more seller} other {# more sellers}}</code> |

This block uses the [ICU Message Format](https://format-message.github.io/icu-message-format-for-translators/), making it possible to fully edit the text message and variables displayed on block.

#### `seller-table` props

| Prop name              | Type      | Description                                                                                | Default value |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `limitShownShippingInformation`       | `number`  | Max number of shipping options to be displayed.                                                                                | `3`         |

#### `seller-add-to-cart` props

| Prop name              | Type      | Description                                                                                | Default value |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `isOneClickBuy`          | `boolean` | Defines if users will keep navigating in the same page once the Buy button was clicked on (`true`) or if they will be redirected (`false`)   | `false`         |

#### `seller-head-cell` props

| Prop name              | Type      | Description                                                                                | Default value |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `title`     | `string`  | Text displayed on the table header for each column. | `undefined`|

## Modus operandi
The Seller Selector app fetch seller's data automatically from the [admin's Catalog ](https://help.vtex.com/tutorial/configuring-the-seller--tutorials_392).
Behind the scenes, the blocks exported from the app use the product context in which they are inserted to identify the seller's data in the SKU registry.
Based on this, they are able to display seller data without having to declare each desired seller in your theme.

## Customization

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

| CSS Handles                     |
| ------------------------------- |
| `linkSellerContainer`           |
| `linkSeller`                    |
| `linkSellerText`                |
| `linkSellerNumber`              |
| `sellerMasterContainer`         |
| `sellerBuyContainer`            |
| `sellerList`                    |
| `sellerBodyCell`                |
| `sellerHead`                    |
| `sellerHeadCell`                |
| `sellerHeadText`                |
| `sellerName`                    |
| `sellerPrice`                   |
| `sellerPriceShipping`           |
| `sellerPriceShippingText`       |
| `sellerRow`                     |
| `sellerShipping`                |
| `sellerShippingText`            |
| `sellerRow`                     |
| `simulateShipping`              |
| `simulateShippingSearch`        |
| `simulateShippingSpinner`       |

```


[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 seller-selector/react/SimulateShipping.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import { useCssHandles } from 'vtex.css-handles'
import { useLazyQuery } from 'react-apollo'
import { useRuntime } from 'vtex.render-runtime'
import {
  AddressRules,
  AddressContainer,
  PostalCodeGetter,
} from 'vtex.address-form'
import { StyleguideInput } from 'vtex.address-form/inputs'
import { Button, Spinner } from 'vtex.styleguide'
import { useProduct } from 'vtex.product-context'
import { addValidation } from 'vtex.address-form/helpers'
import { FormattedMessage } from 'react-intl'
import './global.css'

import SimulateShippingQuery from './queries/SimulateShipping.gql'
import { useSellerContext } from './SellerContext'
import { getNewAddress } from './utils'

const SIMULATE_SHIPPING_CSS_HANDLES = [
  'simulateShipping',
  'simulateShippingSearch',
  'simulateShippingSpinner',
] as const

function SimulateShipping() {
  const handles = useCssHandles(SIMULATE_SHIPPING_CSS_HANDLES)
  const { selectedItem, selectedQuantity } = useProduct() ?? {}
  const { setShippingQuotes } = useSellerContext()
  const [updateShippingQuotes, { loading, data }] = useLazyQuery(
    SimulateShippingQuery
  )

  let shippingItems = null

  const runtime = useRuntime()
  const {
    culture: { country },
  } = runtime

  if (selectedItem) {
    shippingItems = selectedItem.sellers.map((current) => ({
      id: selectedItem.itemId,
      quantity: selectedQuantity?.toString() ?? '1',
      seller: current.sellerId,
    }))
  }

  const variables = {
    shippingItems,
    country,
    postalCode: '',
  }

  const [address, setAddress] = useState(() =>
    addValidation(getNewAddress(country))
  )

  if (data) {
    setShippingQuotes(data.shipping)
  }

  function handleAddressChange(newAddress: any) {
    const updatedAddress = {
      ...address,
      ...newAddress,
    }

    setAddress(updatedAddress)
    if (updatedAddress.postalCode.valid) {
      const postalCode = updatedAddress.postalCode.value

      updateShippingQuotes({ variables: { ...variables, postalCode } })
    }
  }

  const showSpinner = () => {
    if (loading) {
      return (
        <div className={`${handles.simulateShippingSpinner} ml4 mt6`}>
          <Spinner />
        </div>
      )
    }

    return null
  }

  return (
    <div
      className={`${handles.simulateShipping} mt7 flex mr-auto ml-auto mw6 ba-s b--muted-3 pl4 pv5 pb5 mb3 br2`}
    >
      <AddressRules country={country} shouldUseIOFetching>
        <AddressContainer
          Input={StyleguideInput}
          address={address}
          onChangeAddress={handleAddressChange}
        >
          <PostalCodeGetter />
        </AddressContainer>
      </AddressRules>
      <Button
        className={`${handles.simulateShippingSearch} ba-s b--muted-3 br3-s bg-action-primary red`}
        size="small"
        type="submit"
        block
      >
        <FormattedMessage id="store/seller-list.shipping-label" />
      </Button>
      {showSpinner()}
    </div>
  )
}

export default SimulateShipping

```


[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 seller-selector/react/CurrentSellerContext.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

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

import { Seller, LogisticsInfo } from './SellerContext'

const CurrentSellerContext = createContext<CurrentSellerContextValue>({
  currentSeller: null,
  shipping: null,
})

interface CurrentSellerContextValue {
  currentSeller: Seller | null
  shipping: LogisticsInfo | null
}

export const useCurrentSeller = () => {
  return useContext(CurrentSellerContext)
}

interface ProviderProps {
  value: CurrentSellerContextValue
}

export const CurrentSellerProvider: FC<ProviderProps> = ({
  value,
  children,
}) => {
  return (
    <CurrentSellerContext.Provider value={value}>
      {children}
    </CurrentSellerContext.Provider>
  )
}

export default {
  CurrentSellerProvider,
  useCurrentSeller,
}

```


[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 seller-selector/react/SellerName.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

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

import { useCurrentSeller } from './CurrentSellerContext'

const SELLERS_CSS_HANDLES = ['sellerName'] as const

function SellerName() {
  const { currentSeller } = useCurrentSeller()
  const handles = useCssHandles(SELLERS_CSS_HANDLES)

  return (
    <p
      className={`${handles.sellerName} items-center tc w-100-s w-20-m  br2 ph6 pv4 ma0 b`}
    >
      {currentSeller?.sellerName}
    </p>
  )
}

export default SellerName

```


[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 seller-selector/react/global.css from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```css
.vtex-store-components-3-x-simulateShipping .vtex-input {
  height: 100%;
}

.vtex-store-components-3-x-simulateShipping .vtex-input input {
  padding: 10px 5px;
  color: #4f4f4f;
  border: 1px solid #e3e4e6;
  border-radius: 2px;
  height: 100%;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.vtex-seller-selector-0-x-simulateShipping .vtex-button {
  border-radius: 2px;
  width: auto;
  height: 3.8rem;
  margin-left: 0.875rem;
  margin-top: 0.875rem;
}

.spinnerContainer{
  margin-left: 0.875rem;
  margin-top: 1.5rem;
}

.vtex-seller-selector-0-x-sellerMasterContainer h1{
  font-weight: 700;
  text-align: center;
  margin-top: 30px;
}

.vtex-seller-selector-0-x-sellerShippingText , .vtex-seller-selector-0-x-sellerPriceShippingText{
  padding: 5px;;
  min-height: 50px;
}

.vtex-seller-selector-0-x-sellerShippingText:nth-child(even) , .vtex-seller-selector-0-x-sellerPriceShippingText:nth-child(even){
  background-color: #b0b0b085;
}

@media only screen and (max-width: 540px) {
  .vtex-seller-selector-0-x-simulateShipping{
    flex-direction: column;
    padding: 10px;
    margin: 35px;
  }
  .vtex-seller-selector-0-x-sellerName{
    background: #cacbcc;
    border-radius: 0px;
  }
}
```


[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 seller-selector/react/SellerHead.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { ReactNode } from 'react'
import { useCssHandles } from 'vtex.css-handles'

const SELLERS_CSS_HANDLES = ['sellerHead'] as const

interface Props {
  children: ReactNode
}

function SellerHead({ children }: Props) {
  const handles = useCssHandles(SELLERS_CSS_HANDLES)

  return (
    <div
      className={`${handles.sellerHead} mh7 mt1 justify-between-s dn-s flex-m items-center-s br2 bg-muted-3 hover-bg-muted-3 active-bg-muted-3 c-on-muted-3 hover-c-on-muted-3 active-c-on-muted-3 dib`}
    >
      {children}
    </div>
  )
}

export default SellerHead

```


[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 seller-selector/react/SellerAddToCart.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

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

import { useCurrentSeller } from './CurrentSellerContext'

const SELLERS_CSS_HANDLES = ['sellerBuyContainer'] as const

interface Props {
  isOneClickBuy?: boolean
}

function SellerAddToCart({ isOneClickBuy }: Props) {
  const { currentSeller } = useCurrentSeller()
  const handles = useCssHandles(SELLERS_CSS_HANDLES)

  const useAddToCart = !!useChildBlock({ id: 'add-to-cart-button' })

  return (
    <div
      className={`${handles.sellerBuyContainer} items-center tc br2 ph6 pv4 ma0 w-100-s w-20-m`}
    >
      <ExtensionPoint
        id={useAddToCart ? 'add-to-cart-button' : 'buy-button'}
        {...{ isOneClickBuy, selectedSeller: currentSeller }}
      />
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.add-to-cart',
  },
  isOneClickBuy: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.oneClickBuy-title',
  },
})

SellerAddToCart.schema = {
  title: messages.title.id,
  type: 'object',
  properties: {
    isOneClickBuy: {
      title: messages.isOneClickBuy.id,
      type: 'boolean',
      default: false,
    },
  },
}

export default SellerAddToCart

```


[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 seller-selector/react/SellerPriceWithShipping.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { FormattedCurrency } from 'vtex.format-currency'
import { FormattedMessage } from 'react-intl'
import { useCssHandles } from 'vtex.css-handles'

import { useCurrentSeller } from './CurrentSellerContext'
import { useSellerContext } from './SellerContext'

const SELLERS_CSS_HANDLES = [
  'sellerPriceShipping',
  'sellerPriceShippingText',
] as const

function SellerPriceWithShipping() {
  const { currentSeller, shipping } = useCurrentSeller()
  const { limitShownShippingInformation } = useSellerContext()
  const handles = useCssHandles(SELLERS_CSS_HANDLES)

  return (
    <div
      className={`${handles.sellerPriceShipping} ma0 items-center tc br2 ph6 pv4 ma0 w-100-s w-20-m`}
    >
      {shipping ? (
        shipping.slas
          .slice(0, limitShownShippingInformation)
          .map((sla, index: number) => (
            <p key={index} className={`${handles.sellerPriceShippingText} ma0`}>
              <FormattedCurrency
                value={
                  sla.price / 100.0 +
                  (currentSeller ? currentSeller.commertialOffer.Price : 0)
                }
              />
            </p>
          ))
      ) : (
        <FormattedMessage id="store/seller-list.pending" />
      )}
    </div>
  )
}

export default SellerPriceWithShipping

```


[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 seller-selector/react/SellerHeadCell.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { PropsWithChildren } from 'react'
import { useCssHandles } from 'vtex.css-handles'
import { defineMessages } from 'react-intl'

const SELLERS_CSS_HANDLES = ['sellerHeadCell', 'sellerHeadText'] as const

interface Props {
  title: string
}

function SellerHeadCell({ title, children }: PropsWithChildren<Props>) {
  const handles = useCssHandles(SELLERS_CSS_HANDLES)

  return (
    <div className={`${handles.sellerHeadCell} w-20`}>
      {title ? (
        <h5
          className={`${handles.sellerHeadText} items-center tc ph6 pv4 ma0 t-heading-6`}
        >
          {title}
        </h5>
      ) : null}
      {children}
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.head-cell',
  },
  text: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.head-cell-text',
  },
})

SellerHeadCell.schema = {
  title: messages.title.id,
  type: 'object',
  properties: {
    title: {
      title: messages.text.id,
      type: 'string',
      default: '',
    },
  },
}

export default SellerHeadCell

```


[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 seller-selector/react/SellerTable.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useMemo, useState } from 'react'
import type { PropsWithChildren } from 'react'
import { useProduct } from 'vtex.product-context'
import { useCssHandles } from 'vtex.css-handles'
import { defineMessages } from 'react-intl'

import { SellerProvider } from './SellerContext'
import type { ShippingQuote } from './SellerContext'

const SELLERS_CSS_HANDLES = ['sellerMasterContainer'] as const

interface Props {
  limitShownShippingInformation: number
}

function SellerTable({
  limitShownShippingInformation,
  children,
}: PropsWithChildren<Props>) {
  const handles = useCssHandles(SELLERS_CSS_HANDLES)
  const { selectedItem } = useProduct() ?? {}
  const [shippingQuotes, setShippingQuotes] = useState<ShippingQuote | null>(
    null
  )

  const sellerContext = useMemo(
    () => ({
      sellerList: selectedItem
        ? selectedItem.sellers.filter(
            (seller) => seller.commertialOffer.AvailableQuantity > 0
          )
        : null,
      shippingQuotes,
      setShippingQuotes,
      limitShownShippingInformation: limitShownShippingInformation || 3,
    }),
    [limitShownShippingInformation, selectedItem, shippingQuotes]
  )

  return (
    <div className={`${handles.sellerMasterContainer}`}>
      <SellerProvider value={sellerContext}>{children}</SellerProvider>
    </div>
  )
}

const messages = defineMessages({
  title: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.title',
  },
  shippingInformationTitle: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.limitShippingInformation-title',
  },
  shippingInformationDescription: {
    defaultMessage: '',
    id: 'admin/editor.seller-selector.limitShippingInformation-description',
  },
})

SellerTable.schema = {
  title: messages.title.id,
  type: 'object',
  properties: {
    limitShownShippingInformation: {
      title: messages.shippingInformationTitle.id,
      description: messages.shippingInformationDescription.id,
      type: 'number',
      default: 3,
    },
  },
}

export default SellerTable

```


[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 seller-selector/react/SellerBodyCell.tsx from the seller-selector VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import type { ReactNode } from 'react'
import { useCssHandles } from 'vtex.css-handles'

const SELLERS_CSS_HANDLES = ['sellerBodyCell'] as const

interface Props {
  children: ReactNode
}

function SellerBodyCell({ children }: Props) {
  const handles = useCssHandles(SELLERS_CSS_HANDLES)

  return (
    <div
      className={`${handles.sellerBodyCell} items-center tc w-100-s w-20-m br2 ph6 pv4 ma0 w-100-s w-20-m`}
    >
      {children}
    </div>
  )
}

export default SellerBodyCell

```