diff --git a/apps/storefront/.eslintrc.json b/apps/storefront/.eslintrc.json index 3ad8b1bb..8b94f881 100644 --- a/apps/storefront/.eslintrc.json +++ b/apps/storefront/.eslintrc.json @@ -22,7 +22,9 @@ } }, { - "files": ["src/hooks/dom/*.ts", "src/hooks/*.ts"], + "files": [ + "src/hooks/*.ts" + ], "rules": { "react-hooks/exhaustive-deps": 0 } diff --git a/apps/storefront/src/hooks/dom/useCartToQuote.ts b/apps/storefront/src/hooks/dom/useCartToQuote.ts index 4eecf036..753565ac 100644 --- a/apps/storefront/src/hooks/dom/useCartToQuote.ts +++ b/apps/storefront/src/hooks/dom/useCartToQuote.ts @@ -57,65 +57,66 @@ const useCartToQuote = ({ 'blockPendingAccountOrderCreation' ) - const urlArr = ['/cart.php', '/checkout'] - const checkIsInPage = (url: string) => window.location.href.includes(url) const { pathname } = window.location - const showPendingAccountTip = () => { - const isShowBlockPendingAccountOrderCreationTip: IsShowBlockPendingAccountOrderCreationTipProps = - B3SStorage.get('isShowBlockPendingAccountOrderCreationTip') || { - cartTip: 0, - checkoutTip: 0, - } + useEffect(() => { + const urlArr = ['/cart.php', '/checkout'] - if (!urlArr.includes(pathname)) return + const showPendingAccountTip = () => { + const isShowBlockPendingAccountOrderCreationTip: IsShowBlockPendingAccountOrderCreationTipProps = + B3SStorage.get('isShowBlockPendingAccountOrderCreationTip') || { + cartTip: 0, + checkoutTip: 0, + } - if (companyInfo.companyStatus === '') return + if (!urlArr.includes(pathname)) return - if (+companyInfo.companyStatus || !blockPendingAccountOrderCreation) return + if (companyInfo.companyStatus === '') return - if ( - isShowBlockPendingAccountOrderCreationTip.cartTip && - checkIsInPage(urlArr[0]) - ) - return + if (+companyInfo.companyStatus || !blockPendingAccountOrderCreation) + return - if ( - isShowBlockPendingAccountOrderCreationTip.checkoutTip && - checkIsInPage(urlArr[1]) - ) - return - - if (checkIsInPage(urlArr[0])) { - globalSnackbar.warning( - 'Your account is pending approval. Ordering will be enabled after account approval', - { - isClose: true, - } + if ( + isShowBlockPendingAccountOrderCreationTip.cartTip && + checkIsInPage(urlArr[0]) ) - } + return - if (checkIsInPage(urlArr[1])) { - globalSnackbar.error( - 'Your account is pending approval. Ordering will be enabled after account approval' + if ( + isShowBlockPendingAccountOrderCreationTip.checkoutTip && + checkIsInPage(urlArr[1]) ) - } + return + + if (checkIsInPage(urlArr[0])) { + globalSnackbar.warning( + 'Your account is pending approval. Ordering will be enabled after account approval', + { + isClose: true, + } + ) + } + + if (checkIsInPage(urlArr[1])) { + globalSnackbar.error( + 'Your account is pending approval. Ordering will be enabled after account approval' + ) + } - B3SStorage.set('isShowBlockPendingAccountOrderCreationTip', { - cartTip: - +checkIsInPage(urlArr[0]) + - isShowBlockPendingAccountOrderCreationTip.cartTip, - checkoutTip: - +checkIsInPage(urlArr[1]) + - isShowBlockPendingAccountOrderCreationTip.checkoutTip, - }) - } + B3SStorage.set('isShowBlockPendingAccountOrderCreationTip', { + cartTip: + +checkIsInPage(urlArr[0]) + + isShowBlockPendingAccountOrderCreationTip.cartTip, + checkoutTip: + +checkIsInPage(urlArr[1]) + + isShowBlockPendingAccountOrderCreationTip.checkoutTip, + }) + } - useEffect(() => { showPendingAccountTip() - }, [pathname, blockPendingAccountOrderCreation]) + }, [pathname, blockPendingAccountOrderCreation, companyInfo.companyStatus]) const quoteCallBbck = useCallback(() => { const b3CartToQuote = document.querySelector('.b2b-cart-to-quote') @@ -125,7 +126,7 @@ const useCartToQuote = ({ addLoadding(b3CartToQuote) addToQuote() } - }, []) + }, [addLoadding, addToQuote]) const { color = '', @@ -215,7 +216,19 @@ const useCartToQuote = ({ cartQuoteBtnDom.removeEventListener('click', quoteCallBbck) } } - }, [cartQuoteEnabled, addToAllQuoteBtn]) + }, [ + cartQuoteEnabled, + addToAllQuoteBtn, + cartToQuoteBtnLabel, + classSelector, + color, + customCss, + customTextColor, + enabled, + locationSelector, + mediaBlocks, + quoteCallBbck, + ]) } export default useCartToQuote diff --git a/apps/storefront/src/hooks/dom/useDomVariation.ts b/apps/storefront/src/hooks/dom/useDomVariation.ts index 0af19156..2d651fa8 100644 --- a/apps/storefront/src/hooks/dom/useDomVariation.ts +++ b/apps/storefront/src/hooks/dom/useDomVariation.ts @@ -33,7 +33,7 @@ const useDomVariation = (dom: string, quoteCallBbck?: () => void) => { } }) } - }, []) + }, [dom, quoteCallBbck]) useMutationObservable(document.documentElement, cd) diff --git a/apps/storefront/src/hooks/dom/useHideGoogleCustomerReviews.ts b/apps/storefront/src/hooks/dom/useHideGoogleCustomerReviews.ts index 8c46fddb..b4db91ac 100644 --- a/apps/storefront/src/hooks/dom/useHideGoogleCustomerReviews.ts +++ b/apps/storefront/src/hooks/dom/useHideGoogleCustomerReviews.ts @@ -24,7 +24,7 @@ const useHideGoogleCustomerReviews = ( const parentElement = dom?.parentElement if (parentElement) parentElement.style.display = newVisibilityStyle }) - }, [isOpen]) + }, [isOpen, isMobile]) } export default useHideGoogleCustomerReviews diff --git a/apps/storefront/src/hooks/dom/useMonitorBrowserBack.ts b/apps/storefront/src/hooks/dom/useMonitorBrowserBack.ts index 495e3835..b2fd6147 100644 --- a/apps/storefront/src/hooks/dom/useMonitorBrowserBack.ts +++ b/apps/storefront/src/hooks/dom/useMonitorBrowserBack.ts @@ -25,6 +25,8 @@ const useMonitorBrowserBack = ({ window.location.reload() B3SStorage.set('isEnterB2BBuyerPortal', false) } + // disabling to avoid unnecessary renders when adding the missing dependencies + // eslint-disable-next-line react-hooks/exhaustive-deps }, [history.href]) } diff --git a/apps/storefront/src/hooks/dom/useMyQuote.ts b/apps/storefront/src/hooks/dom/useMyQuote.ts index 07deacef..903e664f 100644 --- a/apps/storefront/src/hooks/dom/useMyQuote.ts +++ b/apps/storefront/src/hooks/dom/useMyQuote.ts @@ -54,26 +54,27 @@ const useMyQuote = ({ B3LStorage.set('b2bQuoteDraftList', []) B3LStorage.set('quoteDraftUserId', B3UserId || 0) } - }, [B3UserId]) + }, [B3UserId, role]) const cache = useRef({}) const { state: { addQuoteBtn, quoteOnNonPurchasableProductPageBtn }, } = useContext(CustomStyleContext) - // const [isPurchasable, setPurchasable] = useState(true) - // quote method and goto draft const { addToQuote, addLoadding } = addProductFromProductPageToQuote(setOpenPage) - const quoteCallBack = useCallback((e: React.MouseEvent) => { - const b3MyQuote = e.target as HTMLElement - const b2bLoading = document.querySelector('#b2b-div-loading') - if (b3MyQuote && !b2bLoading) { - addLoadding(b3MyQuote) - addToQuote(role, b3MyQuote) - } - }, []) + const quoteCallBack = useCallback( + (e: React.MouseEvent) => { + const b3MyQuote = e.target as HTMLElement + const b2bLoading = document.querySelector('#b2b-div-loading') + if (b3MyQuote && !b2bLoading) { + addLoadding(b3MyQuote) + addToQuote(role, b3MyQuote) + } + }, + [role, addLoadding, addToQuote] + ) const cd = () => { if (+role !== 2) { @@ -140,7 +141,7 @@ const useMyQuote = ({ }) } - const addBtnStyle = () => { + const addBtnStyle = useCallback(() => { const myQuoteBtn = document.querySelectorAll('.b2b-add-to-quote') myQuoteBtn.forEach((quote: CustomFieldItems) => { const myQuote = quote @@ -167,82 +168,97 @@ const useMyQuote = ({ }` ) }) - } + }, [ + classSelector, + color, + customCss, + customTextColor, + isBuyPurchasable, + mediaBlocks, + myQuoteBtnLabel, + noPuchasableQuoteClassSelector, + noPuchasableQuoteColor, + noPuchasableQuoteCustomCss, + ]) - const purchasableQuote = ( - CustomAddToQuoteAll: NodeListOf | never[], - addToQuoteAll: NodeListOf, - isBuyer: boolean - ) => { - const quoteNode = isBuyer - ? '.b2b-add-to-quote' - : '.b2b-add-to-no-puchasable-quote' - const quoteNodeStyle = isBuyer - ? 'b2b-add-to-quote' - : 'b2b-add-to-no-puchasable-quote' - - if (document.querySelectorAll(quoteNode)?.length) { - const cacheQuoteDom = cache.current - - const isAddStyle = Object.keys(cacheQuoteDom).every( - (key: string) => - (cacheQuoteDom as CustomFieldItems)[key] === - (addQuoteBtn as CustomFieldItems)[key] - ) - if (!isAddStyle) { - addBtnStyle() - cache.current = cloneDeep(addQuoteBtn) + useEffect(() => { + const purchasableQuote = ( + CustomAddToQuoteAll: NodeListOf | never[], + addToQuoteAll: NodeListOf, + isBuyer: boolean + ) => { + const quoteNode = isBuyer + ? '.b2b-add-to-quote' + : '.b2b-add-to-no-puchasable-quote' + const quoteNodeStyle = isBuyer + ? 'b2b-add-to-quote' + : 'b2b-add-to-no-puchasable-quote' + + if (document.querySelectorAll(quoteNode)?.length) { + const cacheQuoteDom = cache.current + + const isAddStyle = Object.keys(cacheQuoteDom).every( + (key: string) => + (cacheQuoteDom as CustomFieldItems)[key] === + (addQuoteBtn as CustomFieldItems)[key] + ) + if (!isAddStyle) { + addBtnStyle() + cache.current = cloneDeep(addQuoteBtn) + } } - } - if (isBuyPurchasable ? enabled : noPuchasableQuoteEnabled) { - ;(CustomAddToQuoteAll.length - ? CustomAddToQuoteAll - : addToQuoteAll - ).forEach((node: CustomFieldItems) => { - const children = node.parentNode.querySelectorAll(quoteNode) - if (!children.length) { - let myQuote: CustomFieldItems | null = null - myQuote = document.createElement('div') - myQuote.innerHTML = myQuoteBtnLabel - myQuote.setAttribute( - 'style', - isBuyPurchasable ? customCss : noPuchasableQuoteCustomCss - ) - myQuote.style.backgroundColor = isBuyPurchasable - ? color - : noPuchasableQuoteColor - myQuote.style.color = customTextColor - myQuote.setAttribute( - 'class', - `${quoteNodeStyle} ${ - isBuyPurchasable ? classSelector : noPuchasableQuoteClassSelector - }` - ) - - setMediaStyle( - mediaBlocks, - `${quoteNodeStyle} ${ - isBuyPurchasable ? classSelector : noPuchasableQuoteClassSelector - }` - ) - if (CustomAddToQuoteAll.length) { - node.appendChild(myQuote) - } else { - node.parentNode.appendChild(myQuote) + if (isBuyPurchasable ? enabled : noPuchasableQuoteEnabled) { + ;(CustomAddToQuoteAll.length + ? CustomAddToQuoteAll + : addToQuoteAll + ).forEach((node: CustomFieldItems) => { + const children = node.parentNode.querySelectorAll(quoteNode) + if (!children.length) { + let myQuote: CustomFieldItems | null = null + myQuote = document.createElement('div') + myQuote.innerHTML = myQuoteBtnLabel + myQuote.setAttribute( + 'style', + isBuyPurchasable ? customCss : noPuchasableQuoteCustomCss + ) + myQuote.style.backgroundColor = isBuyPurchasable + ? color + : noPuchasableQuoteColor + myQuote.style.color = customTextColor + myQuote.setAttribute( + 'class', + `${quoteNodeStyle} ${ + isBuyPurchasable + ? classSelector + : noPuchasableQuoteClassSelector + }` + ) + + setMediaStyle( + mediaBlocks, + `${quoteNodeStyle} ${ + isBuyPurchasable + ? classSelector + : noPuchasableQuoteClassSelector + }` + ) + if (CustomAddToQuoteAll.length) { + node.appendChild(myQuote) + } else { + node.parentNode.appendChild(myQuote) + } + myQuote.addEventListener('click', quoteCallBack, { + capture: true, + }) } - myQuote.addEventListener('click', quoteCallBack, { - capture: true, - }) - } - }) - cache.current = cloneDeep(addQuoteBtn) - } else { - clearQuoteDom() + }) + cache.current = cloneDeep(addQuoteBtn) + } else { + clearQuoteDom() + } } - } - useEffect(() => { if (!productQuoteEnabled) { clearQuoteDom() clearNoPuchasableQuoteDom() @@ -284,7 +300,27 @@ const useMyQuote = ({ item.removeEventListener('click', quoteCallBack) }) } - }, [openQuickView, productQuoteEnabled, addQuoteBtn, isBuyPurchasable]) + }, [ + openQuickView, + productQuoteEnabled, + addQuoteBtn, + isBuyPurchasable, + locationSelector, + noPuchasableQuoteLocationSelector, + quoteCallBack, + addBtnStyle, + classSelector, + color, + customCss, + customTextColor, + enabled, + mediaBlocks, + myQuoteBtnLabel, + noPuchasableQuoteClassSelector, + noPuchasableQuoteColor, + noPuchasableQuoteCustomCss, + noPuchasableQuoteEnabled, + ]) } export default useMyQuote diff --git a/apps/storefront/src/hooks/dom/useOpenPDP.ts b/apps/storefront/src/hooks/dom/useOpenPDP.ts index d6de73e1..fdda41d6 100644 --- a/apps/storefront/src/hooks/dom/useOpenPDP.ts +++ b/apps/storefront/src/hooks/dom/useOpenPDP.ts @@ -92,7 +92,7 @@ export const useOpenPDP = ({ setOpenPage, role }: MutationObserverProps) => { isOpen: true, openUrl: '/register', }) - }, []) + }, [setOpenPage]) const pdpCallBack = useCallback( ({ target }: { target: HTMLElement }) => { @@ -111,6 +111,8 @@ export const useOpenPDP = ({ setOpenPage, role }: MutationObserverProps) => { registerEnabled, }) }, + // Disabling the next line as dispatch is not required to be in the dependency array + // eslint-disable-next-line react-hooks/exhaustive-deps [role, registerEnabled] ) @@ -237,5 +239,14 @@ export const useOpenPDP = ({ setOpenPage, role }: MutationObserverProps) => { shoppingListBtn, roleText, registerEnabled, + classSelector, + color, + customCss, + customTextColor, + enabled, + locationSelector, + mediaBlocks, + myShoppingListBtnLabel, + pdpCallBack, ]) } diff --git a/apps/storefront/src/hooks/dom/usePurchasableQuote.ts b/apps/storefront/src/hooks/dom/usePurchasableQuote.ts index 9ef048b4..2387666c 100644 --- a/apps/storefront/src/hooks/dom/usePurchasableQuote.ts +++ b/apps/storefront/src/hooks/dom/usePurchasableQuote.ts @@ -38,61 +38,61 @@ const usePurchasableQuote = (openQuickView: boolean) => { return false } - const callback = async ( - newSkuValue: string, - isDetailOpen: boolean, - isInit?: boolean - ): Promise => { - const modal = document.getElementById('modal') as HTMLElement - - const dom = isDetailOpen ? document : modal - const productViewQty = - (dom.querySelector('[name="qty[]"]') as CustomFieldItems)?.value || 1 - - const productId = ( - dom.querySelector('input[name=product_id]') as CustomFieldItems - )?.value + useEffect(() => { + const callback = async ( + newSkuValue: string, + isDetailOpen: boolean, + isInit?: boolean + ): Promise => { + const modal = document.getElementById('modal') as HTMLElement + + const dom = isDetailOpen ? document : modal + const productViewQty = + (dom.querySelector('[name="qty[]"]') as CustomFieldItems)?.value || 1 + + const productId = ( + dom.querySelector('input[name=product_id]') as CustomFieldItems + )?.value + + const { + productPurchasable: { + availability, + inventoryLevel, + inventoryTracking, + purchasingDisabled, + }, + } = await getB2BProductPurchasable({ + productId, + sku: newSkuValue || '', + isProduct: !!isInit, + }) - const { - productPurchasable: { - availability, + const productPurchasable = { + availability: availability === 'available', inventoryLevel, - inventoryTracking, + inventoryTracking: + inventoryTracking === 'product' || inventoryTracking === 'variant', purchasingDisabled, - }, - } = await getB2BProductPurchasable({ - productId, - sku: newSkuValue || '', - isProduct: !!isInit, - }) - - const productPurchasable = { - availability: availability === 'available', - inventoryLevel, - inventoryTracking: - inventoryTracking === 'product' || inventoryTracking === 'variant', - purchasingDisabled, - } - if (productInfoRef?.current) { - productInfoRef.current = productPurchasable - } + } + if (productInfoRef?.current) { + productInfoRef.current = productPurchasable + } - const isOOStock = isOOStockPurchaseQuantity( - +productViewQty, - productPurchasable - ) - if ( - purchasingDisabled === '1' || - isOOStock || - availability !== 'available' - ) { - setBuyPurchasable(false) - } else { - setBuyPurchasable(true) + const isOOStock = isOOStockPurchaseQuantity( + +productViewQty, + productPurchasable + ) + if ( + purchasingDisabled === '1' || + isOOStock || + availability !== 'available' + ) { + setBuyPurchasable(false) + } else { + setBuyPurchasable(true) + } } - } - useEffect(() => { const modal = document.getElementById('modal') as HTMLElement let productViewSku: Element | null = diff --git a/apps/storefront/src/hooks/dom/useRegisteredbctob2b.ts b/apps/storefront/src/hooks/dom/useRegisteredbctob2b.ts index d7a3b4d6..c5d0980f 100644 --- a/apps/storefront/src/hooks/dom/useRegisteredbctob2b.ts +++ b/apps/storefront/src/hooks/dom/useRegisteredbctob2b.ts @@ -23,20 +23,20 @@ const useRegisteredbctob2b = ( }, } = useContext(CustomStyleContext) - const createConvertB2BNavNode = () => { - const convertB2BNavNode = document.createElement('li') - convertB2BNavNode.className = 'navUser-item navUser-convert-b2b' - convertB2BNavNode.innerHTML = ` - - ${b3Lang('global.registerB2B.linkText')} - - ` - return convertB2BNavNode - } - const [openQuickView] = useDomVariation(globalB3['dom.navUserLoginElement']) useEffect(() => { + const createConvertB2BNavNode = () => { + const convertB2BNavNode = document.createElement('li') + convertB2BNavNode.className = 'navUser-item navUser-convert-b2b' + convertB2BNavNode.innerHTML = ` + + ${b3Lang('global.registerB2B.linkText')} + + ` + return convertB2BNavNode + } + if ( b2b && !isB2BUser && @@ -76,7 +76,16 @@ const useRegisteredbctob2b = ( } else { document.querySelector('.navUser-item.navUser-convert-b2b')?.remove() } - }, [isB2BUser, customerId, openQuickView, b2b, registerEnabled]) + // ignoring to not add b3Lang to the dependencies array + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + isB2BUser, + customerId, + openQuickView, + b2b, + registerEnabled, + companyInfo.companyStatus, + ]) } export default useRegisteredbctob2b