diff --git a/proto b/proto index b620b757a..90d40c869 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit b620b757a6f8879f9830bf36d1d02685a182af5e +Subproject commit 90d40c869f2d72dab99f9faa41d033f5bb081534 diff --git a/src/app/[locale]/product/[...productParams]/_components/product-images-carousel.tsx b/src/app/[locale]/product/[...productParams]/_components/product-images-carousel.tsx index 6c4c726b0..f311dbb04 100644 --- a/src/app/[locale]/product/[...productParams]/_components/product-images-carousel.tsx +++ b/src/app/[locale]/product/[...productParams]/_components/product-images-carousel.tsx @@ -33,26 +33,10 @@ export function ProductImagesCarousel({ const handleSelectedIndex = useCallback( (index: number) => { if (index === prevIndexRef.current) return; - - const prevIndex = prevIndexRef.current; prevIndexRef.current = index; const realIndex = index % productMedia.length; if (productId) { - if (prevIndex !== -1) { - const prevRealIndex = prevIndex % productMedia.length; - const direction = realIndex > prevRealIndex ? "next" : "previous"; - sendProductImageSwipeEvent({ - product_id: productId, - product_name: productName || "", - product_category: "", - from_index: prevRealIndex + 1, - to_index: realIndex + 1, - total_images: productMedia.length, - swipe_direction: direction, - }); - } - sendProductImageViewEvent({ product_id: productId, image_index: realIndex + 1, @@ -64,6 +48,29 @@ export function ProductImagesCarousel({ [productId, productName, productMedia.length], ); + const swipePrevIndexRef = useRef(-1); + + const handleSettledIndex = useCallback( + (index: number) => { + const realIndex = index % productMedia.length; + const prevReal = swipePrevIndexRef.current; + swipePrevIndexRef.current = realIndex; + + if (productId && prevReal !== -1 && prevReal !== realIndex) { + sendProductImageSwipeEvent({ + product_id: productId, + product_name: productName || "", + product_category: "", + from_index: prevReal + 1, + to_index: realIndex + 1, + total_images: productMedia.length, + swipe_direction: realIndex > prevReal ? "next" : "previous", + }); + } + }, + [productId, productName, productMedia.length], + ); + return (
{mediaForCarousel.map((m, index) => { const isPriority = index < 2; diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx index ca71a92ef..f15f41f31 100644 --- a/src/components/ui/carousel.tsx +++ b/src/components/ui/carousel.tsx @@ -1,6 +1,6 @@ "use client"; -import { Children, useEffect } from "react"; +import { Children, useCallback, useEffect } from "react"; import useEmblaCarousel from "embla-carousel-react"; import { WheelGesturesPlugin } from "embla-carousel-wheel-gestures"; @@ -22,6 +22,7 @@ type CarouselProps = { skipSnaps?: boolean; scrollOnClick?: boolean; setSelectedIndex?: (index: number) => void; + onSettle?: (index: number) => void; }; export function Carousel({ @@ -38,6 +39,7 @@ export function Carousel({ skipSnaps = true, scrollOnClick = false, setSelectedIndex, + onSettle, }: CarouselProps) { const childrenCount = Children.count(children); const isDisabled = disabled || disableForItemCounts?.includes(childrenCount); @@ -54,11 +56,15 @@ export function Carousel({ isDisabled ? [] : [WheelGesturesPlugin()], ); - function onSelect() { + const onSelect = useCallback(() => { if (!emblaApi || !setSelectedIndex || isDisabled) return; - const currentIndex = emblaApi.selectedScrollSnap(); - setSelectedIndex(currentIndex); - } + setSelectedIndex(emblaApi.selectedScrollSnap()); + }, [emblaApi, setSelectedIndex, isDisabled]); + + const onSettleCallback = useCallback(() => { + if (!emblaApi || !onSettle || isDisabled) return; + onSettle(emblaApi.selectedScrollSnap()); + }, [emblaApi, onSettle, isDisabled]); useEffect(() => { if (!emblaApi || !enablePageScroll || isDisabled) return; @@ -104,12 +110,14 @@ export function Carousel({ onSelect(); emblaApi.on("select", onSelect); emblaApi.on("reInit", onSelect); + emblaApi.on("settle", onSettleCallback); return () => { emblaApi.off("select", onSelect); emblaApi.off("reInit", onSelect); + emblaApi.off("settle", onSettleCallback); }; - }, [emblaApi, onSelect, isDisabled]); + }, [emblaApi, onSelect, onSettleCallback, isDisabled]); function scrollNext() { emblaApi?.scrollNext();