
META-INF.resources.components.mini_cart.CartQuickAdd.js Maven / Gradle / Ivy
/**
* SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
* SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
*/
import {ClayButtonWithIcon} from '@clayui/button';
import ClayDropDown from '@clayui/drop-down';
import ClayForm, {ClayInput} from '@clayui/form';
import ClayMultiSelect from '@clayui/multi-select';
import classNames from 'classnames';
import {fetch} from 'frontend-js-web';
import React, {useContext, useRef, useState} from 'react';
import {CHANNEL_RESOURCE_ENDPOINT} from '../../utilities/constants';
import {addToCart} from '../add_to_cart/data';
import InfiniteScroller from '../infinite_scroller/InfiniteScroller';
import MiniCartContext from './MiniCartContext';
import {getCorrectedQuantity} from './util/index';
const CART_QUICK_ADD_NAMESPACE = 'cartQuickAdd_';
const getSearchSKUsURL = (page, search, accountId, channelId) => {
const url = new URL(
`${themeDisplay.getPathContext()}${CHANNEL_RESOURCE_ENDPOINT}/${channelId}/products`,
themeDisplay.getPortalURL()
);
url.searchParams.append('accountId', accountId);
url.searchParams.append('nestedFields', 'skus');
url.searchParams.append('page', page);
url.searchParams.append('pageSize', '100');
url.searchParams.append('search', search);
url.searchParams.append('skus.accountId', accountId);
return url.toString();
};
export default function CartQuickAdd() {
const {cartState} = useContext(MiniCartContext);
const keypressTimoutRef = useRef(null);
const paginatorCurrentPageRef = useRef(1);
const paginatorIsLoadingRef = useRef(false);
const paginatorItemLengthRef = useRef(0);
const paginatorLastPageRef = useRef(1);
const paginatorTotalCountRef = useRef(0);
const requestAbortControllerRef = useRef(new AbortController());
const [formattedSKUs, setFormattedSKUs] = useState([]);
const [quantityError, setQuantityError] = useState(false);
const [quickAddToCartError, setQuickAddToCartError] = useState(false);
const [searchInputValue, setSearchInputValue] = useState('');
const [selectedSKUs, setSelectedSKUs] = useState([]);
const {
accountId,
cartItems = [],
channel: {channel},
id: cartId,
} = cartState;
const channelId = channel.id;
const ProductAutocompleteList = ({onItemClick, sourceItems}) => {
return (
{
if (!paginatorIsLoadingRef.current) {
paginatorIsLoadingRef.current = true;
paginatorCurrentPageRef.current =
paginatorCurrentPageRef.current <
paginatorLastPageRef.current
? paginatorCurrentPageRef.current + 1
: paginatorCurrentPageRef.current;
searchSKUs(
searchInputValue,
paginatorCurrentPageRef.current,
true
);
}
}}
scrollCompleted={
paginatorItemLengthRef.current >=
paginatorTotalCountRef.current
}
>
{sourceItems
.filter(
(sku) =>
!selectedSKUs.includes(sku) && sku.purchasable
)
.map((sku) => {
const {id, label, value} = sku;
return (
onItemClick(sku)}
>
{value}
{label}
);
})}
);
};
const handleAddToCartClick = () => {
const readySKUs = selectedSKUs.map((selectedSKUData) => {
const {
id: selectedId,
productConfiguration: selectedConfiguration,
replacementSku: replacementSKUData,
sku: selectedSKU,
skuUnitOfMeasures,
urls,
} = selectedSKUData;
if (skuUnitOfMeasures && skuUnitOfMeasures.length) {
selectedSKUData.skuUnitOfMeasure = skuUnitOfMeasures[0];
}
if (
selectedSKUData.availability?.label !== 'available' &&
!selectedConfiguration.allowBackOrder &&
replacementSKUData
) {
const {
price,
productConfiguration: replacementConfiguration,
sku: replacementSKU,
skuUnitOfMeasures: replacementUnitOfMeasures,
urls: productURLs,
} = replacementSKUData;
if (
replacementUnitOfMeasures &&
replacementUnitOfMeasures.length
) {
replacementSKUData.skuUnitOfMeasure =
replacementUnitOfMeasures[0];
}
return {
...replacementSKUData,
price,
productURLs,
quantity: getCorrectedQuantity(
{
...replacementConfiguration,
multipleOrderQuantity:
replacementSKUData.skuUnitOfMeasure
?.incrementalOrderQuantity ||
replacementConfiguration.multipleOrderQuantity,
},
replacementSKU,
cartItems,
replacementSKUData.skuUnitOfMeasure?.precision || 0
),
replacedSkuId: selectedId,
settings: replacementConfiguration,
};
}
return {
...selectedSKUData,
productURLs: urls,
quantity: getCorrectedQuantity(
{
...selectedConfiguration,
multipleOrderQuantity:
selectedSKUData.skuUnitOfMeasure
?.incrementalOrderQuantity ||
selectedConfiguration.multipleOrderQuantity,
},
selectedSKU,
cartItems,
selectedSKUData.skuUnitOfMeasure?.precision || 0
),
settings: selectedConfiguration,
skuId: selectedId,
};
});
const unavailableSKU = readySKUs.find(
(readySKU) => readySKU.quantity === 0
);
if (!unavailableSKU) {
addToCart(
readySKUs,
cartId,
channel,
accountId,
null,
CART_QUICK_ADD_NAMESPACE
)
.then(() => {})
.catch((error) => {
Liferay.Util.openToast({
message:
error.detail ||
Liferay.Language.get(
'an-unexpected-system-error-occurred'
),
type: 'danger',
});
});
setSelectedSKUs([]);
}
else {
setQuickAddToCartError(true);
setQuantityError(true);
}
};
const handleProductQueryInput = (productQueryString) => {
clearTimeout(keypressTimoutRef.current);
requestAbortControllerRef.current.abort();
paginatorCurrentPageRef.current = 1;
setSearchInputValue(productQueryString);
keypressTimoutRef.current = setTimeout(() => {
searchSKUs(productQueryString, 1, false);
}, 500);
};
const searchSKUs = (queryString, page, appendData) => {
requestAbortControllerRef.current = new AbortController();
const {signal} = requestAbortControllerRef.current;
if (!queryString.length) {
paginatorIsLoadingRef.current = false;
setFormattedSKUs([]);
return;
}
paginatorIsLoadingRef.current = true;
const searchSKUsURL = getSearchSKUsURL(
page,
queryString,
accountId,
channelId
);
fetch(searchSKUsURL, {
signal,
})
.then((response) => response.json())
.then((availableSKUs) => {
paginatorItemLengthRef.current =
availableSKUs.page * availableSKUs.pageSize;
paginatorLastPageRef.current = availableSKUs.lastPage;
paginatorTotalCountRef.current = availableSKUs.totalCount;
const responseSKUs = [];
availableSKUs.items.forEach((availableSKU) => {
availableSKU.skus.forEach((sku) => {
responseSKUs.push({
...sku,
chipLabel: sku.sku,
label: availableSKU.name,
productConfiguration:
availableSKU.productConfiguration,
urls: availableSKU.urls,
value: sku.sku,
});
});
});
setFormattedSKUs(responseSKUs);
if (appendData) {
setFormattedSKUs(formattedSKUs.concat(responseSKUs));
}
paginatorIsLoadingRef.current = false;
});
};
return (
{
setQuickAddToCartError(false);
setQuantityError(false);
newSKUs = newSKUs.filter((item) => {
if (item.id) {
return item;
}
else {
setQuickAddToCartError(true);
}
});
setSelectedSKUs(newSKUs);
}}
onPaste={(event) => {
const pastedText =
event.clipboardData.getData('Text');
event.preventDefault();
handleProductQueryInput(
searchInputValue.concat(pastedText)
);
}}
placeholder={Liferay.Language.get('search-products')}
size="sm"
sourceItems={formattedSKUs}
value={searchInputValue}
/>
{quickAddToCartError && (
{`${Liferay.Language.get('error-colon')} `}
{quantityError
? Liferay.Language.get(
'please-enter-a-valid-quantity'
)
: Liferay.Language.get('select-from-list')}
)}
);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy