import type { ProductItemsGridProps } from '@graphcommerce/magento-product' import { useProductFiltersPro } from '@graphcommerce/magento-product' import { useMemoObject } from '@graphcommerce/next-ui' import { useDebounce } from '@graphcommerce/react-hook-form' import { useEventCallback } from '@mui/material' import React, { useContext, useEffect, useRef } from 'react' import { useSendEvent } from '../hooks/useSendEvent' import { productItemsToViewItemList, viewItemListToSelectItem, } from '../mapping/productItemsToViewItemList/productItemsToViewItemList' const DatalayerSelectItemContext = React.createContext<((itemId: string) => void) | undefined>( undefined, ) export function useViewItemList() { const context = useContext(DatalayerSelectItemContext) if (!context) { return (itemId: string) => { console.warn(`No DatalayerSelectItemContext provider found, trying to select item ${itemId}`) } } return context } export function DatalayerViewItemList( props: ProductItemsGridProps & { children: React.ReactNode }, ) { const { title: item_list_name, items, children, containerRef } = props const item_list_id = item_list_name.toLowerCase().replace(/\s/g, '_') const params = useProductFiltersPro(true)?.params const sendEvent = useSendEvent() const viewItemList = useMemoObject( productItemsToViewItemList(item_list_id, item_list_name, items, params), ) const sendUids = useRef>(new Map()) const send = useDebounce(() => { const toSend = [...sendUids.current.entries()] .filter(([, value]) => value !== true) .map(([key]) => key) if (toSend.length === 0) return const viewItems = viewItemList.items.filter((item) => toSend.includes(item.item_uid)) sendEvent('view_item_list', { ...viewItemList, items: viewItems }) // Mark as send. toSend.forEach((item_uid) => sendUids.current.set(item_uid, true)) }, 1000) useEffect(() => { sendUids.current.clear() if (typeof containerRef === 'function' || !containerRef?.current) return () => {} const childNodes = [...containerRef.current.childNodes].filter((n) => n instanceof HTMLElement) const io = new IntersectionObserver( (entries) => { for (const entry of entries) { const { target } = entry if (entry.isIntersecting && target instanceof HTMLElement) { const index = childNodes.indexOf(target) const item = viewItemList.items[index] if (item && !sendUids.current.has(item.item_uid)) { sendUids.current.set(item.item_uid, false) } } } send() }, { threshold: 0.5 }, ) childNodes.forEach((node) => { io.observe(node) }) return () => io.disconnect() }, [containerRef, send, viewItemList]) const selectItem = useEventCallback((itemId: string) => { sendEvent('select_item', viewItemListToSelectItem(viewItemList, itemId)) }) return ( {children} ) }