import React, { useEffect, useCallback, useState, ReactElement, useRef, } from "react"; import styles from "./styles.module.css"; import classNames from "../helpers/className"; const defaultCardItems = [ <div key="key1"> <h2>First Item</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> </div>, <div key="key2"> <h2>Second Item</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> </div>, <div key="key3"> <h2>Third Item</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> </div>, ]; type Indexes = { previousIndex: number; currentIndex: number; nextIndex: number; nextIndex2: number; previousIndex2: number; }; const setCardStatus = ( indexes: Indexes, cardIndex: number, showSummary = false ) => { // console.log(indexes, cardIndex); if (indexes.currentIndex === cardIndex) { return styles.active; } else if (indexes.nextIndex === cardIndex) { return showSummary ? `${styles.noTranslate as string}` : `${styles.next as string}`; } else if (indexes.previousIndex === cardIndex) { return showSummary ? `${styles.noTranslate as string}` : (styles.prev as string); } else if (indexes.nextIndex2 === cardIndex) { return showSummary ? `${styles.noTranslate as string}` : (styles.next2 as string); } else if (indexes.previousIndex2 === cardIndex) { return showSummary ? `${styles.noTranslate as string}` : (styles.prev2 as string); } return styles.inactive as string; }; const getValidChildren = (children: React.ReactNode): React.ReactElement[] => { return React.Children.toArray(children).filter( (child): child is React.ReactElement => React.isValidElement(child) ); }; // type CardType = React.ReactElement & { key: string | number }; type CardType = React.ReactElement; type CardCarouselProps = { cardClassName: string; children: CardType[]; containerClassName: string; autoRotate: boolean; showSummary: boolean; leftButton: React.ReactNode; rightButton: React.ReactNode; style: React.CSSProperties; onCardChange: (indexes: Indexes) => void; rotationInterval: number; defaultCardItems?: CardType[]; }; //children: Element[], autoRotate: boolean, onCardChange: (event: any) => void, containerClassName: string, cardClassName: string, leftButton: Element, rightButton: Element , rotationInterval: number, showSummary: boolean, style: any} export const StackedCarouselTwo: React.FC<CardCarouselProps> = ({ showSummary, style, onCardChange, containerClassName, cardClassName, leftButton, rightButton, autoRotate = true, rotationInterval = 2000, //handleCardChange, children, }) => // showSummary: boolean; // style: any; // onCardChange: (event: any) => void; // containerClassName: string; // cardClassName: string; // leftButton: ReactElement<any, any>; // rightButton: ReactElement<any, any>; // autoRotate: boolean; // rotationInterval: number; // children: any; //handleCardChange: (card: number) => void; { // let cardItems = showSummary ? [1, ...(children as CardType[])] : (children as CardType[])|| defaultCardItems; const cardItems = showSummary ? [ <div key="summary">1</div>, ...React.Children.map(children, (child, index) => ( <React.Fragment key={index}>{child}</React.Fragment> )), ] : React.Children.map(children, (child, index) => ( <React.Fragment key={index}>{child}</React.Fragment> )); // console.log(showSummary); const [indexes, setIndexes] = useState({ previousIndex: cardItems.length - 1, currentIndex: 0, nextIndex: 1, nextIndex2: 2, previousIndex2: cardItems.length - 2, }); const handleCardTransition = useCallback(() => { // console.log("card before change =", indexes.currentIndex); // If we've reached the end, start again from the first card, // but carry previous value over if (indexes.currentIndex >= cardItems.length - 1) { setIndexes({ previousIndex: cardItems.length - 1, currentIndex: 0, nextIndex: 1, nextIndex2: 2, previousIndex2: cardItems.length - 2, }); //console.log("useEffect - r", 0); //handleCardChange(0); } else { setIndexes((prevState) => ({ previousIndex: prevState.currentIndex, previousIndex2: prevState.previousIndex, currentIndex: prevState.currentIndex + 1, nextIndex: prevState.currentIndex + 2 === cardItems.length ? 0 : prevState.currentIndex + 2, nextIndex2: prevState.currentIndex + 3 === cardItems.length ? 0 : prevState.currentIndex + 3, })); //console.log("useeffect - rr", indexes.currentIndex - 1); //handleCardChange(indexes.currentIndex + 1); } }, [indexes.currentIndex]); const handleLeftButton = useCallback(() => { // If we've reached the end, start again from the first card, // but carry previous value over if (indexes.currentIndex <= 0) { setIndexes({ previousIndex: cardItems.length - 2, previousIndex2: cardItems.length - 3, currentIndex: cardItems.length - 1, nextIndex: 0, nextIndex2: 1, }); //console.log("useEffect - l", cardItems.length - 1); //handleCardChange(cardItems.length - 1); } else { setIndexes((prevState) => ({ nextIndex: prevState.currentIndex, currentIndex: prevState.currentIndex - 1, previousIndex: prevState.currentIndex - 1 <= 0 ? cardItems.length - 1 : prevState.currentIndex - 2, previousIndex2: prevState.currentIndex - 2 <= 0 ? cardItems.length - 1 : prevState.currentIndex - 3, nextIndex2: prevState.currentIndex + 1, })); //console.log("useeffect - l", indexes.currentIndex - 1); //handleCardChange(indexes.currentIndex - 1); } }, [indexes.currentIndex]); useEffect(() => { onCardChange && onCardChange(indexes); const transitionInterval = setInterval(() => { autoRotate && handleCardTransition(); }, rotationInterval); return () => clearInterval(transitionInterval); }, [handleCardTransition, indexes, autoRotate]); return ( //container: flex items-start m-auto pb-[13%] pl-[10%] pr-[13%] mb-[26%] max-h-[20%] xs:max-sm:min-h-[27vh] sm:max-md:min-h-[27vh] md:max-lg:pl-[8%] row-reverse overflow-hidden h-[10rem] w-full <div className={classNames( `${styles.container as string}`, `scrollbar-hide 2xs:max-lg:pb-0` )} > {leftButton ? ( // spans: z-1000 cursor-pointer <span onClick={handleLeftButton}>{leftButton}</span> ) : ( // leftbutton: translate-y-[50%] blue text-[2em] p-[5px] <span className={styles.leftButton} onClick={handleLeftButton}> ‹ </span> )} {/* cardCarousel: "list style none" p-0 relative w-full combine with containerClassName input*/} <ul style={{ ...style }} className={`${styles.cardCarousel as string} ${ containerClassName ? containerClassName : (styles.carouselDefault as string) }`} > {cardItems.map((card: React.ReactElement, index: number) => { if (showSummary && index === 0) { // cardItems.shift() const cardsGallery = cardItems.slice(1); return ( // combine with cardClassName input* card: w-full h-full "box shadow: 0 10px 5px rgba(0, 0, 0, 0.1) transition: "all 0.5s ease-in-out" grid gtc-"repeat(auto-fit, minmax(80px, 1fr))" gtr-"repeat(auto-fit, minmax(80px, 1fr))" grid-gap-0 <li key={"stacked-carousel"} className={`${cardClassName ?? ""} ${styles.card ?? ""} ${ styles.cardSummary ?? "" } ${setCardStatus(indexes, index, showSummary) ?? ""}`} // className={`${cardClassName ? cardClassName : ""} ${ // styles.card as string // } ${styles.cardSummary as string} ${setCardStatus( // indexes, // index as number, // showSummary // ) as string}`} > {cardsGallery.map((cardItem: CardType, cardIndex: number) => ( <div key={cardItem.key} className={`${cardClassName ?? ""} ${ setCardStatus(indexes, cardIndex, showSummary) ?? "" }`} // className={`${cardClassName ? cardClassName : ""} ${ // setCardStatus(indexes, cardIndex, showSummary) as string // }`} > {cardItem} </div> ))} </li> ); } else { return ( // combine with cardClassName input* card: w-full h-full "box shadow: " <li key={card.key as string | number} className={`${cardClassName ? cardClassName : ""} ${ styles.card as string } ${setCardStatus(indexes, index, showSummary) ?? ""}`} > {card} </li> ); } })} </ul> {/* rightbutton:blue text-[2em] p-[5px] ??absolute ??translate-x-[75vw] */} {rightButton ? ( <span onClick={handleCardTransition}>{rightButton}</span> ) : ( <span style={{ position: "absolute", transform: "translateX(75vw)" }} className={styles.rightButton} onClick={handleCardTransition} > › </span> )} </div> ); };