@shopgate/engage
Version:
Shopgate's ENGAGE library.
139 lines (135 loc) • 4.79 kB
JavaScript
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { showModal } from '@shopgate/engage/core/actions';
import { Accordion, Card, ConditionalWrapper } from '@shopgate/engage/components';
import { makeGetFavorites, getUseGetFavoriteIdsPipeline } from '@shopgate/pwa-common-commerce/favorites/selectors';
import { FAVORITES_SHOW_LIMIT } from '@shopgate/engage/favorites/constants';
import ListAccordionLabel from "./ListAccordionLabel";
import ListContent from "./ListContent";
import styles from "./styles";
import ListAccordionHeader from "./ListAccordionHeader";
/**
* @param {Object} _ State
* @param {Object} props Props
* @returns {Object}
*/
import { jsx as _jsx } from "react/jsx-runtime";
const makeMapStateToProps = (_, {
id
}) => {
const getFavorites = makeGetFavorites(() => id);
return state => ({
items: getFavorites(state),
useGetFavoriteIdsPipeline: getUseGetFavoriteIdsPipeline(state)
});
};
/**
* @param {Object} dispatch Dispatch
* @param {Object} props The component props
* @returns {Object}
*/
const mapDispatchToProps = (dispatch, props) => ({
remove: async id => {
// Protect list deletion with a confirmation modal
const confirmed = await dispatch(showModal({
message: 'favorites.delete_list_modal.message',
title: 'favorites.delete_list_modal.title',
params: {
name: props.name
}
}));
if (confirmed) {
props.remove(id);
}
}
});
/**
* Favorite List component
* @return {JSX.Element}
*/
const FavoriteList = ({
id,
name,
items,
rename,
remove,
removeItem,
addToCart,
hasMultipleFavoritesListsSupport,
useGetFavoriteIdsPipeline
}) => {
const [offset, setOffset] = useState(FAVORITES_SHOW_LIMIT);
const filteredItems = useMemo(() => {
/**
* The getFavoriteIds pipeline doesn't return full products, but only product ids. Product data
* is selected inside the ListContent component via the ProductProvider. To avoid requests with
* huge response data, the favlist items are splitted into chunks, so that the ProductProvider
* only has to request fresh data for each chunk.
*
* As long as not all products from the list are shown, a "Load More" button is presented to the
* user, which will add an additional chunk of product ids to the ListContent component.
*/
if (useGetFavoriteIdsPipeline) {
return items.slice(0, offset);
}
// When the getFavorites pipeline is used, no special handling is necessary. "items" can passed
// the the ListContent component as they are.
return items;
}, [items, offset, useGetFavoriteIdsPipeline]);
const allFavoritesLoaded = useMemo(() => {
if (useGetFavoriteIdsPipeline) {
return items.length - filteredItems.length > 0;
}
/**
* In case of getFavorites pipeline is used, and all favorites are always loaded, "false" as
* return value might seem a bit weird, but the value is actually used to determine if the
* load more button is supposed to be shown (not needed if all favorites are already present).
*/
return false;
}, [filteredItems.length, items.length, useGetFavoriteIdsPipeline]);
const [showLoadMoreButton, setShowLoadMoreButton] = useState(allFavoritesLoaded);
const handleLoadMore = useCallback(() => {
setOffset(offset + FAVORITES_SHOW_LIMIT);
}, [offset]);
useEffect(() => {
setShowLoadMoreButton(allFavoritesLoaded);
}, [offset, allFavoritesLoaded]);
return /*#__PURE__*/_jsx(ConditionalWrapper, {
condition: hasMultipleFavoritesListsSupport,
wrapperFalsy: children => /*#__PURE__*/_jsx("div", {
className: styles.rootNoFavoritesLists,
children: children
}),
wrapper: children => /*#__PURE__*/_jsx(Card, {
className: styles.root,
children: /*#__PURE__*/_jsx(Accordion, {
className: "",
renderAdditionalHeaderContent: () => /*#__PURE__*/_jsx(ListAccordionHeader, {
rename: newName => rename(id, newName),
remove: remove,
id: id
}),
renderLabel: () => /*#__PURE__*/_jsx(ListAccordionLabel, {
title: name
}),
chevronPosition: "left",
startOpened: true,
children: children
})
}),
children: /*#__PURE__*/_jsx(ListContent, {
listId: id,
items: filteredItems,
removeItem: removeItem,
addToCart: addToCart,
onLoadMore: handleLoadMore,
showLoadMoreButton: showLoadMoreButton
})
});
};
FavoriteList.defaultProps = {
hasMultipleFavoritesListsSupport: false,
useGetFavoriteIdsPipeline: false
};
export default connect(makeMapStateToProps, mapDispatchToProps)(FavoriteList);