Untitled
unknown
javascript
3 years ago
14 kB
10
Indexable
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%;
`
Editor is loading...