Untitled
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%; `