import Image from 'next/image'
import React, { MutableRefObject, useEffect, useRef, useState } from 'react'
import cn from 'clsx'
import {
useKeenSlider,
KeenSliderInstance,
KeenSliderPlugin,
} from 'keen-slider/react'
import 'keen-slider/keen-slider.min.css'
import ProductSliderModal from './ProductSliderModal'
import { ProductImage } from '@commerce/types/product'
interface ProductSliderProps {
productName: string
media: ProductImage[]
}
function ThumbnailPlugin(
mainRef: MutableRefObject<KeenSliderInstance | null>
): KeenSliderPlugin {
return (slider) => {
function removeActive() {
slider.slides.forEach((slide) => {
slide.classList.remove('active')
})
}
function addActive(idx: number) {
slider.slides[idx].classList.add('active')
}
function addClickEvents() {
slider.slides.forEach((slide, idx) => {
slide.addEventListener('click', () => {
if (mainRef.current) mainRef.current.moveToIdx(idx)
})
})
}
slider.on('created', () => {
if (!mainRef.current) return
addActive(slider.track.details.rel)
addClickEvents()
mainRef.current.on('animationStarted', (main) => {
removeActive()
const next = main.animator.targetIdx || 0
addActive(main.track.absToRel(next))
slider.moveToIdx(next)
})
})
}
}
const ProductSlider: React.FC<ProductSliderProps> = ({
media,
productName,
}) => {
const [isMounted, setIsMounted] = useState(false)
const [currentSlideIndex, setCurrentSlideIndex] = useState(0)
const [isModalOpen, setModalOpen] = useState(false)
const sliderContainerRef = useRef<HTMLDivElement>(null)
const [sliderRef, slider] = useKeenSlider<HTMLDivElement>({
renderMode: 'performance',
created: () => setIsMounted(true),
initial: 0,
})
const [thumbnailRef, thumbnail] = useKeenSlider<HTMLDivElement>(
{
initial: 0,
slides: {
perView: 5,
spacing: 10,
},
},
[ThumbnailPlugin(slider)]
)
const hasThumbnail = media.length > 1
const handleSlideClick = (idx: number) => {
setCurrentSlideIndex(idx)
setModalOpen(true)
}
// // Stop the history navigation gesture on touch devices
useEffect(() => {
const preventNavigation = (event: TouchEvent) => {
// Center point of the touch area
const touchXPosition = event.touches[0].pageX
// Size of the touch area
const touchXRadius = event.touches[0].radiusX || 0
// We set a threshold (10px) on both sizes of the screen,
// if the touch area overlaps with the screen edges
// it's likely to trigger the navigation. We prevent the
// touchstart event in that case.
if (
touchXPosition - touchXRadius < 10 ||
touchXPosition + touchXRadius > window.innerWidth - 10
)
event.preventDefault()
}
const slider = sliderContainerRef.current!
slider.addEventListener('touchstart', preventNavigation)
return () => {
if (slider) {
console.log('removing touchstart')
slider.removeEventListener('touchstart', preventNavigation)
}
}
}, [])
return (
<>
<div
className="md:w-3/4 lg:w-full mb-8 md:mb-10 lg:mb-0"
ref={sliderContainerRef}
>
<div
ref={sliderRef}
className={cn('keen-slider', {
'mb-3': hasThumbnail,
})}
>
{media.map(({ url, label }, index) => (
<div
key={url}
className="keen-slider__slide"
onClick={() => handleSlideClick(index)}
>
<div className="relative overflow-hidden rounded-lg h-[365px] lg:h-[582px]">
<Image
src={url}
layout="fill"
objectFit="cover"
alt={label}
quality={100}
/>
</div>
</div>
))}
</div>
<div
ref={thumbnailRef}
className={cn('keen-slider thumbnail', {
'!hidden': !hasThumbnail,
})}
>
{hasThumbnail &&
media.map(({ url, label }) => (
<div key={url} className="keen-slider__slide rounded-lg">
<div className="relative rounded-lg overflow-hidden h-14">
<Image
src={url}
layout="fill"
objectFit="cover"
alt={label}
quality={100}
/>
</div>
</div>
))}
</div>
</div>
{isModalOpen && (
<ProductSliderModal
productName={productName}
isOpen={isModalOpen}
onClose={() => setModalOpen(false)}
media={media}
initialSlide={currentSlideIndex}
/>
)}
</>
)
}
export default ProductSlider