diff --git a/CHANGELOG.md b/CHANGELOG.md index b845fd62..8a821608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Fixed + +- Fixing on seller wrapper when there is no seller available + ## [1.28.1] - 2023-11-06 ### Fixed diff --git a/react/SellerWrapper.tsx b/react/SellerWrapper.tsx index b74483f0..3363ae45 100644 --- a/react/SellerWrapper.tsx +++ b/react/SellerWrapper.tsx @@ -1,92 +1,3 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react' -import { useProduct, useProductDispatch } from 'vtex.product-context' -import { useCssHandles } from 'vtex.css-handles' -import type { Item } from 'vtex.product-context/react/ProductTypes' - -import useSeller from './hooks/useSeller' - -const CSS_HANDLES = ['sellerWrapper', 'loadingSeller'] -const SELECT_ITEM_EVENT = 'SET_SELECTED_ITEM' - -type SellerWrapperProps = { - children: React.ReactNode -} - -const SellerWrapper = ({ children }: SellerWrapperProps) => { - const { seller } = useSeller() - const dispatch = useProductDispatch() - const { selectedItem, product } = useProduct() ?? {} - const latestItem = useRef((null as unknown) as Item) - const handles = useCssHandles(CSS_HANDLES) - const [loadingSeller, setLoadingSeller] = useState(true) - - const addSellerDefaultToItem = useCallback( - itemSeller => ({ - ...itemSeller, - sellerDefault: seller?.includes(itemSeller.sellerId), - }), - [seller] - ) - - useEffect(() => { - const shouldDispatchSelectItem = - !!seller && !!product && !!selectedItem && !!dispatch - - if (!shouldDispatchSelectItem) return - const newCurrentSelectedItem = - product?.items?.find(item => - item.sellers?.find( - itemSeller => - seller?.includes(itemSeller.sellerId) && - itemSeller.commertialOffer.AvailableQuantity > 0 - ) - ) ?? ({} as Item) - - if (!newCurrentSelectedItem) { - return - } - - const { sellers } = newCurrentSelectedItem - const selectedItemWithSeller = { - ...newCurrentSelectedItem, - sellers: sellers.map(addSellerDefaultToItem), - } - - if ( - JSON.stringify(latestItem.current) === - JSON.stringify(selectedItemWithSeller) - ) { - return - } - - dispatch?.({ - type: SELECT_ITEM_EVENT, - args: { - item: selectedItemWithSeller, - }, - }) - - setLoadingSeller(false) - - latestItem.current = selectedItemWithSeller - }, [ - seller, - product, - selectedItem, - dispatch, - addSellerDefaultToItem, - latestItem, - ]) - - return ( -
- {children} -
- ) -} +import SellerWrapper from './components/SellerWrapper/SellerWrapper' export default SellerWrapper diff --git a/react/components/SellerWrapper/SellerWrapper.tsx b/react/components/SellerWrapper/SellerWrapper.tsx new file mode 100644 index 00000000..65d021ab --- /dev/null +++ b/react/components/SellerWrapper/SellerWrapper.tsx @@ -0,0 +1,30 @@ +import React, { useEffect } from 'react' +import { useCssHandles } from 'vtex.css-handles' +import { useProduct } from 'vtex.product-context' + +import { useSelectSeller } from '../../hooks/useSelectSeller' + +type SellerWrapperProps = { + children: React.ReactNode +} + +const CSS_HANDLES = ['sellerWrapper', 'sellerWrapperNoSeller'] + +const SellerWrapper = ({ children }: SellerWrapperProps) => { + const handles = useCssHandles(CSS_HANDLES) + const { currentSelectedItem, selectSeller } = useSelectSeller() + + const { selectedItem } = useProduct() ?? {} + + useEffect(() => { + selectSeller({ selectedItem }) + }, [selectedItem, selectSeller]) + + const className = currentSelectedItem + ? `${handles.sellerWrapper}` + : `${handles.sellerWrapper} ${handles.sellerWrapperNoSeller}` + + return
{children}
+} + +export default SellerWrapper diff --git a/react/hooks/useSelectSeller.ts b/react/hooks/useSelectSeller.ts new file mode 100644 index 00000000..9b1a57ac --- /dev/null +++ b/react/hooks/useSelectSeller.ts @@ -0,0 +1,72 @@ +import { useProduct, useProductDispatch } from 'vtex.product-context' +import { useCallback, useMemo, useRef, useState } from 'react' +import type { Item } from 'vtex.product-context/react/ProductTypes' + +import useSeller from './useSeller' + +const SELECT_ITEM_EVENT = 'SET_SELECTED_ITEM' + +export const useSelectSeller = () => { + const { seller } = useSeller() + const { product } = useProduct() ?? {} + const latestItem = useRef((null as unknown) as Item) + const [loading, setLoading] = useState(true) + const productDispatch = useProductDispatch() + + const addSellerDefaultToItem = useCallback( + itemSeller => ({ + ...itemSeller, + sellerDefault: seller?.includes(itemSeller.sellerId), + }), + [seller] + ) + + const currentSelectedItem = useMemo( + () => + product?.items?.find(item => + item.sellers?.find( + itemSeller => + seller?.includes(itemSeller.sellerId) && + itemSeller.commertialOffer.AvailableQuantity > 0 + ) + ) ?? null, + + [seller, product] + ) + + const selectSeller = ({ + selectedItem, + }: { + selectedItem: Item | null | undefined + }) => { + if (!currentSelectedItem || !selectedItem) { + return + } + + // just to keep the dependency + setLoading(true) + const { sellers } = (currentSelectedItem as unknown) as Item + const selectedItemWithSeller = { + ...((currentSelectedItem as unknown) as Item), + sellers: sellers.map(addSellerDefaultToItem), + } + + if ( + JSON.stringify(latestItem.current) === + JSON.stringify(selectedItemWithSeller) + ) { + return + } + + productDispatch?.({ + type: SELECT_ITEM_EVENT, + args: { + item: selectedItemWithSeller, + }, + }) + setLoading(false) + latestItem.current = selectedItemWithSeller + } + + return { loading, seller, currentSelectedItem, selectSeller } +} diff --git a/react/hooks/useSeller.tsx b/react/hooks/useSeller.ts similarity index 100% rename from react/hooks/useSeller.tsx rename to react/hooks/useSeller.ts