Untitled

mail@pastecode.io avatar
unknown
javascript
2 years ago
14 kB
2
Indexable
Never
import React, { useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import styled from 'styled-components'
import qs from 'qs'

import { Paper } from '@material-ui/core'

import UtmUtils from '../../utils/utmUtils'
import { EventLogs } from '../../constants/eventLogs'
import {
  setActiveCallCard,
  CALL_CARD_CART,
  selectUiSize,
  UI_IS_TABLET,
  selectCartEnabled,
} from '../../reducers/uiSlice'
import { selectCurrentStore } from '../../reducers/storeSlice'
import StoreUtils from '../../utils/storeUtils'
import { usePDP } from '../../hooks/usePDP'
import { addProductIntoCart, setCartInitialized } from '../../reducers/cartSlice'
import { saveLog, saveLogEs } from '../../reducers/userLogSlice'
import Select from '../Kit/Select'
import Select2 from '../Kit/Select2'
import { OriginalPrice } from '../Call/DesktopCards/DesktopProducts'
import { Button } from '../Kit/Buttons/Button'
import { ProductPriceWithDue } from '../Kit/ProductDue'
import { useTranslation } from 'react-i18next'
import { useStoreState } from 'easy-peasy'
import useLogsOnCartInitialize from '../../hooks/useLogsOnCartInitialize'
import { EventLogsEs } from '../../constants/eventLogsEs'
import { QuantityHandler } from './QuantityHandler'
import PaymentGateways from '../../strategy/payment/constants'
import { StyledButton } from './GoToCheckout'
const MAX_CHARACTERS_TO_DISPLAY = 47

export const productHasVariant = (product) =>
  (product.variants?.length > 0 || product.variantId) && true

export const ProductDetail = () => {
  const { t } = useTranslation('global')
  const {
    auth: { user },
  } = useStoreState((state) => state)
  const dispatch = useDispatch()
  const { pdp, hidePDP } = usePDP()
  const product = pdp
  const store = useSelector(selectCurrentStore)
  const [paymentGateway] = StoreUtils.getPaymentGateways(store)

  const {
    description,
    price,
    originalPrice,
    imageUrl,
    productHasDue = product?.dueQuantity > 0,
    variants,
    variantOptions,
  } = product
  const [selectedItem, setSelectedItem] = useState(0)
  const [isNotAvailable, setIsNotAvailable] = useState(false)
  const [error, setError] = useState(false)
  const [showFromText, setShowFromText] = useState(productHasVariant(product) && variantOptions)
  const [productQuantityPDP, setProductQuantityPDP] = useState(0)
  const [selectedVariant, setSelectedVariant] = useState(null)
  const [selectedOldVariant, setSelectedOldVariant] = useState(null)
  const [selectStatus, setSelectStatus] = useState([])
  const isCencosudParis = paymentGateway.type === PaymentGateways.CENCOSUD_PARIS

  const variantIsSelected =
    variantOptions &&
    selectedVariant?.length == variants?.length &&
    selectStatus.filter((e) => e).length == variants?.length &&
    selectStatus.every((e) => e)

  const getAvailableVariant = () => variantOptions?.map((item) => item.option)

  useEffect(() => {
    const availableVariant = getAvailableVariant()
    if (availableVariant) {
      setSelectedVariant(availableVariant[0])
    }
  }, [])

  useEffect(() => {
    if (!getAvailableVariant() || !selectedVariant) {
      return
    }
    if (variants.length > selectedVariant.filter(Boolean).length) {
      return
    }
    for (let [j, variant] of getAvailableVariant().entries()) {
      let isVariantMatch = true

      for (let [i, option] of variant.entries()) {
        if (option !== selectedVariant[i]) {
          isVariantMatch = false
          setIsNotAvailable(true)
          break
        }
      }
      if (isVariantMatch) {
        setSelectedItem(j)
        setIsNotAvailable(false)
        setError(false)
        break
      }
    }
    if (variantIsSelected) {
      setShowFromText(false)
    }
  }, [selectedVariant])

  const onVariantChange = (i, option) => {
    let arr = [...selectedVariant]
    arr[i] = option
    setSelectedVariant(arr)
  }

  function onOldVariantChange(option) {
    setSelectedOldVariant(option)
    setError(false)
  }

  const queryParams = qs.parse(window.location.search, { ignoreQueryPrefix: true })
  const uiSize = useSelector(selectUiSize)
  const cartEnabled = useSelector(selectCartEnabled)
  const { sendLogs } = useLogsOnCartInitialize()

  const onProductAdded = (product, variant) => {
    sendLogs(product)
    dispatch(setCartInitialized())
    dispatch(
      saveLog({
        data: { storeId: store.id, producId: product.id },
        type: EventLogs.PRODUCT_ADDED_TO_CART,
        userId: user.id,
        ...UtmUtils.getUtmObject(queryParams),
      }),
    )
    dispatch(
      saveLogEs({
        data: {
          storeId: store.id,
          storeName: store.name,
          createdAt: Date.now(),
          companyName: store.company.name,
          products: product.name,
          eventType: EventLogsEs.PRODUCT_ADDED_TO_CART,
          userId: user.id ?? EventLogsEs.ANONIMO_WEB,
          ...UtmUtils.getUtmObject(queryParams),
        },
        index: 'events_'
          .concat(EventLogsEs.PRODUCT_ADDED_TO_CART)
          .concat('_companies_')
          .concat(store.companyId),
      }),
    )
    let productToCart
    if (variantOptions) {
      productToCart = {
        description: product.description,
        price: variantOptions[selectedItem].price,
        originalPrice: variantOptions[selectedItem].originalPrice,
        imageUrl: variantOptions[selectedItem].imageUrl,
        sku: variantOptions[selectedItem].sku,
        id: variantOptions[selectedItem].id,
        quantity: productQuantityPDP,
        total: variantOptions[selectedItem].price * productQuantityPDP,
      }
    } else {
      productToCart = {
        ...product,
        quantity: productQuantityPDP,
        total: product.price * productQuantityPDP,
      }
    }
    dispatch(addProductIntoCart({ product: productToCart, variant }))
    hidePDP()
  }

  const updateSelectStatus = (index, selectStatusBool) => {
    const updateSelectStatus = [...selectStatus]
    updateSelectStatus[index] = selectStatusBool
    setSelectStatus(updateSelectStatus)
  }

  const printVariantsName = (variants) => {
    let errorText = t('products.errorTextOne')

    if (variants.storeId) {
      return errorText.concat(` ${variants.name}`)
    } else {
      variants.forEach((variant, i) => {
        const isUniqueVariant = variants.length === 1
        if (i == variants.length - 1 && !isUniqueVariant) {
          errorText = errorText.concat(
            `${t('products.errorTextTwo')} ${(variant.label ?? variant.name).toLowerCase()}`,
          )
        } else if (i == 0) {
          errorText = errorText.concat(`${(variant.label ?? variant.name).toLowerCase()} `)
        } else {
          {
            errorText = errorText.concat(`, ${(variant.label ?? variant.name).toLowerCase()} `)
          }
        }
      })
      return errorText
    }
  }

  const onAddClicked = () => {
    if (variantIsSelected) {
      onProductAdded(product, selectedVariant)
    } else if (!variantOptions && (!product.variant || selectedOldVariant)) {
      onProductAdded(product, selectedOldVariant)
    } else {
      setError(true)
    }
  }

  return (
    <>
      <ProductImage data-test="inner-preview-image" elevation={3}>
        <div>
          <img
            src={variantOptions ? variantOptions[selectedItem]?.imageUrl : imageUrl}
            alt={description}
          />
        </div>
      </ProductImage>
      {productHasDue ? (
        <RowWithDue>
          <ProductDescription
            isLongLength={description.length > MAX_CHARACTERS_TO_DISPLAY}
            data-test="pdp-product-description"
          >
            {description}
          </ProductDescription>
          <ProductPriceWithDue product={product} />
        </RowWithDue>
      ) : (
        <Row>
          <ProductDescription
            isLongLength={description.length > MAX_CHARACTERS_TO_DISPLAY}
            data-test="pdp-product-description"
          >
            {description}
          </ProductDescription>
          <ProductPriceContainer>
            <PriceTextFormat data-test="pdp-inner-preview-price">
              {showFromText && <FromText> {t('cart.fromPrice').toUpperCase()}</FromText>}
              <PriceText>
                {StoreUtils.getCurrencySymbol(
                  store.countryCode,
                  paymentGateway.currencyId,
                  variantOptions ? variantOptions[selectedItem].price : price,
                )}
              </PriceText>
            </PriceTextFormat>
            {!!(
              (variantOptions &&
                variantOptions[selectedItem]?.originalPrice &&
                variantOptions[selectedItem]?.originalPrice >
                  variantOptions[selectedItem]?.price) ||
              (originalPrice && originalPrice > price)
            ) && (
              <OriginalPrice data-test="pdp-original-price">
                {StoreUtils.getCurrencySymbol(
                  store.countryCode,
                  paymentGateway.currencyId,
                  variantOptions ? variantOptions[selectedItem].originalPrice : originalPrice,
                )}
              </OriginalPrice>
            )}
          </ProductPriceContainer>
        </Row>
      )}
      <ContainerProductOptions>
        {/*start new variants model object */}
        {variantOptions?.length > 0 && variants?.length > 0 && (
          <>
            <VariantsOptions>
              {variants?.map((variant, i) => (
                <Select2
                  key={i}
                  onChange={(variant) => {
                    onVariantChange(i, variant)
                    updateSelectStatus(i, true)
                  }}
                  id={product.id}
                  options={variant}
                  options2={variantOptions}
                  label={variant.name}
                  error={error}
                  required
                />
              ))}
            </VariantsOptions>
            {error && (
              <ErrorVariantText error={error} data-test="pdp-variant-error">
                {printVariantsName(variants)}
              </ErrorVariantText>
            )}
          </>
        )}

        {product.variant && product.variant.options.length > 0 && (
          <>
            <VariantsOptions isOldVariant>
              <Select
                onChange={onOldVariantChange}
                id={product.id}
                options={product.variant.options}
                defaultValue={
                  product.variantOptionName && product.variantOptionName !== ''
                    ? product.variant.options.find((op) => op.name === product.variantOptionName).id
                    : ''
                }
                label={product.variant.label ?? product.variant.name}
                error={error}
                required
              />
            </VariantsOptions>
            {error && (
              <ErrorVariantText error={error} data-test="pdp-variant-error">
                {printVariantsName(product.variant)}
              </ErrorVariantText>
            )}
          </>
        )}
        <QuantityHandler
          product={product}
          selectedItem={selectedItem}
          setProductQuantityPDP={setProductQuantityPDP}
        />
      </ContainerProductOptions>

      <StyledButton
        isCencosudParis={isCencosudParis}
        variant="contained"
        disabled={isNotAvailable}
        onClick={() => onAddClicked()}
        data-test="product-detail-add-button"
      >
        {t('cart.variantButton')}
      </StyledButton>

      {uiSize === UI_IS_TABLET && (
        <Button
          goToCart
          disabled={!cartEnabled}
          onClick={() => dispatch(setActiveCallCard(CALL_CARD_CART))}
          data-test="product-detail-add-button"
        >
          {t('cart.goToCartButton')}
        </Button>
      )}
    </>
  )
}

const ProductImage = styled(Paper)`
  width: 100%;
  padding-top: 100%;
  position: relative;
  overflow: hidden;
  border-radius: 0.5em;

  > div {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    display: flex;

    > img {
      margin: auto;
      max-width: 100%;
      max-height: 100%;
    }
  }
`
const ProductDescription = styled.p`
  align-self: flex-start;
  font-weight: 500;
  width: 64%;
  overflow: ${({ isLongLength }) => (isLongLength ? 'hidden' : 'visible')};
  white-space: ${({ isLongLength }) => (isLongLength ? 'nowrap' : 'normal')};
  text-overflow: ${({ isLongLength }) => (isLongLength ? 'ellipsis' : 'clip')};
`
const Row = styled.span`
  margin-top: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
`
const RowWithDue = styled.span`
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 1em;
`
const ProductPriceContainer = styled.div`
  margin: 0;
  margin-bottom: 0.75rem;
  font-size: 0.9rem;
  font-weight: 600;
  text-align: right;
  width: 36%;
`
const VariantsOptions = styled.div`
  display: grid;
  grid-template-columns: ${({ isOldVariant }) =>
    isOldVariant ? 'repeat(1, minmax(0, 1fr))' : 'repeat(2, minmax(min-content, 1fr))'};
  grid-column: span 2;
  gap: 0.438rem;
`
const PriceTextFormat = styled.div`
  display: flex;
  flex-direction: column;
  align-items: end;
  margin: 0;
`
const PriceText = styled.p`
  font-weight: 600;
  font-size: 0.875rem;
  margin: 0;
`
const ErrorVariantText = styled.span`
  grid-column: span 3;
  grid-row: 2;
  font-weight: 400;
  font-size: 0.625rem;
  margin: 0.625rem;
  display: inline-block;
  color: ${({ error }) => (error ? 'red' : 'white')};
`
const FromText = styled.p`
  font-weight: 500;
  font-size: 0.594rem;
  margin: 0;
`
const ContainerProductOptions = styled.div`
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin: 0.375rem 0;
  gap: 0.438rem;
  width: 100%;
`